summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPicca Frédéric-Emmanuel <picca@debian.org>2018-03-04 10:22:38 +0100
committerPicca Frédéric-Emmanuel <picca@debian.org>2018-03-04 10:22:38 +0100
commitff4fbae651b05b715916e6e3f04126d24fbc391d (patch)
tree4d52921a0c25f47129ef21844d33744cca91fcfa
parent94b03dc6b5dfc0613957cd8f585461282375126e (diff)
parent270d5ddc31c26b62379e3caa9044dd75ccc71847 (diff)
Update upstream source from tag 'upstream/0.7.0+dfsg'
Update to upstream version '0.7.0+dfsg' with Debian dir fa8c5340967c8a813b9eb3e27b9f41d777ea47c6
-rw-r--r--CHANGELOG.rst76
-rw-r--r--PKG-INFO139
-rw-r--r--README.rst135
-rw-r--r--doc/source/Tutorials/Sift/sift.rst315
-rw-r--r--doc/source/Tutorials/array_widget.rst5
-rw-r--r--doc/source/Tutorials/convert.rst107
-rw-r--r--doc/source/Tutorials/fit.rst124
-rw-r--r--doc/source/Tutorials/io.rst5
-rw-r--r--doc/source/Tutorials/specfile_to_hdf5.rst63
-rw-r--r--doc/source/applications/convert.rst130
-rw-r--r--doc/source/applications/img/silx-view-hdf5.pngbin0 -> 51926 bytes
-rw-r--r--doc/source/applications/img/silx-view-image.pngbin0 -> 166677 bytes
-rw-r--r--doc/source/applications/img/silx-view-table.pngbin0 -> 52325 bytes
-rw-r--r--doc/source/applications/index.rst17
-rw-r--r--doc/source/applications/view.rst60
-rw-r--r--doc/source/conf.py11
-rw-r--r--doc/source/description/sift.rst314
-rw-r--r--doc/source/index.rst39
-rw-r--r--doc/source/install.rst326
-rw-r--r--doc/source/modules/gui/dialog/abstractdatafiledialog.rst13
-rw-r--r--doc/source/modules/gui/dialog/datafiledialog.rst13
-rw-r--r--doc/source/modules/gui/dialog/imagefiledialog.rst13
-rw-r--r--doc/source/modules/gui/dialog/img/datafiledialog.pngbin0 -> 31843 bytes
-rw-r--r--doc/source/modules/gui/dialog/img/imagefiledialog_edf.pngbin0 -> 109562 bytes
-rw-r--r--doc/source/modules/gui/dialog/img/imagefiledialog_h5.pngbin0 -> 46649 bytes
-rw-r--r--doc/source/modules/gui/dialog/index.rst33
-rw-r--r--doc/source/modules/gui/gallery.rst39
-rw-r--r--doc/source/modules/gui/icons.rst12
-rw-r--r--doc/source/modules/gui/index.rst1
-rw-r--r--doc/source/modules/gui/plot/actions/examples.rst46
-rw-r--r--doc/source/modules/gui/plot/actions/index.rst12
-rw-r--r--doc/source/modules/gui/plot/getting_started.rst259
-rw-r--r--doc/source/modules/gui/plot/index.rst1
-rw-r--r--doc/source/modules/gui/plot/plotsignal.rst166
-rw-r--r--doc/source/modules/gui/plot/plottoolbuttons.rst7
-rw-r--r--doc/source/modules/gui/plot/plotwidget.rst5
-rw-r--r--doc/source/modules/gui/plot3d/actions.rst3
-rw-r--r--doc/source/modules/gui/plot3d/dev.rst8
-rw-r--r--doc/source/modules/gui/plot3d/img/Plot3DWindow.pngbin20571 -> 21207 bytes
-rw-r--r--doc/source/modules/gui/plot3d/img/ScalarFieldView.pngbin42407 -> 55012 bytes
-rw-r--r--doc/source/modules/gui/plot3d/img/SceneWidget.pngbin0 -> 349485 bytes
-rw-r--r--doc/source/modules/gui/plot3d/img/SceneWindow.pngbin0 -> 363783 bytes
-rw-r--r--doc/source/modules/gui/plot3d/index.rst9
-rw-r--r--doc/source/modules/gui/plot3d/items.rst173
-rw-r--r--doc/source/modules/gui/plot3d/scalarfieldview.rst2
-rw-r--r--doc/source/modules/gui/plot3d/scenewidget.rst29
-rw-r--r--doc/source/modules/gui/plot3d/scenewindow.rst22
-rw-r--r--doc/source/modules/gui/plot3d/viewer3dvolume_example.rst7
-rw-r--r--doc/source/modules/index.rst3
-rw-r--r--doc/source/modules/io/index.rst2
-rw-r--r--doc/source/modules/io/url.rst8
-rw-r--r--doc/source/modules/opencl/codec_cbf.rst9
-rw-r--r--doc/source/modules/opencl/fbp.rst10
-rw-r--r--doc/source/modules/opencl/index.rst15
-rw-r--r--doc/source/modules/opencl/medfilt.rst7
-rw-r--r--doc/source/modules/opencl/sift/align.rst7
-rw-r--r--doc/source/modules/opencl/sift/index.rst11
-rw-r--r--doc/source/modules/opencl/sift/match.rst7
-rw-r--r--doc/source/modules/opencl/sift/plan.rst7
-rw-r--r--doc/source/modules/sx.rst77
-rw-r--r--doc/source/modules/utils/index.rst2
-rw-r--r--doc/source/modules/utils/testutils.rst7
-rw-r--r--doc/source/overview.rst21
-rw-r--r--doc/source/sample_code/img/colormapDialog.pngbin0 -> 48471 bytes
-rw-r--r--doc/source/sample_code/img/customDataView.pngbin0 -> 4571 bytes
-rw-r--r--doc/source/sample_code/img/fileDialog.pngbin0 -> 27709 bytes
-rw-r--r--doc/source/sample_code/img/plot3dContextMenu.pngbin52128 -> 40674 bytes
-rw-r--r--doc/source/sample_code/img/plot3dSceneWindow.pngbin0 -> 363783 bytes
-rw-r--r--doc/source/sample_code/img/plotClearAction.pngbin0 -> 26459 bytes
-rw-r--r--doc/source/sample_code/img/viewer3DVolume.pngbin58235 -> 61379 bytes
-rw-r--r--doc/source/sample_code/index.rst243
-rw-r--r--doc/source/tutorials.rst4
-rw-r--r--examples/animatedicons.py155
-rw-r--r--examples/colormapDialog.py272
-rw-r--r--examples/customDataView.py106
-rw-r--r--examples/customHdf5TreeModel.py3
-rwxr-xr-xexamples/fftPlotAction.py8
-rw-r--r--examples/fileDialog.py262
-rwxr-xr-xexamples/hdf5widget.py167
-rw-r--r--examples/icons.py102
-rwxr-xr-xexamples/imageview.py7
-rw-r--r--examples/plot3dSceneWindow.py197
-rw-r--r--examples/plotClearAction.py75
-rw-r--r--examples/plotContextMenu.py11
-rwxr-xr-xexamples/plotItemsSelector.py4
-rw-r--r--examples/plotUpdateFromThread.py6
-rw-r--r--examples/plotWidget.py8
-rwxr-xr-xexamples/printPreview.py11
-rwxr-xr-xexamples/shiftPlotAction.py6
-rwxr-xr-xexamples/simplewidget.py5
-rw-r--r--examples/stackView.py6
-rw-r--r--examples/syncaxis.py1
-rw-r--r--package/debian8/control9
-rwxr-xr-xpackage/debian8/rules1
-rw-r--r--package/debian9/control5
-rwxr-xr-xpackage/debian9/rules1
-rw-r--r--package/desktop/org.silx.SilxView.desktop10
-rw-r--r--package/desktop/silx.xml60
-rw-r--r--requirements-dev.txt5
-rw-r--r--requirements.txt10
-rwxr-xr-xrun_tests.py175
-rw-r--r--setup.py141
-rw-r--r--silx.egg-info/PKG-INFO139
-rw-r--r--silx.egg-info/SOURCES.txt149
-rw-r--r--silx/app/convert.py368
-rw-r--r--silx/app/test/test_convert.py37
-rw-r--r--silx/app/test/test_view.py22
-rw-r--r--silx/app/test_.py33
-rw-r--r--silx/app/view.py50
-rw-r--r--silx/gui/_glutils/OpenGLWidget.py5
-rw-r--r--silx/gui/_glutils/Texture.py7
-rw-r--r--silx/gui/_glutils/gl.py5
-rw-r--r--silx/gui/_utils.py79
-rw-r--r--silx/gui/console.py5
-rw-r--r--silx/gui/data/DataViewer.py153
-rw-r--r--silx/gui/data/DataViewerFrame.py17
-rw-r--r--silx/gui/data/DataViewerSelector.py40
-rw-r--r--silx/gui/data/DataViews.py365
-rw-r--r--silx/gui/data/Hdf5TableView.py35
-rw-r--r--silx/gui/data/NXdataWidgets.py390
-rw-r--r--silx/gui/data/NumpyAxesSelector.py24
-rw-r--r--silx/gui/data/TextFormatter.py47
-rw-r--r--silx/gui/data/test/test_dataviewer.py87
-rw-r--r--silx/gui/data/test/test_numpyaxesselector.py16
-rw-r--r--silx/gui/data/test/test_textformatter.py13
-rw-r--r--silx/gui/dialog/AbstractDataFileDialog.py1718
-rw-r--r--silx/gui/dialog/DataFileDialog.py342
-rw-r--r--silx/gui/dialog/FileTypeComboBox.py213
-rw-r--r--silx/gui/dialog/ImageFileDialog.py338
-rw-r--r--silx/gui/dialog/SafeFileIconProvider.py150
-rw-r--r--silx/gui/dialog/SafeFileSystemModel.py802
-rw-r--r--silx/gui/dialog/__init__.py29
-rw-r--r--silx/gui/dialog/setup.py40
-rw-r--r--silx/gui/dialog/test/__init__.py47
-rw-r--r--silx/gui/dialog/test/test_datafiledialog.py981
-rw-r--r--silx/gui/dialog/test/test_imagefiledialog.py803
-rw-r--r--silx/gui/dialog/utils.py104
-rw-r--r--silx/gui/hdf5/Hdf5Formatter.py5
-rw-r--r--silx/gui/hdf5/Hdf5Item.py126
-rw-r--r--silx/gui/hdf5/Hdf5TreeModel.py135
-rw-r--r--silx/gui/hdf5/Hdf5TreeView.py113
-rw-r--r--silx/gui/hdf5/NexusSortFilterProxyModel.py20
-rw-r--r--silx/gui/hdf5/_utils.py51
-rw-r--r--silx/gui/hdf5/test/test_hdf5.py99
-rw-r--r--silx/gui/icons.py3
-rw-r--r--silx/gui/plot/ColorBar.py44
-rw-r--r--silx/gui/plot/Colormap.py243
-rw-r--r--silx/gui/plot/ColormapDialog.py897
-rw-r--r--silx/gui/plot/ComplexImageView.py314
-rw-r--r--silx/gui/plot/CurvesROIWidget.py684
-rw-r--r--silx/gui/plot/Interaction.py2
-rw-r--r--silx/gui/plot/PlotToolButtons.py15
-rw-r--r--silx/gui/plot/PlotTools.py10
-rw-r--r--silx/gui/plot/PlotWidget.py172
-rw-r--r--silx/gui/plot/PlotWindow.py63
-rw-r--r--silx/gui/plot/Profile.py12
-rw-r--r--silx/gui/plot/StackView.py24
-rw-r--r--silx/gui/plot/_utils/test/test_ticklayout.py18
-rw-r--r--silx/gui/plot/_utils/ticklayout.py20
-rw-r--r--silx/gui/plot/actions/PlotAction.py3
-rw-r--r--silx/gui/plot/actions/__init__.py12
-rw-r--r--silx/gui/plot/actions/control.py140
-rw-r--r--silx/gui/plot/actions/fit.py4
-rw-r--r--silx/gui/plot/actions/histogram.py4
-rw-r--r--silx/gui/plot/actions/io.py133
-rw-r--r--silx/gui/plot/actions/medfilt.py8
-rw-r--r--silx/gui/plot/backends/BackendBase.py11
-rw-r--r--silx/gui/plot/backends/BackendMatplotlib.py154
-rw-r--r--silx/gui/plot/backends/BackendOpenGL.py177
-rw-r--r--silx/gui/plot/backends/glutils/GLPlotCurve.py2
-rw-r--r--silx/gui/plot/backends/glutils/PlotImageFile.py2
-rw-r--r--silx/gui/plot/items/__init__.py7
-rw-r--r--silx/gui/plot/items/axis.py8
-rw-r--r--silx/gui/plot/items/complex.py356
-rw-r--r--silx/gui/plot/items/core.py95
-rw-r--r--silx/gui/plot/items/image.py7
-rw-r--r--silx/gui/plot/items/marker.py3
-rw-r--r--silx/gui/plot/matplotlib/Colormap.py58
-rw-r--r--silx/gui/plot/matplotlib/__init__.py5
-rw-r--r--silx/gui/plot/test/__init__.py6
-rw-r--r--silx/gui/plot/test/testColormap.py76
-rw-r--r--silx/gui/plot/test/testColormapDialog.py321
-rw-r--r--silx/gui/plot/test/testColors.py4
-rw-r--r--silx/gui/plot/test/testComplexImageView.py4
-rw-r--r--silx/gui/plot/test/testCurvesROIWidget.py19
-rw-r--r--silx/gui/plot/test/testItem.py20
-rw-r--r--silx/gui/plot/test/testMaskToolsWidget.py9
-rw-r--r--silx/gui/plot/test/testPlotTools.py4
-rw-r--r--silx/gui/plot/test/testPlotWidget.py22
-rw-r--r--silx/gui/plot/test/testPlotWidgetNoBackend.py4
-rw-r--r--silx/gui/plot/test/testProfile.py4
-rw-r--r--silx/gui/plot/test/testSaveAction.py97
-rw-r--r--silx/gui/plot/test/testScatterMaskToolsWidget.py9
-rw-r--r--silx/gui/plot/test/testUtilsAxis.py23
-rw-r--r--silx/gui/plot/test/utils.py127
-rw-r--r--silx/gui/plot/utils/axis.py78
-rw-r--r--silx/gui/plot3d/ParamTreeView.py541
-rw-r--r--silx/gui/plot3d/Plot3DWidget.py60
-rw-r--r--silx/gui/plot3d/Plot3DWindow.py23
-rw-r--r--silx/gui/plot3d/SFViewParamTree.py270
-rw-r--r--silx/gui/plot3d/ScalarFieldView.py430
-rw-r--r--silx/gui/plot3d/SceneWidget.py646
-rw-r--r--silx/gui/plot3d/SceneWindow.py192
-rw-r--r--silx/gui/plot3d/_model/__init__.py (renamed from silx/third_party/_local/__init__.py)17
-rw-r--r--silx/gui/plot3d/_model/core.py372
-rw-r--r--silx/gui/plot3d/_model/items.py1388
-rw-r--r--silx/gui/plot3d/_model/model.py184
-rw-r--r--silx/gui/plot3d/actions/Plot3DAction.py10
-rw-r--r--silx/gui/plot3d/actions/io.py15
-rw-r--r--silx/gui/plot3d/actions/mode.py15
-rw-r--r--silx/gui/plot3d/actions/viewpoint.py141
-rw-r--r--silx/gui/plot3d/items/__init__.py43
-rw-r--r--silx/gui/plot3d/items/clipplane.py50
-rw-r--r--silx/gui/plot3d/items/core.py622
-rw-r--r--silx/gui/plot3d/items/image.py126
-rw-r--r--silx/gui/plot3d/items/mesh.py145
-rw-r--r--silx/gui/plot3d/items/mixins.py302
-rw-r--r--silx/gui/plot3d/items/scatter.py474
-rw-r--r--silx/gui/plot3d/items/volume.py463
-rw-r--r--silx/gui/plot3d/scene/__init__.py2
-rw-r--r--silx/gui/plot3d/scene/axes.py19
-rw-r--r--silx/gui/plot3d/scene/camera.py7
-rw-r--r--silx/gui/plot3d/scene/cutplane.py46
-rw-r--r--silx/gui/plot3d/scene/function.py36
-rw-r--r--silx/gui/plot3d/scene/interaction.py58
-rw-r--r--silx/gui/plot3d/scene/primitives.py1241
-rw-r--r--silx/gui/plot3d/scene/test/test_utils.py4
-rw-r--r--silx/gui/plot3d/scene/transform.py24
-rw-r--r--silx/gui/plot3d/scene/utils.py42
-rw-r--r--silx/gui/plot3d/scene/viewport.py59
-rw-r--r--silx/gui/plot3d/scene/window.py27
-rw-r--r--silx/gui/plot3d/setup.py2
-rw-r--r--silx/gui/plot3d/test/__init__.py12
-rw-r--r--silx/gui/plot3d/test/testScalarFieldView.py4
-rw-r--r--silx/gui/plot3d/tools/GroupPropertiesWidget.py200
-rw-r--r--silx/gui/plot3d/tools/ViewpointTools.py119
-rw-r--r--silx/gui/plot3d/tools/__init__.py6
-rw-r--r--silx/gui/plot3d/tools/toolbars.py111
-rw-r--r--silx/gui/qt/_qt.py64
-rw-r--r--silx/gui/qt/_utils.py25
-rw-r--r--silx/gui/setup.py3
-rw-r--r--silx/gui/test/__init__.py15
-rw-r--r--silx/gui/test/test_utils.py91
-rw-r--r--silx/gui/test/utils.py88
-rw-r--r--silx/gui/widgets/FrameBrowser.py2
-rw-r--r--silx/gui/widgets/MedianFilterDialog.py10
-rw-r--r--silx/gui/widgets/PeriodicTable.py8
-rw-r--r--silx/gui/widgets/PrintPreview.py4
-rw-r--r--silx/gui/widgets/ThreadPoolPushButton.py11
-rw-r--r--silx/gui/widgets/test/test_threadpoolpushbutton.py24
-rw-r--r--silx/image/test/test_shapes.py4
-rw-r--r--silx/io/__init__.py9
-rw-r--r--silx/io/commonh5.py53
-rw-r--r--silx/io/configdict.py8
-rw-r--r--silx/io/convert.py81
-rw-r--r--silx/io/dictdump.py27
-rw-r--r--silx/io/fabioh5.py336
-rw-r--r--silx/io/nxdata.py669
-rw-r--r--silx/io/specfile.c12792
-rw-r--r--silx/io/specfile.pyx18
-rw-r--r--silx/io/specfile/src/locale_management.c24
-rw-r--r--silx/io/specfilewrapper.py4
-rw-r--r--silx/io/spech5.py155
-rw-r--r--silx/io/test/__init__.py4
-rw-r--r--silx/io/test/test_dictdump.py25
-rw-r--r--silx/io/test/test_fabioh5.py181
-rw-r--r--silx/io/test/test_nxdata.py271
-rw-r--r--silx/io/test/test_specfile.py32
-rw-r--r--silx/io/test/test_specfilewrapper.py17
-rw-r--r--silx/io/test/test_spech5.py72
-rw-r--r--silx/io/test/test_spectoh5.py23
-rw-r--r--silx/io/test/test_url.py209
-rw-r--r--silx/io/test/test_utils.py221
-rw-r--r--silx/io/url.py366
-rw-r--r--silx/io/utils.py419
-rw-r--r--silx/math/fit/fitmanager.py12
-rw-r--r--silx/math/fit/test/test_fit.py6
-rw-r--r--silx/math/medianfilter/test/test_medianfilter.py4
-rw-r--r--silx/math/test/benchmark_combo.py5
-rw-r--r--silx/math/test/test_combo.py4
-rw-r--r--silx/math/test/test_marchingcubes.py4
-rw-r--r--silx/opencl/backprojection.py4
-rw-r--r--silx/opencl/codec/__init__.py0
-rw-r--r--silx/opencl/codec/byte_offset.py439
-rw-r--r--silx/opencl/codec/setup.py43
-rw-r--r--silx/opencl/codec/test/__init__.py37
-rw-r--r--silx/opencl/codec/test/test_byte_offset.py317
-rw-r--r--silx/opencl/common.py5
-rw-r--r--silx/opencl/image.py387
-rw-r--r--silx/opencl/processing.py59
-rw-r--r--silx/opencl/projection.py89
-rw-r--r--silx/opencl/setup.py3
-rw-r--r--silx/opencl/test/__init__.py7
-rw-r--r--silx/opencl/test/test_addition.py6
-rw-r--r--silx/opencl/test/test_backprojection.py4
-rw-r--r--silx/opencl/test/test_image.py137
-rw-r--r--silx/opencl/test/test_projection.py16
-rw-r--r--silx/resources/__init__.py45
-rw-r--r--silx/resources/gui/icons/colormap-histogram.pngbin0 -> 641 bytes
-rw-r--r--silx/resources/gui/icons/colormap-histogram.svg37
-rw-r--r--silx/resources/gui/icons/colormap-none.pngbin0 -> 232 bytes
-rw-r--r--silx/resources/gui/icons/colormap-none.svg33
-rw-r--r--silx/resources/gui/icons/colormap-range.pngbin0 -> 284 bytes
-rw-r--r--silx/resources/gui/icons/colormap-range.svg37
-rw-r--r--silx/resources/gui/icons/math-phase.pngbin515 -> 1868 bytes
-rw-r--r--silx/resources/gui/icons/math-phase.svg4
-rw-r--r--silx/resources/gui/icons/math-square-amplitude.pngbin0 -> 592 bytes
-rw-r--r--silx/resources/gui/icons/math-square-amplitude.svg3
-rw-r--r--silx/resources/opencl/codec/byte_offset.cl235
-rw-r--r--silx/resources/opencl/image/cast.cl181
-rw-r--r--silx/resources/opencl/image/histogram.cl178
-rw-r--r--silx/resources/opencl/image/map.cl85
-rw-r--r--silx/resources/opencl/image/max_min.cl207
-rw-r--r--silx/sx/__init__.py38
-rw-r--r--silx/sx/_plot.py338
-rw-r--r--silx/sx/_plot3d.py246
-rw-r--r--silx/test/__init__.py4
-rw-r--r--silx/test/test_resources.py15
-rw-r--r--silx/test/test_sx.py121
-rw-r--r--silx/test/utils.py243
-rw-r--r--silx/third_party/EdfFile.py4
-rw-r--r--silx/third_party/_local/enum.py877
-rw-r--r--silx/third_party/_local/six.py868
-rw-r--r--silx/third_party/concurrent_futures.py59
-rw-r--r--silx/third_party/scipy_spatial.py51
-rw-r--r--silx/third_party/setup.py6
-rw-r--r--silx/utils/array_like.py6
-rw-r--r--silx/utils/deprecation.py8
-rw-r--r--silx/utils/exceptions.py33
-rw-r--r--silx/utils/launcher.py18
-rw-r--r--silx/utils/property.py52
-rw-r--r--silx/utils/test/test_deprecation.py18
-rw-r--r--silx/utils/test/test_launcher.py4
-rw-r--r--silx/utils/testutils.py281
-rw-r--r--version.py11
335 files changed, 33408 insertions, 15186 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 041dc7a..2eb56e6 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,20 +1,78 @@
Change Log
==========
-0.6.1: 2017/11/10
+0.7.0: 2018/02/27
-----------------
- * Plot:
+ * Input/output:
+
+ * Priovides `silx.io.url.DataUrl` to parse supported links identifying
+ group or dataset from files.
+ * `silx.io.open` now supports h5pyd and silx custom URLs.
+ * `silx.io.get_data` is provided to allow to reach a numpy array from silx.
+
+ * OpenCL:
+
+ * Provides an API to share memory between OpenCL tasks within the same device.
+ * Provides CBF compression and decompression.
+ * Simple processing on images (normalization, histogram).
+ * Sift upgrade using memory sharing.
+
+ * `silx.sx`:
+
+ * Added `contour3d` function for displaying 3D isosurfaces.
+ * Added `points3d` function for displaying 2D/3D scatter plots.
+ * Added `ginput` function for interactive input of points on 1D/2D plots.
+
+ * Graphic user interface:
+
+ * Provides a file dialog to pick a dataset or a group from HDF5 files.
+ * Provides a file dialog to pick an image from HDF5 files or multiframes formats.
+ * The colormap dialog can now be used as non-modal.
+ * `PlotWidget` can save the displayed data as a new `NXentry` of a HDF5 file.
+ * `PlotWidget` exports displayed data as spec files using more digits.
+ * Added new OpenGL-based 3D visualization widgets:
+
+ * Supports 3D scalar field view 2D/3D scatter plots and images.
+ * Provides an object oriented API similar to that of the 1D/2D plot.
+ * Features a tree of parameters to edit visualized item's properties
+ (e.g., transforms, colormap...)
+ * Provides interactive panning of cut and clip planes.
+
+ * Updates of `ScalarFieldView` widget:
+
+ * Added support for a 3x3 transform matrix (to support non orthogonal axes)
+ * Added support of an alternative interaction when `ctrl` is pressed
+ (e.g., rotate by default and pan when ctrl/command key is pressed).
+ * Added 2 sliders to control light direction in associated parameter tree view.
+
+ * `silx view`:
+
+ * Uses a single colormap to show any datasets.
+ * The colormap dialog can stay opened while browsing the data.
+ * The application is associated with some file types to be used to load files
+ on Debian.
+ * Provides a square amplitude display mode to visualize complex images.
+ * Browsing an `NXentry` can display a default `NXdata`.
+ * Added explanation when an `NXdata` is not displayable.
+ * `NXdata` visualization can now show multiple curves (see `@auxiliary_signals`).
+ * Supports older `NXdata` specification.
+
+ * `silx convert`:
- * Fix logarithmic axes, broken by new matplotlib version 2.1.0.
- * Fix axis limits changed signal, not emitted with matplotlib 1.5.x and 2.0.x
- when the widget is resized.
- * Support displaying float128 data with matplotlib < 2.1.0.
- * Fix minor bugs with the crosshair cursor and the legends widget.
+ * Added handling of file series as a single multiframe
+ * Default behavior changes to avoid to add an extra group at the root,
+ unless explicitly requested (see `--add-root-group`).
+ * Writer uses now utf-8 text as default (NeXus specification).
+ * EDF files containing MCA data are now interpreted as spectrum.
- * Update documentation on Zenodo DOI and Debian packages installation.
- * Fix the Debian packaging script for Ubuntu distributions.
+ * Miscellaneous:
+ * Added `silx.utils.testutils` to share useful unittest functions with other
+ projects.
+ * Python 2 on Mac OS X is no longer tested.
+ * Experimental support to PySide2.
+ * If fabio is used, a version >= 0.6 is mandatory.
0.6.0: 2017/10/02
-----------------
diff --git a/PKG-INFO b/PKG-INFO
index ed985dc..907a50f 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,7 +1,7 @@
Metadata-Version: 1.1
Name: silx
-Version: 0.6.1
-Summary: Software library for X-Ray data analysis
+Version: 0.7.0
+Summary: Software library for X-ray data analysis
Home-page: http://www.silx.org/
Author: data analysis unit
Author-email: silx@esrf.fr
@@ -10,127 +10,77 @@ Description:
silx toolkit
============
- The silx project aims at providing a collection of Python packages to support the
+ The purpose of the *silx* project is to provide a collection of Python packages to support the
development of data assessment, reduction and analysis applications at synchrotron
radiation facilities.
It aims at providing reading/writing different file formats, data reduction routines
- and a set of Qt widgets to browse and visualize data.
+ and a set of Qt widgets to browse and visualise data.
- The current version provides:
+ The current version features:
- * reading `HDF5 <https://www.hdfgroup.org/HDF5/>`_ file format (with support of
- `SPEC <https://certif.com/spec.html>`_ file format and
+ * Support of `HDF5 <https://www.hdfgroup.org/HDF5/>`_,
+ `SPEC <https://certif.com/spec.html>`_ and
`FabIO <http://www.silx.org/doc/fabio/dev/getting_started.html#list-of-file-formats-that-fabio-can-read-and-write>`_
- images)
- * histogramming
- * fitting
- * 1D and 2D visualization widgets using multiple backends (matplotlib or OpenGL)
- * an OpenGL-based widget to display 3D scalar field with isosurface and cutting plane
- * an image plot widget with a set of associated tools
- * a unified browser for HDF5, SPEC and image file formats supporting inspection and
- visualization of n-dimensional datasets.
- * a unified viewer (*silx view filename*) for HDF5, SPEC and image file formats
- * a unified converter to HDF5 format (*silx convert filename*)
- * median filters on images (C and OpenCL implementations)
- * image alignement (sift - OpenCL implementation)
- * filtered backprojection and forward projection for tomography
+ images file formats.
+ * OpenCL-based data processing: image alignment (SIFT),
+ image processing (median filter, histogram),
+ filtered backprojection for tomography
+ * Data reduction: histogramming, fitting, median filter
+ * A set of Qt widgets, including:
+
+ * 1D and 2D visualization widgets with a set of associated tools using multiple backends (matplotlib or OpenGL)
+ * OpenGL-based widgets to visualize data in 3D (scalar field with isosurface and cut plane, scatter plot)
+ * a unified browser for HDF5, SPEC and image file formats supporting inspection and
+ visualization of n-dimensional datasets.
+
+ * a set of applications:
+
+ * a unified viewer (*silx view filename*) for HDF5, SPEC and image file formats
+ * a unified converter to HDF5 format (*silx convert filename*)
Installation
------------
- To install silx, run::
+ To install silx, run:
+
+ .. code-block:: bash
pip install silx
- Or with Anaconda on Linux and MacOS::
+ Or using Anaconda on Linux and MacOS:
+
+ .. code-block:: bash
conda install silx -c conda-forge
- To install silx locally, run::
-
- pip install silx --user
-
- Unofficial packages for different distributions are available :
+ Unofficial packages for different distributions are available:
- Unofficial Debian8 packages are available at http://www.silx.org/pub/debian/
- - CentOS 7 rpm packages are provided by Max IV at the following url: http://pubrepo.maxiv.lu.se/rpm/el7/x86_64/
+ - CentOS 7 rpm packages are provided by Max IV at: http://pubrepo.maxiv.lu.se/rpm/el7/x86_64/
- Fedora 23 rpm packages are provided by Max IV at http://pubrepo.maxiv.lu.se/rpm/fc23/x86_64/
- Arch Linux (AUR) packages are also available: https://aur.archlinux.org/packages/python-silx
- Beside this, we provide a certain number of wheels (pre-compiled binary packages) to be installed
- onto a pre-existing Python installation:
-
- - On Windows, binary wheels are available for Python 2.7, 3.5 and 3.6.
- - On MacOS, binary wheels are available for Python 2.7, 3.5 and 3.6.
- - On Linux, manylinux1 binary wheels are available for Python 2.7, 3.4, 3.5 and 3.6.
-
- Those builds are made from "up-date" systems at the time of the release, i.e. they use
- the latest stable version of numpy (and cython).
- Hence your system should use a fairly recent version of numpy to be compatible with silx.
- This can be achieved simply by::
-
- pip install numpy --upgrade
-
-
- The latest development version can be obtained from the git repository::
-
- git clone https://github.com/silx-kit/silx.git
- cd silx
- pip install . [--user]
-
- Dependencies
- ------------
-
- * `Python <https://www.python.org/>`_ 2.7, 3.4 or above.
- * `numpy <http://www.numpy.org>`_
-
- The GUI widgets of the silx package depend on the following extra packages:
-
- * A Qt binding: `PyQt5, PyQt4 <https://riverbankcomputing.com/software/pyqt/intro>`_ (using API version 2) or `PySide <https://pypi.python.org/pypi/PySide/>`_
- * `matplotlib <http://matplotlib.org/>`_ for the silx.gui.plot package
- * `PyOpenGL <http://pyopengl.sourceforge.net/>`_ for the silx.gui.plot3d package
-
- Most modules and functions dealing with `HDF5 <https://www.hdfgroup.org/HDF5/>`_ input/output depend on:
-
- * `h5py <http://www.h5py.org/>`_
-
- Parallel algorithms depend on:
-
- * `PyOpenCL <https://documen.tician.de/pyopencl/>`_
-
- The console widgets depend on:
-
- * `ipython <https://ipython.org/>`_
- * `qtconsole <https://pypi.python.org/pypi/qtconsole>`_
-
-
- Supported platforms: Linux, Windows, Mac OS X.
+ `Detailed installation instructions <http://www.silx.org/doc/silx/dev/install.html>`_
+ are available in the documentation.
Documentation
-------------
- Documentation of latest release is available at http://www.silx.org/doc/silx/latest/
-
- Documentation of previous releases and nightly build is available at http://www.silx.org/doc/silx/
-
- To build the documentation from the source (requires `Sphinx <http://www.sphinx-doc.org>`_), run::
-
- python setup.py build build_doc
+ The documentation of `latest release <http://www.silx.org/doc/silx/latest/>`_ and
+ the documentation of `the nightly build <http://www.silx.org/doc/silx/dev>`_ are
+ available at http://www.silx.org/doc/silx/
Testing
-------
+ *silx* features a comprehensive test-suite used in continuous integration for
+ all major operating systems:
+
- Travis CI status: |Travis Status|
- Appveyor CI status: |Appveyor Status|
- To run the tests from the python interpreter, run:
-
- >>> import silx.test
- >>> silx.test.run_tests()
-
- To run the tests, from the source directory, run::
-
- python run_tests.py
+ Please refer to the `documentation on testing <http://www.silx.org/doc/silx/dev/install.html#testing>`_
+ for details.
Examples
--------
@@ -142,13 +92,14 @@ Description:
License
-------
- The source code of silx is licensed under the MIT license.
- See the `LICENSE <https://github.com/silx-kit/silx/blob/master/LICENSE>`_ and `copyright <https://github.com/silx-kit/silx/blob/master/copyright>`_ files for details.
+ The source code of *silx* is licensed under the MIT license.
+ See the `LICENSE <https://github.com/silx-kit/silx/blob/master/LICENSE>`_ and
+ `copyright <https://github.com/silx-kit/silx/blob/master/copyright>`_ files for details.
Citation
--------
- silx releases can be cited by their DOI on Zenodo: |zenodo DOI|
+ *silx* releases can be cited via their DOI on Zenodo: |zenodo DOI|
.. |Travis Status| image:: https://travis-ci.org/silx-kit/silx.svg?branch=master
:target: https://travis-ci.org/silx-kit/silx
diff --git a/README.rst b/README.rst
index a7ccdf5..b6ab6c2 100644
--- a/README.rst
+++ b/README.rst
@@ -2,127 +2,77 @@
silx toolkit
============
-The silx project aims at providing a collection of Python packages to support the
+The purpose of the *silx* project is to provide a collection of Python packages to support the
development of data assessment, reduction and analysis applications at synchrotron
radiation facilities.
It aims at providing reading/writing different file formats, data reduction routines
-and a set of Qt widgets to browse and visualize data.
+and a set of Qt widgets to browse and visualise data.
-The current version provides:
+The current version features:
-* reading `HDF5 <https://www.hdfgroup.org/HDF5/>`_ file format (with support of
- `SPEC <https://certif.com/spec.html>`_ file format and
+* Support of `HDF5 <https://www.hdfgroup.org/HDF5/>`_,
+ `SPEC <https://certif.com/spec.html>`_ and
`FabIO <http://www.silx.org/doc/fabio/dev/getting_started.html#list-of-file-formats-that-fabio-can-read-and-write>`_
- images)
-* histogramming
-* fitting
-* 1D and 2D visualization widgets using multiple backends (matplotlib or OpenGL)
-* an OpenGL-based widget to display 3D scalar field with isosurface and cutting plane
-* an image plot widget with a set of associated tools
-* a unified browser for HDF5, SPEC and image file formats supporting inspection and
- visualization of n-dimensional datasets.
-* a unified viewer (*silx view filename*) for HDF5, SPEC and image file formats
-* a unified converter to HDF5 format (*silx convert filename*)
-* median filters on images (C and OpenCL implementations)
-* image alignement (sift - OpenCL implementation)
-* filtered backprojection and forward projection for tomography
+ images file formats.
+* OpenCL-based data processing: image alignment (SIFT),
+ image processing (median filter, histogram),
+ filtered backprojection for tomography
+* Data reduction: histogramming, fitting, median filter
+* A set of Qt widgets, including:
+
+ * 1D and 2D visualization widgets with a set of associated tools using multiple backends (matplotlib or OpenGL)
+ * OpenGL-based widgets to visualize data in 3D (scalar field with isosurface and cut plane, scatter plot)
+ * a unified browser for HDF5, SPEC and image file formats supporting inspection and
+ visualization of n-dimensional datasets.
+
+* a set of applications:
+
+ * a unified viewer (*silx view filename*) for HDF5, SPEC and image file formats
+ * a unified converter to HDF5 format (*silx convert filename*)
Installation
------------
-To install silx, run::
+To install silx, run:
+
+.. code-block:: bash
pip install silx
-Or with Anaconda on Linux and MacOS::
+Or using Anaconda on Linux and MacOS:
+
+.. code-block:: bash
conda install silx -c conda-forge
-To install silx locally, run::
-
- pip install silx --user
-
-Unofficial packages for different distributions are available :
+Unofficial packages for different distributions are available:
- Unofficial Debian8 packages are available at http://www.silx.org/pub/debian/
-- CentOS 7 rpm packages are provided by Max IV at the following url: http://pubrepo.maxiv.lu.se/rpm/el7/x86_64/
+- CentOS 7 rpm packages are provided by Max IV at: http://pubrepo.maxiv.lu.se/rpm/el7/x86_64/
- Fedora 23 rpm packages are provided by Max IV at http://pubrepo.maxiv.lu.se/rpm/fc23/x86_64/
- Arch Linux (AUR) packages are also available: https://aur.archlinux.org/packages/python-silx
-Beside this, we provide a certain number of wheels (pre-compiled binary packages) to be installed
-onto a pre-existing Python installation:
-
-- On Windows, binary wheels are available for Python 2.7, 3.5 and 3.6.
-- On MacOS, binary wheels are available for Python 2.7, 3.5 and 3.6.
-- On Linux, manylinux1 binary wheels are available for Python 2.7, 3.4, 3.5 and 3.6.
-
-Those builds are made from "up-date" systems at the time of the release, i.e. they use
-the latest stable version of numpy (and cython).
-Hence your system should use a fairly recent version of numpy to be compatible with silx.
-This can be achieved simply by::
-
- pip install numpy --upgrade
-
-
-The latest development version can be obtained from the git repository::
-
- git clone https://github.com/silx-kit/silx.git
- cd silx
- pip install . [--user]
-
-Dependencies
-------------
-
-* `Python <https://www.python.org/>`_ 2.7, 3.4 or above.
-* `numpy <http://www.numpy.org>`_
-
-The GUI widgets of the silx package depend on the following extra packages:
-
-* A Qt binding: `PyQt5, PyQt4 <https://riverbankcomputing.com/software/pyqt/intro>`_ (using API version 2) or `PySide <https://pypi.python.org/pypi/PySide/>`_
-* `matplotlib <http://matplotlib.org/>`_ for the silx.gui.plot package
-* `PyOpenGL <http://pyopengl.sourceforge.net/>`_ for the silx.gui.plot3d package
-
-Most modules and functions dealing with `HDF5 <https://www.hdfgroup.org/HDF5/>`_ input/output depend on:
-
-* `h5py <http://www.h5py.org/>`_
-
-Parallel algorithms depend on:
-
-* `PyOpenCL <https://documen.tician.de/pyopencl/>`_
-
-The console widgets depend on:
-
-* `ipython <https://ipython.org/>`_
-* `qtconsole <https://pypi.python.org/pypi/qtconsole>`_
-
-
-Supported platforms: Linux, Windows, Mac OS X.
+`Detailed installation instructions <http://www.silx.org/doc/silx/dev/install.html>`_
+are available in the documentation.
Documentation
-------------
-Documentation of latest release is available at http://www.silx.org/doc/silx/latest/
-
-Documentation of previous releases and nightly build is available at http://www.silx.org/doc/silx/
-
-To build the documentation from the source (requires `Sphinx <http://www.sphinx-doc.org>`_), run::
-
- python setup.py build build_doc
+The documentation of `latest release <http://www.silx.org/doc/silx/latest/>`_ and
+the documentation of `the nightly build <http://www.silx.org/doc/silx/dev>`_ are
+available at http://www.silx.org/doc/silx/
Testing
-------
+*silx* features a comprehensive test-suite used in continuous integration for
+all major operating systems:
+
- Travis CI status: |Travis Status|
- Appveyor CI status: |Appveyor Status|
-To run the tests from the python interpreter, run:
-
->>> import silx.test
->>> silx.test.run_tests()
-
-To run the tests, from the source directory, run::
-
- python run_tests.py
+Please refer to the `documentation on testing <http://www.silx.org/doc/silx/dev/install.html#testing>`_
+for details.
Examples
--------
@@ -134,13 +84,14 @@ Some examples of sample code using silx are provided with the
License
-------
-The source code of silx is licensed under the MIT license.
-See the `LICENSE <https://github.com/silx-kit/silx/blob/master/LICENSE>`_ and `copyright <https://github.com/silx-kit/silx/blob/master/copyright>`_ files for details.
+The source code of *silx* is licensed under the MIT license.
+See the `LICENSE <https://github.com/silx-kit/silx/blob/master/LICENSE>`_ and
+`copyright <https://github.com/silx-kit/silx/blob/master/copyright>`_ files for details.
Citation
--------
-silx releases can be cited by their DOI on Zenodo: |zenodo DOI|
+*silx* releases can be cited via their DOI on Zenodo: |zenodo DOI|
.. |Travis Status| image:: https://travis-ci.org/silx-kit/silx.svg?branch=master
:target: https://travis-ci.org/silx-kit/silx
diff --git a/doc/source/Tutorials/Sift/sift.rst b/doc/source/Tutorials/Sift/sift.rst
deleted file mode 100644
index 7168cf3..0000000
--- a/doc/source/Tutorials/Sift/sift.rst
+++ /dev/null
@@ -1,315 +0,0 @@
-
-SIFT image alignment tutorial
-=============================
-
-SIFT (Scale-Invariant Feature Transform) is an algorithm developped by
-David Lowe in 1999. It is a worldwide reference for image alignment and
-object recognition. The robustness of this method enables to detect
-features at different scales, angles and illumination of a scene.
-
-Silx provides an implementation of SIFT in OpenCL, meaning that it can
-run on Graphics Processing Units and Central Processing Units as well.
-Interest points are detected in the image, then data structures called
-*descriptors* are built to be characteristic of the scene, so that two
-different images of the same scene have similar descriptors. They are
-robust to transformations like translation, rotation, rescaling and
-illumination change, which make SIFT interesting for image stitching.
-
-In the fist stage, descriptors are computed from the input images. Then,
-they are compared to determine the geometric transformation to apply in
-order to align the images. This implementation can run on most graphic
-cards and CPU, making it usable on many setups. OpenCL processes are
-handled from Python with PyOpenCL, a module to access OpenCL parallel
-computation API.
-
-This tutuorial explains the three subsequent steps:
-
-- keypoint extraction
-- Keypoint matching
-- image alignment
-
-All the tutorial has been made using the Jupyter notebook.
-
-.. code:: python
-
- import time
- start_time = time.time()
- %pylab nbagg
-
-
-.. parsed-literal::
-
- Populating the interactive namespace from numpy and matplotlib
-
-
-.. code:: python
-
- # display test image
- import silx
- print("Silx version %s"%silx.version)
-
- from PIL import Image
- from silx.test.utils import utilstest
- path = utilstest.getfile("lena.png")
- image = numpy.asarray(Image.open(path))
- fig, ax = subplots()
- ax.imshow(image, cmap="gray")
-
-
-.. parsed-literal::
-
- Silx version 0.5.0-dev0
-
-
-
-.. parsed-literal::
-
- <IPython.core.display.Javascript object>
-
-
-
-.. raw:: html
-
- <img src="data:image/png;base64,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" width="640">
-
-
-
-
-.. parsed-literal::
-
- <matplotlib.image.AxesImage at 0x7f0805b03e80>
-
-
-
-.. code:: python
-
- #Initialization of the sift object is time consuming: it compiles all the code.
- import os
- #set to 1 to see the compilation going on
- os.environ["PYOPENCL_COMPILER_OUTPUT"] = "0"
- from silx.image import sift
- #switch to "GPU" to "CPU" to enable fail-save version.
- %time sift_ocl = sift.SiftPlan(template=image, devicetype="GPU")
-
-
-.. parsed-literal::
-
- CPU times: user 112 ms, sys: 112 ms, total: 224 ms
- Wall time: 240 ms
-
-
-.. code:: python
-
- print("Time for calculating the keypoints on one image of size %sx%s"%image.shape[:2])
- %time keypoints = sift_ocl(image)
- print("Number of keypoints: %s"%len(keypoints))
- print("Keypoint content:")
- print(keypoints.dtype)
- print("x: %.3f \t y: %.3f \t sigma: %.3f \t angle: %.3f" %
- (keypoints[-1].x,keypoints[-1].y,keypoints[-1].scale,keypoints[-1].angle))
- print("descriptor:")
- print(keypoints[-1].desc)
-
-
-.. parsed-literal::
-
- Time for calculating the keypoints on one image of size 512x512
- CPU times: user 652 ms, sys: 0 ns, total: 652 ms
- Wall time: 649 ms
- Number of keypoints: 411
- Keypoint content:
- (numpy.record, [('x', '<f4'), ('y', '<f4'), ('scale', '<f4'), ('angle', '<f4'), ('desc', 'u1', (128,))])
- x: 275.483 y: 302.585 sigma: 36.518 angle: -0.194
- descriptor:
- [ 11 5 0 1 5 20 22 8 88 20 3 0 0 4 40 120 41 9
- 13 52 32 36 15 81 1 8 14 25 89 84 7 1 12 0 0 0
- 22 94 29 9 120 32 0 0 1 21 43 69 81 20 0 0 22 120
- 43 49 48 120 13 2 16 79 17 3 24 6 0 0 30 76 16 9
- 120 64 7 5 5 10 7 38 64 75 36 37 38 54 5 8 109 120
- 9 1 2 4 12 21 39 22 0 0 18 19 5 4 120 120 10 5
- 1 0 0 0 27 42 44 52 37 20 6 2 24 10 3 2 7 42
- 81 25]
-
-
-.. code:: python
-
- #Overlay keypoints on the image:
- fig, ax = subplots()
- ax.imshow(image)
- ax.plot(keypoints[:].x, keypoints[:].y,".g")
-
-
-
-.. parsed-literal::
-
- <IPython.core.display.Javascript object>
-
-
-
-.. raw:: html
-
- <img src="data:image/png;base64,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" width="640">
-
-
-
-
-.. parsed-literal::
-
- [<matplotlib.lines.Line2D at 0x7f07fc026278>]
-
-
-
-.. code:: python
-
- #Diplaying keypoints by scale:
- fig, ax = subplots()
- ax.hist(keypoints[:].scale, 100)
- ax.set_xlabel("scale")
-
-
-
-.. parsed-literal::
-
- <IPython.core.display.Javascript object>
-
-
-
-.. raw:: html
-
- <img src="data:image/png;base64,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RQButs+sxr+p/n71Ay2f83veavqTWjb+g7bd77XVb5/iMY+t7nPSOJsBKAgBYHcE4Ga7q7p5222/UL119fVeAvCcOwIoAAFgdwTgZru1+vfbbnt+9f7V13t5C3i7s/4ZQAEIALsjADfbf+yeJ4G8vBNHBbdOAnnh2vSLm+wkEAEIALsjADfbE6q/q15SPax6bvWp6rvW5rm++lj1zOqK6g1NdhkYAQgAuyMAN98/brn482eq/9nJZwHXiQtBf2g1z43VI3bx+AIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgJwsx1r2bjr451r0y+sXl3dVn2yel31gF0+hwAEgMkIwM12rPrz6oFr44vXpt9Qvbe6qnp89dbqLbt8DgEIAJMRgJvtWPUnp5h2SXVXdfXabY9q2RmeuIvnEIAAMBkBuNmOVZ+qPlC9q/rN6iGraVe1bPhLt93n1uq6XTyHAASAyQjAzfaM6juqx1bfUt3cEnj3q55b3bnDfd5Wvew0j3lBy86yNS5LAALAVATg0XJpdUf1fe09AI91zxNLBCAATEQAHj1vr17a3t8CdgQQACYnAI+Wi6rbqxd04iSQ56xNf2ROAgGAjScAN9vPV0+pLq+eVP1h9ZHq/qvpN7Qc8buy5TIwN6/GbghAAJiMANxsv9VyBvCd1ftW33/l2vStC0Hf3nK28OtbrhW4GwIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjAI+OH2vZ0K9Yu+3C6tXVbdUnq9dVD9jl4wpAAJiMADwanlC9u/rTTg7AG6r3VldVj6/eWr1ll48tAAFgMgJw811U/VX1tOqmTgTgJdVd1dVr8z6qZWd44i4eXwACwGQE4Ob7terlq69v6kQAXtWy4S/dNv+t1XWnebwLWnaWrXFZAhAApiIAN9s11TtaPutXJwfgc6s7d7jP26qXneYxj7XsMCcNAQgA8xCAm+vB1d9Uj1277abGA9ARQACYnADcXM9u2bCfXRt3V59bff1N7e0t4O18BhAAJiMAN9f9qq/eNt5e/frq662TQJ6zdp9H5iQQANh4AvBoual7Xgbm1urKlsvA3LwauyEAAWAyAvBouamdLwR9e/Wp6vXVA3f5mAIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUedcAIpCADg9AcgoAQgAkxGAjBKAADAZAcgoAQgAkxGAjBKAADAZAcgoAQgAkxGAjBKAADAZAcgoAQgAkxGAm+351Z9Vf7sab62esTb9wurV1W3VJ6vXVQ/Y5XMIQACYjADcbN9WfWv18OoR1c9Ud1WPWU2/oXpvdVX1+JZAfMsun0MAAsBkBODRc3v1fdUlLTF49dq0R7XsDE/cxeMJQACYjAA8Ou5TXVPdWX1Vy1G/u6tLt813a3XdLh5XAALAZATg5rui5fN9n60+3vKWcNVzW2Jwu7dVLzvN413QsrNsjcsSgAAwFQG4+e5bPazlM34vrT7ScgRwrwF4rGWHOWkIQACYhwA8em6sfrm9vwXsCCAATE4AHj1/VL2mEyeBPGdt2iNzEggAbDwBuNleWj25urzls4AvrT5XPX01/YaWI35XtrxFfPNq7IYABIDJCMDN9qvVe1o+6/fhlrd/n742fetC0LdXn6peXz1wl88hAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgKQUQIQACYjABklAAFgMgJws724env1ierD1RuqR26b58Lq1dVt1Ser11UP2MVzbEwAikYAjgoBuNl+v7q2ekz1NdXvVbdWX7g2zw3Ve6urqsdXb63esovnEIAAMBkBeLTcv2VjP3n1/SXVXdXVa/M8ajXPE8/wMQUgAExGAB4tD2vZ2F+9+v6q1feXbpvv1uq6UzzGBS07y9a4LAEIAFMRgEfH+dWbqj9eu+251Z07zPu26mWneJxjLTvMSeNcD8AziTsBCMBRIQCPjhuq91RftnbbXgJwyiOAAhAAThCAR8OrquPVV2y7fS9vAW83xWcABSAAnCAAN9t5LfH3/urhO0zfOgnkOWu3PbINPAlEAALACQJws/1S9fHqKdUD18bnr81zQ8sRvytbLgNz82qcKQEIAJMRgJvtHidrrMa1a/NsXQj69upT1etbIvFMHakAFIkAbAIByCgBCACTEYCMEoAAMBkByCgBCACTEYCMEoAAMBkByCgBCACTEYCMEoAAMBkByCgBCACTEYCMmjIADzISAeBcJwAZJQABYDICkFECEAAmIwAZJQABYDICkFECEAAmIwAZJQABYDICkFECEAAmIwAZJQABYDICkFECEAAmIwAZJQABYDICkFECEAAmIwAZJQABYDICkFECEAAmIwAZtbEBuNdIBIBznQBklAAEgMkIQEYJQACYjABklAAEgMkIQEYJQACYjABklAAEgMkIQEYJQACYjABklAAEgMkIQEYJQACYjABklAAEgMkIQEYJQACYjABklAAEgMkIQEYJQACYjADcbE+ufrf6QMtGfva26edVP1V9sPp0dWP18F0+hwAEgMkIwM32jOqnq29v5wC8vvp49azqsdUbq3dVF+7iOQQgAExGAB4d2wPwvJYjfy9au+2S6jPVNbt4XAEIAJMRgEfH9gB86Oq2x22b783VK3fxuAIQACYjAI+O7QH4pNVtD9o232ur3z7N41zQsrNsjcsSgAAwFQF4dOxXAB5b3e+kIQABYB4C8OjYr7eAHQEUgABMTgAeHac6CeSFa7ddnJNABCAAG08AbraLWo7wPa5lI1+3+vohq+nXVx+rnlldUb0hl4ERgABsPAG42Z7aDp/Xq16zmr51IegPtRz5u7F6xC6fQwACwGQEIKMEIABMRgAySgACwGQEIKMEIABMRgAy6kgHoCgEYEYCkFECUAACMBkByCgBKAABmIwAZJQAFIAATEYAMkoACkAAJiMAGSUABSAAkxGAjBKAAhCAyQhARglAAQjAZAQgowSgAARgMgKQUQLwgAJQWAJwUAQgowSgAARgMgKQUQJQAAIwGQHIKAEoAAGYjABklAC8l1DbazTu1zwAsJ0AZJQAFIAATEYAMkoACkAAJiMAGSUABSAAkxGAjBKAAhCAyQhARgnAcygAD3KZAdgcApBRAlAAAjAZAcgoASgAAZiMAGSUABSAAExGADJKAJ6lsNzP1+dMHvdsOteWB2B2ApBRAlAAHrhzbXkAZicAGSUABeCBO9eWB2B2ApBRAlAAHrhzbXkAZicAGSUABeCBO9eWB2B2ApBRAnADxl5e94O0X89/VKLxsF+fo/K6snv2jXkIQEYJwA0Ye3ndD9J+Pf9R+WF02K/PUXld2T37xjwEIKME4AaMvbzuB2m/nv+o/DA67NfnqLyu7J59Yx4CkFECcAPGXl73g7Rfz39Ufhgd9utzVF5Xds++MQ8BSNUPVe+pPlPdUn3dLu4rADdg7OV1P9e210Euz7luv16fvT7fDPZrmTdhfzlIM74W59oyH9byCEC+s7qz+p7qq6pfqT5WfckZ3l8AbsDYy+t+rm2vg1yec91+vT57fb4Z7Ncyb8L+cpBmfC3OtWU+rOURgNxSvWrt+/Or91c/dob3F4AbMPbyup9r2+sgl+dct1+vz16fbwb7tcybsL8cpBlfi3NtmQ9reQTg0Xbf6rPVs7fd/mvVG09xnwtadpatcVl19/Hjx+++44479n08+EdfaxzC2Mvrfq5tr4NcnoPYtw/7/5Mzud9en+9sr/9hLvMm7C8zvM5HeZkPa3mOHz8uAI+wL23Z+N+w7fafazkyuJNjq/sYhmEYhjH/uCyOnL0E4PYjgBdXl7d2NHD13+3zbNqwrps5rOtmDuu6eeOorOdBr+tl1Xlx5OzlLeDTubhlJ714cLlmYF03k3XdTNZ18xyV9ayjta4coluqX1z7/vzqfZ35SSDrjtJOal03k3XdTNZ18xyV9ayjta4cou9suf7f86pHV7/cchmYB+zhsY7STmpdN5N13UzWdfMclfWso7WuHLIfrm5tuR7gLdXX7/FxLmg5SeSC/Vmsc5p13UzWdTNZ181zVNazjta6AgAAAAAAAAAAAAAAAAfhh6r3tFxS5pbq687q0hycY93zz+i882wu0D56cvW71Qda1mv7BcLPq36q+mD16erG6uGHuYD76N7W9TXdczv//iEu3355cfX26hPVh6s3VI/cNs+F1aur26pPVq9rb5eBOtvOZF1v6p7b9d8d3iLum+dXf1b97Wq8tXrG2vRN2aZ17+t6U5uxTbf7sZZ1ecXabZu0XdkQ39lyCZnvqb6q+pWWawl+ydlcqANyrPrz6oFr44vP5gLto2dUP119eztH0fXVx6tnVY9t+Wsx72r5R2k297aur6n+Uydv5y86xOXbL79fXVs9pvqa6vdaLvn0hWvz3FC9t7qqenzLD9i3HOpS7o8zWdebWv59Wt+uM15b7duqb235BewR1c9Ud7Wse23ONq17X9eb2oxtuu4J1burP+3kANyk7cqGuKV61dr351fvb29/TeRcd6z6k7O9EIdgexSd13Lk70Vrt13ScsT3mkNcroNwqgB8w+EvyoG7f8v6Pnn1/SUtP0yvXpvnUat5nni4i7bvtq9rLbHwih3nnt/t1fe12dt0y9a61uZt04uqv6qe1snrdhS2K5PZ778nfK47Vn2q5a3Dd1W/WT3kbC7QAdkeRQ9d3fa4bfO9uXrlYS3UATlVAH685a3Ev2z5zfvvHe5iHYiHtazvV6++v2r1/aXb5ru1uu4Ql+sgbF/XWn6gfqT6aMuR/JdWX3DoS7a/7tPyS9idLe/AbPI23b6utXnb9Neql6++vqkTAbjJ25VJfWnLTvkN227/uZYjg5vmGdV3tLwF+i3VzS3/A97vbC7UAdgeRU9a3fagbfO9tvrtw1qoA7JTAF5TPbO6YjXtL6q3tfwAmtX51ZuqP1677bktP0y3e1v1ssNYqAOy07pW/UDL/7dXVN/V8nfPX3+4i7Zvrmj5HNhnW35Z+dbV7Zu4TU+1rrVZ2/Sa6h2d+FjNTZ0IwE3crkzuqAXgdpdWd3Ti7YhNcdQDcLutI6DfdPCLc2BuaDlR68vWbtvUHyo7retOto6qfOVBL9ABuG/LUc7Htxz1+kjLUbFN3KanWtedzLpNH1z9TcvBhS03JQA5hx21t4B38vaWf5Q2yVF/C3gnH6l+8ICX5aC8qjpefcW22zfxbaVTretOvrBl/b/lQJfocNxY/XKbuU2321rXncy6TZ/dstyfXRt3V59bff1Nbf52ZUK3VL+49v35LYfhN/EkkO0uavlA8gvO9oLss1OdBPLCtdsubnNPAtnuy1r+IX7mwS/OvjqvJYje386X7Nn6YPlz1m57ZHN+sPze1nUn39iyro+9txkn8Ectn13dpG16KlvrupNZt+n9Wj6vuj7eXv366uujsF2Z0He2hMDzqke3/Gb2sTbz+kQ/Xz2lurzlbdE/bDkydP+zuEz75aKWI3yPa/lH5brV11snuVzfsl23Phv3hua9DMzp1vWi6t+2/KN6ectv3v+15cy8C87Cso74pZbPTD2lky+T8flr89zQchThypa32G5ejdnc27p+ZfUTLet4ect+/NctR7Fn89KWs5svb/l/8aUtv6A8fTV9U7ZpnX5dN2mb7uSm7nkZmE3ZrmyQH27ZMe9sOSL49Wd3cQ7Mb7WcAXxny1HO32q+z5qcylO75wVV7+7Eb9pbF4L+UEvw39hyXa4ZPbVTr+vnV3/QcgbwXS2fJfuV5vyFZqd1vLvlenlbti4ue3vLGe6vbwmn2dzbuj64JQxua9l//1fLZ5VnvGbcr7bsl3e27Kc3diL+anO2aZ1+XTdpm+7kpna+EPQmbFcAAAAAAAAAAAAAAAAAAAAAAAAAAADuxbUtf3kDAIAj4toEIADAkXJtAhAA4Jx0dfWO6tMtfzP1xuoLV9O+t/ofLX9n9YPVq9bu9y9W9/tUdbz6peqitenXds8AfFb131r+Luu7qp+sPm/f1gQAgHv1oOrvquuqy6srqn/WEnLPb4nCH6keUT2h+tG1+/5odeXqfldV72yJwC3XdnIA/sPqjup51UOrp1fvbolAAAAOyT+o7q6+fIdp769+ehePdXX10bXvr+3kALyxevG2+/zT6gO7eA4AAAbdpyXM/rb6ner7qy+qvqQlDK88zX2fVv3nllD8RMvRwrurL1hNv7aTA/Ajq3k+uTa23wcAgENwXvWN1b+q/qz6cMtbwacLwMtbPsf38uqJLW8Rf+/qPpeu5rm2kwPw09W/rB62wzh/n9YFAIBduk/1vpYTPN7dqd8Cfk51VyeH2493+gB8S/Wr+7isAADswddXL6m+tnpI9R0tZ/w+o+VkjU9XL6ge3vJ5wX++ut/XtMTej7Sc0PHdLeF4ugD8lpYTTn6yekz16Oqadvc5QwAABj26+v2Wt30/U/1l9cNr03+w5ezeu1pO1viFtWnXrW77P6vH+O5OH4C1ROBbVve5o7ql5XOHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnMv+H625rciQ7INuAAAAAElFTkSuQmCC" width="640">
-
-
-
-
-.. parsed-literal::
-
- <matplotlib.text.Text at 0x7f07fc042128>
-
-
-
-.. code:: python
-
- #One can see 3 groups of keypoints, boundaries at: 8 and 20. Let's display them using colors.
- S = 8
- L = 20
- tiny = keypoints[keypoints[:].scale<S]
- small = keypoints[numpy.logical_and(keypoints[:].scale<L,keypoints[:].scale>=S)]
- bigger = keypoints[keypoints[:].scale>=L]
-
- fig, ax = subplots()
- ax.imshow(image, cmap="gray")
- ax.plot(tiny[:].x, tiny[:].y,",g", label="tiny")
- ax.plot(small[:].x, small[:].y,".b", label="small")
- ax.plot(bigger[:].x, bigger[:].y,"or", label="large")
- ax.legend()
-
-
-
-.. parsed-literal::
-
- <IPython.core.display.Javascript object>
-
-
-
-.. raw:: html
-
- <img src="data:image/png;base64,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" width="640">
-
-
-
-
-.. parsed-literal::
-
- <matplotlib.legend.Legend at 0x7f07f47bf710>
-
-
-
-Image matching and alignment
-----------------------------
-
-Matching can also be performed on the device (GPU) as every single
-keypoint from an image needs to be compared with all keypoints from the
-second image.
-
-In this simple example we will simple offset the first image by a few
-pixels
-
-.. code:: python
-
- shifted = numpy.zeros_like(image)
- shifted[5:,8:] = image[:-5, :-8]
- shifted_points = sift_ocl(shifted)
-
-.. code:: python
-
- %time mp = sift.MatchPlan()
- %time match = mp(keypoints, shifted_points)
- print("Number of Keypoints with for image 1 : %i, For image 2 : %i, Matching keypoints: %i" % (keypoints.size, shifted_points.size, match.shape[0]))
- from numpy import median
- print("Measured offsets dx: %.3f, dy: %.3f"%(median(match[:,1].x-match[:,0].x),median(match[:,1].y-match[:,0].y)))
-
-
-.. parsed-literal::
-
- CPU times: user 20 ms, sys: 128 ms, total: 148 ms
- Wall time: 167 ms
- CPU times: user 8 ms, sys: 4 ms, total: 12 ms
- Wall time: 14.9 ms
- Number of Keypoints with for image 1 : 411, For image 2 : 399, Matching keypoints: 351
- Measured offsets dx: 8.000, dy: 5.000
-
-
-.. code:: python
-
- # Example of usage of the automatic alignment:
- import scipy.ndimage
- rotated = scipy.ndimage.rotate(image, 20, reshape=False)
- sa = sift.LinearAlign(image)
- fig,ax = subplots(1, 3, figsize=(12,4))
- ax[0].imshow(image)
- ax[1].imshow(rotated)
- ax[2].imshow(sa.align(rotated))
-
-
-.. parsed-literal::
-
- /scisoft/users/jupyter/jupy34/lib/python3.4/site-packages/pyopencl/cffi_cl.py:1469: CompilerWarning: Non-empty compiler output encountered. Set the environment variable PYOPENCL_COMPILER_OUTPUT=1 to see more.
- "to see more.", CompilerWarning)
-
-
-
-.. parsed-literal::
-
- <IPython.core.display.Javascript object>
-
-
-
-.. raw:: html
-
- <img src="data:image/png;base64,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" width="1200">
-
-
-
-
-.. parsed-literal::
-
- <matplotlib.image.AxesImage at 0x7f076c299240>
-
-
-
-References
-~~~~~~~~~~
-
-- David G. Lowe, Distinctive image features from scale-invariant
- keypoints, International Journal of Computer Vision, vol. 60, no 2,
- 2004, p. 91–110 - "http://www.cs.ubc.ca/~lowe/papers/ijcv04.pdf"
-
-.. code:: python
-
- print("Total execution time: %.3fs" % (time.time() - start_time))
-
-
-.. parsed-literal::
-
- Total execution time: 6.190s
-
diff --git a/doc/source/Tutorials/array_widget.rst b/doc/source/Tutorials/array_widget.rst
index f2ccfdf..c6a32e3 100644
--- a/doc/source/Tutorials/array_widget.rst
+++ b/doc/source/Tutorials/array_widget.rst
@@ -4,7 +4,8 @@
ArrayTableWidget
================
-:class:`ArrayTableWidget` is a widget designed to visualize numpy arrays or h5py datasets.
+:class:`ArrayTableWidget` is a widget designed to visualize numpy arrays or h5py
+datasets.
3D example
----------
@@ -166,7 +167,7 @@ for internal storage. This ensures that the original data object is not
modified when a cell of the table is changed interactively in the widget.
This behavior has a negative impact on performances, especially for large data arrays.
-To avoid this, you can explicitely disable the copy operation when setting the data:
+To avoid this, you can explicitly disable the copy operation when setting the data:
.. code-block:: python
diff --git a/doc/source/Tutorials/convert.rst b/doc/source/Tutorials/convert.rst
new file mode 100644
index 0000000..c7e67a6
--- /dev/null
+++ b/doc/source/Tutorials/convert.rst
@@ -0,0 +1,107 @@
+
+Converting various data files to HDF5
+=====================================
+
+This document explains how to convert SPEC files, EDF files and various other data
+formats into HDF5 files.
+
+An understanding of the way these data formats are exposed by the :meth:`silx.io.open`
+function is a prerequisite for this tutorial. You can learn more about this subject by
+reading :doc:`io`.
+
+Using the convert module
+++++++++++++++++++++++++
+
+The *silx* module :mod:`silx.io.convert` can be used to convert various data files into a
+HDF5 file with the same structure as the one exposed by the :mod:`spech5` or :mod:`fabioh5` modules.
+
+.. code-block:: python
+
+ from silx.io.convert import convert
+
+ convert("myspecfile.dat", "myfile.h5")
+
+
+You can then read the file with any HDF5 reader.
+
+
+The function :func:`silx.io.convert.convert` is a simplified version of a
+more flexible function :func:`silx.io.convert.write_to_h5`.
+
+The latter allows you to write scans into a specific HDF5 group in the output directory.
+You can also decide whether you want to overwrite an existing file, or append data to it.
+You can specify whether existing data with the same name as input data should be overwritten
+or ignored.
+
+This allows you to repeatedly transfer new content of a SPEC file to an existing
+HDF5 file, in between two scans.
+
+The following script is an example of a command line interface to :func:`write_to_h5`.
+
+.. literalinclude:: ../../../examples/writetoh5.py
+ :lines: 44-
+
+But the functionality implemented in this script (and much more) is already implemented
+in the *silx convert* application.
+
+
+Using the convert application
++++++++++++++++++++++++++++++
+
+.. versionadded:: 0.6
+
+
+*silx* also provides a ``silx convert`` command line application, which allows you to
+perform standard conversions without having to write your own program.
+
+Type ``silx convert --help`` in a terminal to see all available options.
+
+.. note::
+
+ The complete documentation for the *silx convert* command is available here:
+ :doc:`../applications/convert`.
+
+Converting single files
+***********************
+
+The simplest command to convert a single SPEC file to an HDF5 file would be:
+
+.. code-block:: bash
+
+ silx convert myspecfile.dat
+
+As no output name is supplied, the output file name will be a time-stamp with a
+*.h5* suffix (e.g. *20180110-114930.h5*).
+
+The following example allows you to append the content of a SPEC file to an
+existing HDF5 file::
+
+ silx convert myspecfile.dat -m a -o myhdf5file.h5
+
+The ``-m a`` argument stands for *append mode*. The ``-o myhdf5file.h5``
+argument is used to specify the output file name.
+
+You could write the file into a specific group of the HDF5 file by providing
+the complete URL in the format ``file_path::group_path``. For instance::
+
+ silx convert myspecfile.dat -m a -o archive.h5::/2017-09-20/SPEC
+
+
+Merging a stack of images
+*************************
+
+*silx convert* can merge a stack of image files.
+It support series of single frame files, and is based on
+`fabio.file_series <http://www.silx.org/doc/fabio/dev/api/modules.html?highlight=series#fabio.file_series.file_series>`_.
+All frames must have the same shape.
+
+The following command merges all files matching a pattern::
+
+ silx convert --file-pattern ch09__mca_0005_0000_%d.edf -o ch09__mca_0005_0000_multiframe.h5
+
+The data in the output file is presented as a 3D array.
+
+It is possible to provide multiple indices in the file name pattern, and specify a
+range for each index::
+
+ silx convert --file-pattern ch09__mca_0005_%04d_%04d.edf --begin 0,1 --end 0,54
diff --git a/doc/source/Tutorials/fit.rst b/doc/source/Tutorials/fit.rst
index 1305299..9889274 100644
--- a/doc/source/Tutorials/fit.rst
+++ b/doc/source/Tutorials/fit.rst
@@ -16,7 +16,7 @@ Using :func:`leastsq`
Running an iterative fit with :func:`leastsq` involves the following steps:
- designing a fit model function that has the signature ``f(x, ...)``,
- where ``x`` is an array of values of the independant variable and all
+ where ``x`` is an array of values of the independent variable and all
remaining parameters are the parameters to be fitted
- defining the sequence of initial values for all parameters to be fitted.
You can usually start with ``[1., 1., ...]`` if you don't know a better
@@ -26,13 +26,13 @@ Running an iterative fit with :func:`leastsq` involves the following steps:
Data required to perform a fit is:
- - an array of ``x`` values (abscissa, independant variable)
+ - an array of ``x`` values (abscissa, independent variable)
- an array of ``y`` data points
- the ``sigma`` array of uncertainties associated to each data point.
This is optional, by default each data point gets assigned a weight of 1.
-Standard fit
-************
+Default (unweighted) fit
+************************
Let's demonstrate this process in a short example, using synthetic data.
We generate an array of synthetic data using a polynomial function of degree 4,
@@ -83,16 +83,22 @@ The output of this program is::
Optimal parameters for y fitting:
a=2.400000, b=-9.999665, c=14.970422, d=31.683448, e=-3216.131136
+.. note::
+
+ The exact results may vary depending on your Python version.
+
We can see that this fit result is poor. In particular, parameters ``d`` and ``e``
are very poorly fitted.
-This is most likely due to numerical rounding errors. As we are dealing with
-very large values in our ``y`` array, we are affected by the limits of how
-floating point numbers are represented by computers. The larger a value, the
-larger its rounding error.
-If you limit the ``x`` range to deal with
-smaller ``y`` values, the fit result becomes perfect. In our example, replacing ``x``
-with::
+This is due to the fact that data points with large values have a stronger influence
+in the fit process. In our examples, as ``x`` increases, ``y`` increases fast.
+The influence of the weighting, and how to solve this issue is explained in more details
+in the next section.
+
+In the meantime, if you simply limit the ``x`` range, to deal with
+smaller ``y`` values, you can notice that the fit result becomes perfect.
+
+In our example, replacing ``x`` with::
x = numpy.arange(100)
@@ -106,11 +112,66 @@ produces the following result::
a=2.400000, b=-10.000000, c=15.200000, d=-24.600000, e=150.000000
+Weighted fit
+************
+
+Since the fitting algorithm minimizes the sum of squared differences between input
+and evaluated data, points with higher y value had a greater weight in the fitting process.
+A solution to this problem, if we want to improve our fit, is to define uncertainties
+for the data.
+The larger the uncertainty on a data sample, the smaller its weight will be
+in the least-square problem.
+
+It is important to set the uncertainties correctly, or you risk favoring either
+the lower values or the higher values in your data.
+
+The common approach in counting experiments is to use the square-root of the data
+values as the uncertainty value (assuming a Poissonian law).
+Let's apply it to our previous example:
+
+.. code-block:: python
+
+ sigma = numpy.sqrt(y)
+
+ # Fit y
+ fitresult = leastsq(model=poly4,
+ xdata=x,
+ ydata=y,
+ sigma=sigma,
+ p0=initial_parameters,
+ full_output=True)
+
+This results in a great improvement::
+
+ Weighted fit took 6 iterations
+ Reduced chi-square: 0.000000
+ Theoretical parameters:
+ a=2.4, b=-10, c=15.2, d=-24.6, e=150
+ Optimal parameters for y fitting:
+ a=2.400000, b=-10.000000, c=15.200000, d=-24.600000, e=150.000000
+
+The resulting fit is perfect. The fit converged even faster than when
+we limited ``x`` range to 0 -- 100.
+
+To use a real world example, when fitting x-ray fluorescence spectroscopy data,
+this common approach means that we consider the variance of each channel to be
+the number of counts in that channel.
+That corresponds to assuming a normal distribution.
+The true distribution being a Poisson distribution, the Gaussian distribution
+is a good approximation for channels with high number of counts,
+but the approximation is not valid when the number of counts in a channel is small.
+
+Therefore, in spectra where the overall statistics is very low, a
+weighted fit can lead the fitting process to fit the background
+considering the peaks as outliers, because the fit will consider a
+channel with 1 count 100 times more relevant than a channel with 100
+counts.
+
Constrained fit
***************
-But let's revert back to our initial ``x = numpy.arange(1000)``, to experiment
+But let's revert back to our unweighted fit, to experiment
with different approaches to improving the fit.
The :func:`leastsq` functions provides
@@ -151,43 +212,6 @@ The output of this program is::
The chi-square value is much improved and the results are much better, at the
cost of more iterations.
-Weighted fit
-************
-A third approach to improve our fit is to define uncertainties for the data.
-The larger the uncertainty on a data sample, the smaller its weight will be
-in the least-square problem.
-
-In our case, we do not know the uncertainties associated to our data. We could
-determine the uncertainties due to numerical rounding errors, but let's just use
-a common approach that requires less work: use the square-root of the data values
-as their uncertainty value:
-
-.. code-block:: python
-
- sigma = numpy.sqrt(y)
-
- # Fit y
- fitresult = leastsq(model=poly4,
- xdata=x,
- ydata=y,
- sigma=sigma,
- p0=initial_parameters,
- full_output=True)
-
-This results in a great improvement::
-
- Weighted fit took 6 iterations
- Reduced chi-square: 0.000000
- Theoretical parameters:
- a=2.4, b=-10, c=15.2, d=-24.6, e=150
- Optimal parameters for y fitting:
- a=2.400000, b=-10.000000, c=15.200000, d=-24.600000, e=150.000000
-
-The resulting fit is perfect. The very large ``y`` values with their very large
-associated uncertainties have been practicaly rejected from the fit process. The fit
-converged even faster than with the solution of limiting the ``x`` range to
-0 -- 100.
-
.. _fitmanager-tutorial:
Using :class:`FitManager`
@@ -326,7 +350,7 @@ And the result of this program is::
In addition to gaussians, we could have fitted several other similar type of
functions: asymetric gaussian functions, lorentzian functions,
-Pseudo-Voigt functions or hypermet tailing functions.
+pseudo-voigt functions or hypermet tailing functions.
The :meth:`loadtheories` method can also be used to load user defined
functions. Instead of a module, a path to a Python source file can be given
diff --git a/doc/source/Tutorials/io.rst b/doc/source/Tutorials/io.rst
index 139ad2d..369e5ad 100644
--- a/doc/source/Tutorials/io.rst
+++ b/doc/source/Tutorials/io.rst
@@ -31,7 +31,8 @@ Regarding HDF5 files, the de-facto standard for reading them in Python is to
use the *h5py* library.
*silx* tries to address this situation by providing a unified way to read all
-data formats supported at the ESRF. Today, HDF5 is the preffered format to store
+data formats supported at the ESRF.
+Today, HDF5 is the preffered format to store
data for many scientific institutions, including most synchrotrons.
So it was decided to provide tools for reading data that mimic the *h5py* library's API.
@@ -100,7 +101,7 @@ The objects defined in `silx.io` implement a subset of these attributes and meth
- :attr:`filename`: Name of the file on disk.
- :attr:`mode`: String indicating if the file is open in read mode ("r")
or write mode ("w"). :meth:`silx.io.open` always returns objects in read mode.
- - :meth:`close`: Close this file. All open objects will become invalid.
+ - :meth:`close`: Close this file. All child objects, groups and datasets, will become invalid.
The :attr:`parent` of a file is `None`, and its :attr:`name` is an empty string.
diff --git a/doc/source/Tutorials/specfile_to_hdf5.rst b/doc/source/Tutorials/specfile_to_hdf5.rst
index 32d942a..5a5f0a5 100644
--- a/doc/source/Tutorials/specfile_to_hdf5.rst
+++ b/doc/source/Tutorials/specfile_to_hdf5.rst
@@ -293,64 +293,13 @@ Files and groups can be treated as iterators, which allows looping through them.
print("Found labels in scan " + scan_group.name + " :")
print(", ".join(dataset_names))
-Converting SPEC data to HDF5
-++++++++++++++++++++++++++++
-
-Using the convert module
-************************
-
-The *silx* module :mod:`silx.io.convert` can be used to convert a SPEC file into a
-HDF5 file with the same structure as the one exposed by the :mod:`spech5` module.
-
-.. code-block:: python
-
- from silx.io.convert import convert
-
- convert("/home/pierre/myspecfile.dat", "myfile.h5")
-
-
-You can then read the file with any HDF5 reader.
-
-
-The function :func:`silx.io.convert.convert` is a simplified version of a
-more flexible function :func:`silx.io.convert.write_to_h5`.
-
-The latter allows you to write scans into a specific HDF5 group in the output directory.
-You can also decide whether you want to overwrite an existing file, or append data to it.
-You can specify whether existing data with the same name as input data should be overwritten
-or ignored.
-This allows you to repeatedly transfer new content of a SPEC file to an existing HDF5 file, in between
-two scans.
+.. note::
-The following script is an example of a command line interface to :func:`write_to_h5`.
+ A :class:`SpecH5` object is also returned when you open a SPEC file
+ with :meth:`silx.io.open`. See :doc:`io` for additional information.
-.. literalinclude:: ../../../examples/writetoh5.py
- :lines: 44-
-
-Using the convert application
-*****************************
-
-.. versionadded:: 0.6
-
-*silx* also provides a ``silx convert`` command line application, which allows you to
-perform standard conversions without having to write your own program.
-
-Type ``silx convert --help`` in a terminal to see all available options.
-
-The simplest command to convert a single SPEC file to an HDF5 file would be::
-
- silx convert myspecfile.dat
-
-As no output name is supplied, the input file name is reused but the extension is
-modified from *.dat* to *.h5*.
-
-The following example allows you to append the content of a SPEC file to an
-existing HDF5 file::
-
- silx convert myspecfile.dat -m a -o myhdf5file.h5
-
-You could write the file into a specific group of the HDF5 file by providing
-the complete URI in the format ``file_path::group_path``. For instance::
+Converting SPEC data to HDF5
+++++++++++++++++++++++++++++
- silx convert myspecfile.dat -m a -o archive.h5::/2017-09-20/SPEC
+See :doc:`convert`.
diff --git a/doc/source/applications/convert.rst b/doc/source/applications/convert.rst
new file mode 100644
index 0000000..28da60b
--- /dev/null
+++ b/doc/source/applications/convert.rst
@@ -0,0 +1,130 @@
+
+silx convert
+============
+
+Purpose
+-------
+
+The *silx convert* command is provided to help with archiving legacy file
+formats into HDF5 files.
+
+You can refer to following tutorials for additional information
+about the output format:
+
+ - :doc:`../Tutorials/io`
+ - :doc:`../Tutorials/convert`
+ - :doc:`../Tutorials/specfile_to_hdf5`
+
+Usage
+-----
+
+::
+
+ silx convert [-h] [--file-pattern FILE_PATTERN] [-o OUTPUT_URI]
+ [-m MODE] [--begin BEGIN] [--end END] [--add-root-group]
+ [--overwrite-data] [--min-size MIN_SIZE]
+ [--chunks [CHUNKS]] [--compression [COMPRESSION]]
+ [--compression-opts COMPRESSION_OPTS] [--shuffle]
+ [--fletcher32] [--debug]
+ [input_files [input_files ...]]
+
+
+
+Options
+-------
+
+::
+
+ input_files Input files (EDF, TIFF, SPEC...). When specifying
+ multiple files, you cannot specify both fabio images
+ and SPEC files. Multiple SPEC files will simply be
+ concatenated, with one entry per scan. Multiple image
+ files will be merged into a single entry with a stack
+ of images.
+
+
+ -h, --help show this help message and exit
+ --file-pattern FILE_PATTERN
+ File name pattern for loading a series of indexed
+ image files (toto_%04d.edf). This argument is
+ incompatible with argument input_files. If an output
+ URI with a HDF5 path is provided, only the content of
+ the NXdetector group will be copied there. If no HDF5
+ path, or just "/", is given, a complete NXdata
+ structure will be created.
+ -o OUTPUT_URI, --output-uri OUTPUT_URI
+ Output file name (HDF5). An URI can be provided to
+ write the data into a specific group in the output
+ file: /path/to/file::/path/to/group. If not provided,
+ the filename defaults to a timestamp: YYYYmmdd-
+ HHMMSS.h5
+ -m MODE, --mode MODE Write mode: "r+" (read/write, file must exist), "w"
+ (write, existing file is lost), "w-" (write, fail if
+ file exists) or "a" (read/write if exists, create
+ otherwise)
+ --begin BEGIN First file index, or first file indices to be
+ considered. This argument only makes sense when used
+ together with --file-pattern. Provide as many start
+ indices as there are indices in the file pattern, separated
+ by commas. Examples: "--filepattern toto_%d.edf
+ --begin 100", "--filepattern toto_%d_%04d_%02d.edf
+ --begin 100,2000,5".
+ --end END Last file index, or last file indices to be
+ considered. The same rules as with argument --begin
+ apply. Example: "--filepattern toto_%d_%d.edf --end
+ 199,1999"
+ --add-root-group This option causes each input file to be written to a
+ specific root group with the same name as the file.
+ When merging multiple input files, this can help
+ preventing conflicts when datasets have the same name
+ (see --overwrite-data). This option is ignored when
+ using --file-pattern.
+ --overwrite-data If the output path exists and an input dataset has the
+ same name as an existing output dataset, overwrite the
+ output dataset (in modes "r+" or "a").
+ --min-size MIN_SIZE Minimum number of elements required to be in a dataset
+ to apply compression or chunking (default 500).
+ --chunks <CHUNKS> Chunk shape. Provide an argument that evaluates as a
+ python tuple (e.g. "(1024, 768)"). If this option is
+ provided without specifying an argument, the h5py
+ library will guess a chunk for you. Note that if you
+ specify an explicit chunking shape, it will be applied
+ identically to all datasets with a large enough size
+ (see --min-size).
+ --compression <COMPRESSION>
+ Compression filter. By default, the datasets in the
+ output file are not compressed. If this option is
+ specified without argument, the GZIP compression is
+ used. Additional compression filters may be available,
+ depending on your HDF5 installation.
+ --compression-opts COMPRESSION_OPTS
+ Compression options. For "gzip", this may be an
+ integer from 0 to 9, with a default of 4. This is only
+ supported for GZIP.
+ --shuffle Enables the byte shuffle filter. This may improve the
+ compression ratio for block oriented compressors like
+ GZIP or LZF.
+ --fletcher32 Adds a checksum to each chunk to detect data
+ corruption.
+ --debug Set logging system in debug mode
+
+
+Examples of usage
+-----------------
+
+
+Simple single file conversion to new output file::
+
+ silx convert 31oct98.dat -o 31oct98.h5
+
+Concatenation of all SPEC files in the current directory::
+
+ silx convert *.dat -o all_SPEC.h5
+
+Appending a file to an existing output file::
+
+ silx convert ch09__mca_0005_0000_0008.edf -o archive.h5::/ch09__mca_0005_0000_0008 -m a --compression
+
+Merging a list of single frame EDF files into a multiframe HDF5 file::
+
+ silx convert --file-pattern ch09__mca_0005_0000_%d.edf -o ch09__mca_0005_0000_multiframe.h5
diff --git a/doc/source/applications/img/silx-view-hdf5.png b/doc/source/applications/img/silx-view-hdf5.png
new file mode 100644
index 0000000..96449fd
--- /dev/null
+++ b/doc/source/applications/img/silx-view-hdf5.png
Binary files differ
diff --git a/doc/source/applications/img/silx-view-image.png b/doc/source/applications/img/silx-view-image.png
new file mode 100644
index 0000000..85b0362
--- /dev/null
+++ b/doc/source/applications/img/silx-view-image.png
Binary files differ
diff --git a/doc/source/applications/img/silx-view-table.png b/doc/source/applications/img/silx-view-table.png
new file mode 100644
index 0000000..b71728c
--- /dev/null
+++ b/doc/source/applications/img/silx-view-table.png
Binary files differ
diff --git a/doc/source/applications/index.rst b/doc/source/applications/index.rst
new file mode 100644
index 0000000..2601e2c
--- /dev/null
+++ b/doc/source/applications/index.rst
@@ -0,0 +1,17 @@
+
+Applications documentation
+==========================
+
+While *silx* is first and foremost a Python library to be used by developers,
+a set of command line applications is provided to use some key features of
+the library without knowing anything about Python.
+
+To see the list of all available commands, type the following command in a terminal::
+
+ silx help
+
+.. toctree::
+ :maxdepth: 1
+
+ view
+ convert
diff --git a/doc/source/applications/view.rst b/doc/source/applications/view.rst
new file mode 100644
index 0000000..694f95d
--- /dev/null
+++ b/doc/source/applications/view.rst
@@ -0,0 +1,60 @@
+
+silx view
+=========
+
+Purpose
+-------
+
+The *silx view* command is provided to open data files
+in a graphical user interface. It allows to select a particular
+piece of data or a particular header in structured data formats,
+and to view this data in plot widgets or in simple table views.
+
+
+.. |imgViewImg| image:: img/silx-view-image.png
+ :height: 300px
+ :align: middle
+
+.. |imgViewTable| image:: img/silx-view-table.png
+ :height: 300px
+ :align: middle
+
+.. |imgViewHdf5| image:: img/silx-view-hdf5.png
+ :height: 300px
+ :align: middle
+
+.. list-table::
+ :widths: 1 2
+
+ * - |imgViewImg|
+ - Image view
+ * - |imgViewTable|
+ - Viewing raw data as values in a table
+ * - |imgViewHdf5|
+ - Viewing metadata and HDF5 attributes
+
+
+Usage
+-----
+
+::
+
+ silx view [-h] [--debug] [--use-opengl-plot] [files [files ...]]
+
+
+Options
+-------
+
+ -h, --help Show this help message and exit
+ --debug Set logging system in debug mode
+ --use-opengl-plot Use OpenGL for plots (instead of matplotlib)
+
+
+Examples of usage
+-----------------
+
+::
+
+ silx view 31oct98.dat
+ silx view *.edf
+ silx view myfile.h5
diff --git a/doc/source/conf.py b/doc/source/conf.py
index e724d3c..234e4fa 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -52,6 +52,13 @@ try:
except ImportError:
raise RuntimeError("%s is not on the path. Fix your PYTHONPATH and restart sphinx." % project)
+# Disable deprecation warnings:
+# It avoid to spam documentation logs with deprecation warnings.
+# If we want to generate the documentation of deprecated features it should
+# not make the logs durty.
+from silx.utils.deprecation import depreclog
+depreclog.disabled = 1
+
# Add local sphinx extension directory
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'ext'))
@@ -68,7 +75,9 @@ extensions = [
'sphinx.ext.mathjax',
'sphinx.ext.viewcode',
'sphinx.ext.doctest',
- 'sphinxext-archive'
+ 'sphinxext-archive',
+ 'nbsphinx'
+
]
autodoc_member_order = 'bysource'
diff --git a/doc/source/description/sift.rst b/doc/source/description/sift.rst
index d4a9fad..71ba9c5 100644
--- a/doc/source/description/sift.rst
+++ b/doc/source/description/sift.rst
@@ -1,25 +1,27 @@
General introduction to sift.
=============================
-silx.image.sift, a parallel version of SIFT algorithm
------------------------------------------------------
+silx.opencl.sift, a parallel version of SIFT algorithm
+------------------------------------------------------
SIFT (Scale-Invariant Feature Transform) is an algorithm developed by David Lowe in 1999.
It is a worldwide reference for image alignment and object recognition.
The robustness of this method enables to detect features at different scales,
angles and illumination of a scene.
The implementation available in silx uses OpenCL, meaning that it can run on
-Graphics Processing Units and Central Processing Units as well.
-Interest points are detected in the image, then data structures called
-*descriptors* are built to be characteristic of the scene, so that two different
-images of the same scene have similar descriptors. They are robust to transformations
-like translation, rotation, rescaling and illumination change, which make SIFT
-interesting for image stitching.
+Graphics Processing Units (GPU) as well as on Central Processing Units (CPU).
+Interesting points (keypoints) are detected in the image, then data structures called
+*descriptors*, characteristic of the scene, are extracted so that two different
+images of the same scene exhibit similar descriptors.
+The descriptors are insensitive to transformations like translation, rotation,
+rescaling and illumination changes, making SIFT interesting for image stitching.
+
In the fist stage, descriptors are computed from the input images.
-Then, they are compared to determine the geometric transformation to apply in
-order to align the images.
-silx.image.sift can run on most graphic cards and CPU, making it usable on many setups.
-OpenCL processes are handled from Python with PyOpenCL, a module to access OpenCL parallel computation API.
+Then, they are compared against each other to determine the geometric transformation
+to apply in order to align the images.
+*silx.opencl.sift* can run on most GPU and CPU, offerng a large flexibility.
+OpenCL processes are driven from Python via PyOpenCL, a module to access OpenCL
+the parallel computation API.
Introduction
@@ -27,48 +29,40 @@ Introduction
The European Synchrotron Radiation Facility (ESRF) beamline ID21 developed a
full-field method for X-ray absorption near-edge spectroscopy (XANES).
-Since the flat field images are not acquired simultaneously with the sample
-transmission images, a realignment procedure has to be performed.
-Serial SIFT implementation used to take about 8 seconds per frame, and one stack
-can have up to 500 frames.
-It is a bottleneck in the global process, therefore a parallel version had to be implemented.
-silx.image.sift differs from existing parallel implementations of SIFT in the way
-that the whole process is done on the device, enabling crucial speed-ups.
+Since the flat field images and the sample transmission images are not acquired
+simultaneously, an image realignment procedure has to be performed.
+The sequential SIFT implementation used to take about 8 seconds per frame, and
+one typical stack can have up to 500 frames.
+This is a bottleneck in the global process, hence a parallel version had to be
+implemented.
+*silx.opencl.sift* differs from existing parallel implementations of SIFT in the way
+that the whole process is executed on the device, enabling crucial speed-ups.
-Launching silx.image.sift
--------------------------
+Launching silx.opencl.sift
+--------------------------
-silx.image.sift is written in Python, and handles the OpenCL kernels with PyOpenCL.
+silx.opencl.sift is written in Python, and handles the OpenCL kernels through PyOpenCL.
This enables a simple and efficient access to GPU resources.
-The project is installed as a Python library and can be imported in a script.
+The package is installed as a Python library and can be imported in a script.
-Before image alignment, points of interest (keypoints) have to be detected in each image.
+Prior to image alignment, keypoints have to be detected in each image and their
+descriptors calculated.
The whole process can be launched by several lines of code.
How to use it
.............
-silx.image.sift is installed as part of silx and requires PyOpenCL to be useable.
-It generates a library that can be imported, then used to compute a list of descriptors from an image.
-The image can be in RGB values, but all the process is done on grayscale values.
-One can specify the devicetype, either CPU or GPU.
-
-.. Although being integrated in ESRF EDNA framework for online image alignment,
- and thus mostly used by developers, silx.image.sift provides example scripts.
-
- .. code-block:: python
-
- #TODO: update
- python test/demo.py --type=GPU my_image.jpg
-
-This computes and shows the keypoints on the input image.
-One can also launch silx.image.sift interactively with iPython :
+*silx.opencl.sift* is installed as a part of *silx* and requires PyOpenCL.
+One can also launch silx.opencl.sift interactively with IPython:
+This computes and shows the last keypoint of the input image.
+Color input images are converted to grayscale automatically during the processing.
+One can specify the devicetype, either "CPU" or "GPU".
.. code-block:: python
- from silx.image import sift
+ from silx.opencl import sift
import numpy
import scipy.misc
image_rgb = scipy.misc.imread("my_image.jpg")
@@ -77,44 +71,48 @@ One can also launch silx.image.sift interactively with iPython :
print(kp[-1])
-silx.image.sift files
-.....................
+silx.opencl.sift files
+......................
-The Python sources are in the ``silx.image.sift`` module:
+The Python sources are in the ``silx.opencl.sift`` module:
.. code-block:: python
from silx.image import sift
print(sift.__file__)
-The file ``plan.py`` corresponds to the keypoint extraction and handles the whole process:
-from kernel compilation to descriptors generation as numpy array.
-The OpenCL kernels are distributed as *resources* in the "openCL" folder; they are compiled on the fly.
-Several kernels have multiple implementations, depending the architecture to run on.
+The file ``plan.py`` contains the keypoint extraction code and drives the whole
+process: from kernel compilation to descriptors generation as numpy array.
+The OpenCL kernels are distributed as *resources* in the "openCL" folder; they
+are compiled on the fly.
+Several kernels have multiple implementations, depending on the computer architecture
+to run on.
-The file ``match.py`` does the matching between two lists of keypoints returned by ``plan.py``.
+The file ``match.py`` carries out the matching between two lists of keypoints
+returned by ``plan.py``.
-The file ``alignment.py`` does the image alignment : it computes the keypoints
+The file ``alignment.py`` performes the image alignment : it computes the keypoints
from two images (``plan.py``), then uses the matching result (``match.py``)
to find out the transformation aligning the second image on the first.
-Each of those module contain a class which holds GPU contexts, memory and kernel.
+Each of these modules contains a class which holds GPU contexts, memory and kernel.
They are expensive to instantiate and should be re-used as much as possible.
Overall process
***************
-The different steps of SIFT are handled by ``plan.py``.
-When launched, it automatically choose the best device to run on, unless a device
+The different steps of SIFT are controled by ``plan.py``.
+When launched, it automatically chooses the best device to run on, unless a device
is explicitly provided in the options.
All the OpenCL kernels that can be compiled are built on the fly.
-Buffers are pre-allocated on the device, and all the steps are executed on rge device (GPU).
+Buffers are pre-allocated on the device, and all the steps are executed on the device (GPU).
At each *octave* (scale level), keypoints are returned to the CPU and the buffers are re-used.
-Once the keypoints are computed, the keypoints of two different images can be compared.
+Once computed, the keypoints of two different images can be compared.
This matching is done by ``match.py``.
-It simply takes the descriptors of the two lists of keypoints, and compare them with a L1 distance.
-It returns a vector of *matchings*, i.e couples of similar keypoints.
+It simply takes the descriptors of the two lists of keypoints, and compares them
+using a L1 distance (absolute value).
+It returns a vector of *matching-keypoints*, i.e couples of similar keypoints.
For image alignment, ``alignment.py`` takes the matching vector between two images
and determines the transformation to be done in order to align the second image on the first.
@@ -137,25 +135,25 @@ The keypoints are detected in several steps according to Lowe's paper_ :
keypoints :math:`(x,y,s, \theta)`
* Descriptor computation: a histogram of orientations is built around every keypoint,
then concatenated in a 128-values vector.
- This vector is called *SIFT descriptor*, it is robust to rotation, illumination, translation and scaling.
+ This vector is called *SIFT descriptor*, it is insensitive to rotation, illumination, translation and scaling.
The scale variation is simulated by blurring the image.
-A very blurred image represents a scene seen from a distance, for small details are not visible.
+A very blurred image represents a scene seen from a distance, in which small
+details are no more visible.
Unlike existing parallel versions of SIFT, the entire process is done on the
device to avoid time-consuming transfers between CPU and GPU.
This leads to several tricky parts like the use of atomic instructions, or
-writing different versions of the same kernel to adapt to every platform.
-
+using different versions of the same kernel taylored for different platforms.
Keypoints detection
...................
The image is increasingly blurred to imitate the scale variations.
-This is done by convolving with a gaussian kernel.
-Then, consecutive blurs are subtracted to get *differences of gaussians (DoG)*.
+This is done by convolving the image with a Gaussian kernel.
+Then, consecutive blurs are subtracted to get *differences of Gaussians (DoG)*.
In these DoG, every pixel is tested. Let :math:`(x,y)` be the pixel position in
the current (blurred) image, and :math:`s` its *scale* (that is, the blur factor).
The point :math:`(x,y,s)` is a local maximum in the scale-space if
@@ -170,10 +168,10 @@ The point :math:`(x,y,s)` is a local maximum in the scale-space if
:alt: detection in scale-space
-For these steps, we highly benefit from the parallelism : every pixel is handled
-by a GPU thread.
-Besides, convolution is implemented in the direct space (without Fourier Transform)
-and is quite fast (50 times faster than the convolutions done by the C++ reference
+Those steps highly benefit from the parallelism of the OpenCL: every pixel is processed
+by a different thread.
+Besides, the convolution is implemented in the direct space (without Fourier Transform)
+and is quite fast (50 times faster than the convolutions in the C++ reference
implementation).
@@ -182,27 +180,28 @@ Keypoints refinement
At this stage, many keypoints are not reliable. Low-contrast keypoints are discarded,
and keypoints located on an edge are rejected as well.
-For keypoints located on an edge, principal curvature across the edge is much larger
-than the principal curvature along it. Finding these principal curvatures amounts
+For keypoints located on an edge, the principal curvature across the edge is much larger
+than the principal curvature along it.
+Finding these principal curvatures amounts
to solving for the eigenvalues of the second-order Hessian matrix of the current DoG.
-The ratio of the eigenvalues :math:`r` is compared to a threshold :math:`\dfrac{(r+1)^2}{r} < R`
-with R defined by taking r=10.
-To improve keypoints accuracy, the coordinates are interpolated with a second-order Taylor development.
+To improve keypoints accuracy, the coordinates are interpolated with a second-order
+Taylor series.
.. math::
D \left( \vec{x} + \vec{\delta_x} \right) \simeq D + \dfrac{\partial D}{\partial \vec{x}} \cdot \vec{\delta_x} + \dfrac{1}{2} \left( \vec{\delta_x} \right)^T \cdot \left( H \right) \cdot \vec{\delta_x} \qquad \text{with } H = \dfrac{\partial^2 D}{\partial \vec{x}^2}
-Keypoints that were too far from a *true* (interpolated) extremum are rejected.
+Keypoints too far from a *true* (interpolated) extremum are also rejected.
Orientation assignment
......................
-An orientation has to be assigned to each keypoint so that SIFT descriptors will
-be invariant to rotation. For each blurred version of the image, the gradient
+An orientation has to be assigned to each keypoint, so that SIFT descriptors will
+be invariant to rotation.
+For each blurred version of the image, the gradient
magnitude and orientation are computed.
From the neighborhood of a keypoint, a histogram of orientations is built
(36 bins, 1 bin per 10 degrees).
@@ -218,28 +217,38 @@ keypoint with a different orientation.
The parallel implementation of this step is complex, and the performances strongly
depend on the graphic card the program is running on.
-That is why there are different files for this kernel, adapted for different platforms.
-The file to compile is automatically determined in ``plan.py``.
+That is why different opencl kernels have been written with the same signature,
+but adapted to different platforms.
+The kernel to be used are automatically determined in ``plan.py``.
Descriptor computation
......................
A histogram of orientations is built around every keypoint.
-The neighborhood is divided into 4 regions of 4 sub-regions of 4x4 pixels.
+The neighborhood is divided into 4 regions, each of 4 sub-regions of 4x4 pixels.
In every sub-region, a 8-bin histogram is computed; then, all the histograms are
-concatenated in a 128-values descriptor.
-The histogram is weighted by the gradient magnitudes and the current scale factor,
-so that the descriptor is robust to rotation, illumination, translation and scaling.
-Here again, there are several files adapted to different platforms.
+concatenated in a 128-value descriptor (4x4x8 = 128).
+The concatenated histogram is weighted by the gradient magnitudes and the current
+scale factor, so that the descriptor is invariant to rotation, illumination,
+translation and scaling.
+Here again, there are several kernels adapted to different platforms.
Image matching and alignment
----------------------------
-Matching is also explained in this tutorial, once the keypoints are
+Matching is also explained in this tutorial: once the keypoints are extracted
+from two images, their descriptors (128-value vector) are compared two by two,
+using the L1-norm (sum of absolute value difference).
+For a given keypoint K1 from the image 1, a keypoint K2 from image 2 matches K1
+if the L1-distance between K1-K2 is much shorter than any other pair K1-Kn for
+any other keypoint of image 2.
+Once keypoints are matched, building the afine transformation with the
+least-squares displacement is done using a singular value decomposition of the
+over-complete system of equation.
.. figure:: img/sift_match1.png
:align: center
@@ -251,12 +260,15 @@ Matching is also explained in this tutorial, once the keypoints are
:alt: Another example of image matching for pattern recognition
+
Performances
------------
-The aim of silx.image.sift is to fasten the SIFT keypoint extraction by running it on GPU.
-On big images with many keypoints, it enables a speed-up between 30 and 50 times.
-The following benchmark was done on an Intel Xeon E5-2667 (2.90GHz, 2x6 cores)
+The aim of silx.opencl.sift is to speed-up the SIFT keypoint extraction by
+running it on GPU.
+On big images with many keypoints, this module enables a speed-up between 30 and
+50 times.
+The following benchmark has been carried out on an Intel Xeon E5-2667 (2.90GHz, 2x6 cores)
CPU, and a NVidia Tesla K20m GPU.
@@ -264,7 +276,8 @@ CPU, and a NVidia Tesla K20m GPU.
:align: center
:alt: Benchmark GPU vs CPU
-silx.image.sift can also be run on CPU, even running up to 10 times faster than the C++ implementation.
+*silx.opencl.sift* can also be run on CPU, even running up to 10 times faster
+than the reference C++ implementation.
.. figure:: img/sift_bench_cpu0.png
:align: center
@@ -275,125 +288,134 @@ silx.image.sift can also be run on CPU, even running up to 10 times faster than
SIFT parameters
---------------
-Command line parameters
-.......................
+SiftPlan constructor parameters
+...............................
-When launched from the command line, silx.image.sift can handle several options
+When instanciated, silx.opencl.sift.SiftPlan can take several optionnal parameters
like the device to run on and the *number of pixels per keypoint*.
-By default ``PIX_PER_KP`` is 10, meaning that we gess one keypoint will be found
-for every 10 pixels.
-This is for buffers allocation on the device, as the number of keypoints that
+By default ``PIX_PER_KP`` is 10, meaning that on guesses one keypoint will be found
+every 10 pixels.
+This initial step is setout for buffer allocation on the device, as the number
+of keypoints that
will be found is unknown, and strongly depends of the type of image.
-10 pixels per keypoint is a high estimation, even for images with many features
-like landscapes.
-For example, this 5.8 MPixels image_ gives about 2500 keypoints, which makes
-2270 pixels per keypoints.
+10 pixels per keypoint is a conservative estimation, even for images with many
+features like landscapes.
+For example, a 5.8 MPixels image (of ESRF) yields about 2500 keypoints, hence
+2270 pixels per keypoint.
-.. _image: http://www.lightsources.org/imagebank/image/esr032
-
-If you have big images with few features and the image does not fit on the GPU,
-you can increase ``PIX_PER_KP`` in the command line options in order to
+If one has large images with few features and the image does not fit on the GPU,
+you can increase ``PIX_PER_KP`` in the constructor options in order to
decrease the amount of memory required.
Advanced SIFT parameters
........................
-The file ``param.py`` contains SIFT default parameters, recommended by
-David Lowe in his paper_ or by the authors of the C++ version in ASIFT_.
-You should not modify these values unless you know what you are doing.
-Some parameters require to understand several aspects of the algorithm,
+The file ``param.py`` in the source folder contains SIFT default parameters,
+recommended by David Lowe in his paper_ or by the authors of the C++ version in ASIFT_.
+The user should not modify these values unless one is an advanced SIFT-user.
+Some parameters require the understanding of several aspects of the algorithm,
explained in Lowe's original paper.
.. _ASIFT: http://www.ipol.im/pub/art/2011/my-asift
-``DoubleImSize`` (0 by default) is for the pre-blur factor of the image.
+``DoubleImSize`` (0 by default) stands for the pre-blur factor of the image.
At the beginning, the original image is blurred (*prior-smoothing*) to eliminate noise.
-The standard deviation of the gaussian filter is either ``1.52`` if DoubleImSize is 0, or ``1.25`` if DoubleImSize is 1.
-Setting this parameter to 1 decrease the prior-smoothing factor, the algorithm will certainly find more keypoints but less accurate.
+The standard deviation of the Gaussian filter is either ``1.52`` (if DoubleImSize is 0),
+or ``1.25`` (if DoubleImSize is 1).
+Setting this parameter to 1 decreases the prior-smoothing factor, hence the algorithm
+will certainly find more keypoints but less accurate, as they result from the noise of
+the first octave.
``InitSigma`` (1.6 by default) is the prior-smoothing factor.
-The original image is blurred by a gaussian filter which standard deviation is
+The original image is blurred by a Gaussian filter which standard deviation is
:math:`\sqrt{\text{InitSigma}^2 - c^2}`.
-with ``c == 0.5`` if ``DoubleImSize == 0`` or ``c == 1`` otherwise.
-If the prior-smoothing factor is decreased, the algorithm will certainly find more
-keypoint, but they will be less accurate.
+with ``c = 0.5`` if ``DoubleImSize == 0`` or ``c = 1`` otherwise.
+Once again, if the prior-smoothing factor is decreased, the algorithm will find
+more keypoint in the first octave, located in the noise of the image.
-``BorderDist`` (5 by default) is the minimal distance to borders:
+``BorderDist`` (5 by default) is the minimum distance from a keypoint to the image
+borders:
+Border to create artefacts in the bluring procedure and in the gradiant.
pixels that are less than ``BorderDist`` pixels from the border will be ignored
for the processing.
-If features are likely to be near the borders, decreasing this parameter will
-enable to detect them.
+If the featuring keypoints are near the borders, decreasing this parameter will
+enable onr to detect them but their descriptor are probably less reliable.
``Scales`` (3 by default) is the number of Difference of Gaussians (DoG) that will
-actually be used for keypoints detection.
-In the gaussian pyramid, Scales+3 blurs are made, from which Scales+2 DoGs are computed.
+actually be used for keypoints detection within an octave.
+In the Gaussian hierarchical pyramid, Scales+3 subsequently blured images are
+used to compute Scales+2 DoGs.
The DoGs in the middle are used to detect keypoints in the scale-space.
If ``Scales`` is 3, there will be 6 blurs and 5 DoGs in an octave, and 3 DoGs
will be used for local extrema detection.
-Increasing Scales will make more blurred images in an octave, so SIFT can detect
-a few more strong keypoints.
-However, it will slow down the execution for few additional keypoints.
+Increasing Scales will produce more blurred images in an octave, thus SIFT can detect
+a few more reliable keypoints,
+however, it will slow down the execution for a few additional keypoints.
``PeakThresh`` (255 * 0.04/3.0 by default) is the grayscale threshold for keypoints
refinement.
-To discard low-contrast keypoints, every pixel which grayscale value is below
-this threshold can not become a keypoint.
+To discard low-contrast keypoints, every pixel whose grayscale value is below
+this threshold cannot become a keypoint.
Decreasing this threshold will lead to a larger number of keypoints, which can
be useful for detecting features in low-contrast areas.
``EdgeThresh`` (0.06 by default) and ``EdgeThresh1`` (0.08 by default) are the
-limit ratio of principal curvatures while testing if keypoints are located on an edge.
+limit ratios of principal curvatures while testing if keypoints are located on an edge.
Those points are not reliable for they are sensivite to noise.
For such points, the principal curvature across the edge is much larger than the
principal curvature along it.
Finding these principal curvatures amounts to solving for the eigenvalues of the
second-order Hessian matrix of the current DoG.
-The ratio of the eigenvalues :math:`r` is compared to a threshold :math:`\dfrac{(r+1)^2}{r} < R`
-with R defined by taking r=10, which gives
-:math:`\frac{(r+1)^2}{r} = 12.1`, and 1/12.1 = 0.08.
+The ratio of the curvatures is compared to a threshold.
In the first octave, the value 0.06 is taken instead of 0.08.
-Decreasing these values lead to a larger number of keypoints, but sensivite to
-noise because they are located on edges.
-
-``OriSigma`` (1.5 by default) is related to the radius of gaussian weighting in
-orientation assignment.
-In this stage, for a given keypoint, we look in a region of radius
-:math:`3 \times s \times \text{OriSigma}` with :math:`s` the scale of the current keypoint.
-Increasing it will not lead to increase the number of keypoints found;
-it will take a larger area into account while computing the orientation assignment.
-Thus, the descriptor will be characteristic of a larger neighbourhood.
+Decreasing these values leads to a larger number of keypoints, but more sensivite to
+noise because they are located on edges, hence sliding.
+
+``OriSigma`` (1.5 by default) is related to the radius of Gaussian weighting while
+assessing the orientation for a keypoint.
+At this stage, for a given keypoint, we look into a region of radius
+:math:`3 \times s \times \text{OriSigma}`, :math:`s` being the scale of the
+current keypoint.
+Increasing ``OriSigma`` will not lead to increasing the number of keypoints found;
+it will instead take a larger area into account while determining the orientation
+assignment.
+The descriptor will therefore be characteristic of a larger neighbourhood.
``MatchRatio`` (0.73 by default) is the threshold used for image alignment.
Descriptors are compared with a :math:`L^1`-distance.
-For a given descriptor, if the ratio between the closest-neighbor the
-second-closest-neighbor is below this threshold, then a matching is added to the list.
-Increasing this value leads to a larger number of matchings, certainly less accurate.
+For a given descriptor, if the ratio of distances between the closest-neighbour and the
+second-closest-neighbour is below this threshold, then the closest-neighbour
+matches the descriptor and the matching pair is added to the list.
+Increasing this value leads to a larger number of matching occurences, certainly
+less accurate.
Region of Interest for image alignment
......................................
-When processing the image matching, a region of interest (ROI) can be specified
-on the image.
-It is a binary image which can have any shape.
-For instance, if a sample is centered on the image, the user can select the
-center of the image before processing.
+When performing the image matching, a region of interest (ROI) can be specified
+in the image.
+The ROI is a binary image which can have any shape.
+For instance, if a sample is centred on the image, the user can select the
+centre of the image before processing it.
.. figure:: img/sift_frame_ROI.png
:align: center
:alt: Sample with region of interest
-It both accelerates the processing and avoids to do match keypoints that are not
-on the sample.
+This both accelerates the processing and avoids trying to match keypoints that
+are not on the sample.
References
..........
-- David G. Lowe, Distinctive image features from scale-invariant keypoints, International Journal of Computer Vision, vol. 60, no 2, 2004, p. 91–110 - "http://www.cs.ubc.ca/~lowe/papers/ijcv04.pdf"
+- David G. Lowe, Distinctive image features from scale-invariant keypoints,
+ International Journal of Computer Vision, vol. 60, no 2, 2004, p. 91–110 -
+ "http://www.cs.ubc.ca/~lowe/papers/ijcv04.pdf"
diff --git a/doc/source/index.rst b/doc/source/index.rst
index f1e83b2..0a44784 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -2,16 +2,35 @@ silx |version|
==============
The silx project aims at providing a collection of Python packages to support the
-development of data assessment, reduction and analysis applications at synchrotron
-radiation facilities.
-It aims at providing reading/writing different file formats, data reduction routines
-and a set of Qt widgets to browse and visualize data.
+development of data assessment, reduction and analysis at synchrotron radiation
+facilities.
+It intends to provide reading/writing tools for different file formats, data
+reduction routines and a set of Qt widgets to browse and visualise data.
+Silx can be cited by its DOIs referenced on
+`Zenodo <https://doi.org/10.5281/zenodo.591709>`_.
-Silx can be cited by its DOIs referenced on `Zenodo <https://doi.org/10.5281/zenodo.591709>`_.
+The current version (v0.7) caters for:
+
+* Supporting `HDF5 <https://www.hdfgroup.org/HDF5/>`_,
+ `SPEC <https://certif.com/spec.html>`_ and
+ `FabIO <http://www.silx.org/doc/fabio/dev/getting_started.html#list-of-file-formats-that-fabio-can-read-and-write>`_
+ images file formats.
+* OpenCL-based data processing: image alignment (SIFT),
+ image processing (median filter, histogram),
+ filtered backprojection for tomography
+* Data reduction: histogramming, fitting, median filter
+* A set of Qt widgets, including:
+
+ * 1D and 2D visualization widgets with a set of associated tools using multiple backends (matplotlib or OpenGL)
+ * OpenGL-based widgets to visualize data in 3D (scalar field with isosurface and cut plane, scatter plot)
+ * a unified browser for HDF5, SPEC and image file formats supporting inspection and
+ visualization of n-dimensional datasets.
+
+* a set of applications:
+
+ * a unified viewer (*silx view filename*) for HDF5, SPEC and image file formats
+ * a unified converter to HDF5 format (*silx convert filename*)
-The current version provides reading `SPEC <https://certif.com/spec.html>`_ file
-format, histogramming, fitting, curves and image plot widget with a set of
-associated tools.
.. toctree::
:hidden:
@@ -21,6 +40,7 @@ associated tools.
description/index.rst
tutorials.rst
modules/index.rst
+ applications/index.rst
changelog.rst
license.rst
virtualenv.rst
@@ -40,6 +60,9 @@ associated tools.
:doc:`modules/index`
Documentation of the packages included in *silx*
+:doc:`applications/index`
+ Documentation of the applications provided by *silx*
+
:doc:`modules/gui/gallery`
Widgets gallery and screenshots
diff --git a/doc/source/install.rst b/doc/source/install.rst
index 4d8ba5a..e7bbe1c 100644
--- a/doc/source/install.rst
+++ b/doc/source/install.rst
@@ -2,68 +2,88 @@
Installation steps
==================
-*silx* supports `Python <https://www.python.org/>`_ versions 2.7, 3.4 or later.
-
-To install *silx* on Windows, read the `Windows instructions`_.
-
-To install *silx* on Linux, read the `Linux instructions`_.
-
-To install *silx* on MacOS, read the `MacOS instructions`_.
-
-You will find the simple instructions for each platform at the beginning of each section, followed by more detailed instructions concerning dependencies and alternative installation methods.
-
-For all platform, to install *silx* from the source, see `Installing from source`_.
-
-To install *silx* in a virtualenv, read :ref:`silx-venv`.
+*silx* supports most operating systems, different version of the Python
+programming language.
+While `numpy <http://www.numpy.org/>`_ is the only mandatory dependency,
+graphical widgets require Qt, management of data files requires
+`h5py <http://docs.h5py.org/en/latest/build.html>`_ and
+`fabio <https://github.com/silx-kit/fabio>`_, and high performance data-analysis
+code on GPU requires `pyopencl <https://mathema.tician.de/software/pyopencl/>`_.
+
+This table summarized the the support matrix of silx v0.7:
+
++------------+--------------+---------------------+
+| System | Python vers. | Qt and its bindings |
++------------+--------------+---------------------+
+| `Windows`_ | 3.5, 3.6 | PyQt5.6+ |
++------------+--------------+---------------------+
+| `MacOS`_ | 2.7, 3.5-3.6 | PyQt5.6+ |
++------------+--------------+---------------------+
+| `Linux`_ | 2.7, 3.4-3.6 | PyQt4.8+, PyQt5.3+ |
++------------+--------------+---------------------+
+
+For all platform, you can install *silx* from the source, see `Installing from source`_.
+
+To install *silx* in a `Virtual Environment`_, there is short version here-after
+and a `longer description :ref:`silx-venv`.
Dependencies
------------
-The only mandatory dependency of *silx* is `numpy <http://www.numpy.org/>`_.
-
-Yet, a set of `Optional dependencies`_ is necessary to enable all *silx* features.
-
-Optional dependencies
-+++++++++++++++++++++
-
The GUI widgets depend on the following extra packages:
-* A Qt binding: either `PyQt5, PyQt4 <https://riverbankcomputing.com/software/pyqt/intro>`_ or `PySide <https://pypi.python.org/pypi/PySide/>`_
+* A Qt binding: either `PyQt5, PyQt4 <https://riverbankcomputing.com/software/pyqt/intro>`_,
+ `PySide <https://pypi.python.org/pypi/PySide/>`_, or `PySide2 <https://wiki.qt.io/PySide2>`_
* `matplotlib <http://matplotlib.org/>`_
* `PyOpenGL <http://pyopengl.sourceforge.net/>`_
-* `IPython <https://ipython.org/>`_ and `qt_console <https://pypi.python.org/pypi/qtconsole>`_ for the ``silx.gui.console`` widget.
+* `IPython <https://ipython.org/>`_ and `qt_console <https://pypi.python.org/pypi/qtconsole>`_
+ for the ``silx.gui.console`` widget.
Tools for reading and writing files depend on the following packages:
* `h5py <http://docs.h5py.org/en/latest/build.html>`_ for HDF5 files
* `fabio <https://github.com/silx-kit/fabio>`_ for multiple image formats
-*silx.opencl* and *silx.image.sift* further depends on OpenCL and the following packages to :
+*silx.opencl* further depends on OpenCL and the following packages to :
* `pyopencl <https://mathema.tician.de/software/pyopencl/>`_
* `Mako <http://www.makotemplates.org/>`_
+The complete list of dependencies with the minimal version is described in the
+`requirement.txt <https://github.com/silx-kit/silx/blob/0.7/requirements.txt>`_
+at the top level of the source package.
+
Build dependencies
++++++++++++++++++
-In addition to run-time dependencies, building *silx* requires a C/C++ compiler, `numpy <http://www.numpy.org/>`_ and `cython <http://cython.org>`_ (optional).
+In addition to run-time dependencies, building *silx* requires a C/C++ compiler,
+`numpy <http://www.numpy.org/>`_ and `cython <http://cython.org>`_ (optional).
-On Windows it is recommended to use Python 3.5, because with previous versions of Python, it might be difficult to compile the extensions.
+On Windows it is recommended to use Python 3.5, because with previous versions
+of Python, it might be difficult to compile extensions (i.e. binary modules).
-This project uses cython to generate C files.
-Cython is not mandatory to build *silx* and is only needed when developing binary modules.
-If using cython, *silx* requires at least version 0.18 (with memory-view support).
+This project uses Cython (version > 0.21) to generate C files.
+Cython is now mandatory to build *silx* from the development branch and is only
+needed when compiling binary modules.
+The complete list of dependencies for building the package, including its
+documentation, is described in the
+`requirement-dev.txt <https://github.com/silx-kit/silx/blob/0.7/requirements-dev.txt>`_
+at the top level of the source package.
-Linux instructions
-------------------
-If NumPy is not installed on your system, you need to install it first
-either with the package manager of your system (recommended way) or with pip::
- pip install numpy --user
+Linux
+-----
-On Linux, you can install *silx* in your home directory::
+If NumPy is not installed on your system, you need to install it first,
+preferably with the package manager of your system.
+If you cannot use the package manager of your system (which requires the root
+access), please refer to the `Virtual Environment`_ procedure.
+
+On Linux, you can install *silx* in your home directory
+
+.. code-block:: bash
pip install silx --user
@@ -75,46 +95,45 @@ On Linux, you can install *silx* in your home directory::
This installs *silx* without the optional dependencies.
-To install *silx* on Debian 8, see `Installing a Debian package`_.
-This method requires **sudo** privileges, but has the benefit of installing dependencies in a simple way.
-
-CentOS 7 rpm packages are provided by Max IV at the following url: http://pubrepo.maxiv.lu.se/rpm/el7/x86_64/
+To install *silx* on Debian or Ubuntu systems, see `Installing a Debian package`_.
+This method requires **sudo** privileges, but has the benefit of installing
+dependencies in a simple way.
-Fedora 23 rpm packages are provided by Max IV at http://pubrepo.maxiv.lu.se/rpm/fc23/x86_64/
+`CentOS 7 RPM packages <http://pubrepo.maxiv.lu.se/rpm/el7/x86_64/>`_ and
+`Fedora 23 rpm packages <http://pubrepo.maxiv.lu.se/rpm/fc23/x86_64/>`_
+are provided by the Max IV institute at Lund, Sweden.
-An Arch Linux (AUR) package is also available: https://aur.archlinux.org/packages/python-silx
+An `Arch Linux (AUR) package <https://aur.archlinux.org/packages/python-silx>`_
+is provided by Leonid Bloch.
You can also choose to compile and install *silx* from it's sources:
see `Installing from source`_.
.. note::
- The Debian packages `python-silx` and `python3-silx` will not install executables (`silx view`, `silx convert` ...).
- So in order to access those applications you should use: `python* -m silx appX`.
- For example to open the viewer:
-
- .. code-block:: python
-
- python -m silx view
+ The Debian packages `python-silx` and `python3-silx` will not install executables
+ (`silx view`, `silx convert` ...). Please install the silx package.
Installing a Debian package
+++++++++++++++++++++++++++
Debian 8 (Jessie) packages are available on http://www.silx.org/pub/debian/ for amd64 computers.
-To install it, you need to download this file::
+To install it, you need to download this file
+
+.. code-block:: bash
http://www.silx.org/pub/debian/silx.list
and copy it into the /etc/apt/source.list.d folder.
Then run ``apt-get update`` and ``apt-get install python-silx``
-::
+.. code-block:: bash
wget http://www.silx.org/pub/debian/silx.list
sudo cp silx.list /etc/apt/sources.list.d
sudo apt-get update
- sudo apt-get install python-silx python3-silx
+ sudo apt-get install python-silx python3-silx silx
.. note::
@@ -127,12 +146,55 @@ If the Pin-number of silx.org is too low compared to other sources:
download http://www.silx.org/pub/debian/silx.pref into /etc/apt/preferences.d
and start the update/install procedure again.
+Virtual Environment
+-------------------
+
+Virtual environments are self-contained directory tree that contains a Python
+installation for a particular version of Python, plus a number of additional
+packages.
+They do require administrator privileges, nor *root* access.
+
+To create a virtual environment, decide upon a directory where you want to place
+it (for example *myenv*), and run the *venv* module as a script with the directory path:
+
+.. code-block:: bash
-Windows instructions
---------------------
+ python3 -m venv myenv
-The simple way of installing the *silx* library on Windows is to type following
-commands in a command prompt::
+This will create the *myenv* directory if it doesn’t exist, and also create
+directories inside it containing a copy of the Python interpreter, the standard
+library, and various supporting files.
+
+Once you’ve created a virtual environment, you may activate it.
+
+On Windows, run:
+
+.. code-block:: bash
+
+ myenv\\Scripts\\activate.bat
+
+On Unix or MacOS, run:
+
+.. code-block:: bash
+
+ source myenv/bin/activate
+
+You can install, upgrade, and remove packages using a program called *pip* within
+your virtual environment.
+
+.. code-block:: bash
+
+ pip install numpy
+ pip install -r https://github.com/silx-kit/silx/raw/0.7/requirements.txt
+ pip install silx
+
+Windows
+-------
+
+The simple way of installing the *silx* library on Windows is to type the following
+commands in a command prompt:
+
+.. code-block:: bash
pip install silx
@@ -149,32 +211,26 @@ read the following sections.
Installing Python
+++++++++++++++++
-Download and install Python from `python.org <https://www.python.org/downloads/>`_.
-
-We recommend that you install the 64bits version of Python, which is not the default version suggested on the Python website. The 32bits version is limited to 2 GB of memory, and also we don't provide a silx wheel for it. This means that you would have to install silx from its sources, which requires you to install a C compiler first.
-
-We also encourage you to use Python 3.5 or newer.
-
-Configure Python as explained on `docs.python.org
-<https://docs.python.org/3/using/windows.html#configuring-python>`_ to add
-the python installation directory to your PATH environment variable.
+Download and install Python from `python.org <https://www.python.org/downloads/>`_.
-Alternative Scientific Python stacks exists, such as `WinPython <http://winpython.github.io/>`_.
-They all offer most of the scientific packages already installed which makes the installation of dependencies much easier.
+We recommend that you install the 64bits version of Python, which is not the
+default version suggested on the Python website.
+The 32bits version is limited to 2 GB of memory, and also we don't provide a
+binary wheel for it.
+This means that you would have to install *silx* from its sources, which requires
+you to install a C compiler first.
-Installing pip
-++++++++++++++
+We also encourage you to use Python 3.5 or newer, former versions are no more
+officially supported.
-Recent version of Python (`> 2.7.9` or `> 3.4`) provide pip by default.
-
-If you have an older version of Python and you do not wish to upgrade it,
-you can install pip yourself.
-
-Download the script https://bootstrap.pypa.io/get-pip.py and execute it in a
-command prompt::
-
- python get-pip.py
+Configure Python as explained on
+`docs.python.org <https://docs.python.org/3/using/windows.html#configuring-python>`_
+to add the python installation directory to your PATH environment variable.
+Alternative Scientific Python stacks exists, such as
+`WinPython <http://winpython.github.io/>`_ or `Anaconda <https://www.anaconda.com/download/#windows>`_.
+They all offer most of the scientific packages already installed which makes the
+installation of dependencies much easier.
Using pip
+++++++++
@@ -191,27 +247,11 @@ prompt.
Installing dependencies
+++++++++++++++++++++++
-Some of the dependencies may be simply installed with pip::
-
- pip install numpy
- pip install matplotlib
- pip install PyOpenGL
- pip install PyQt5
- pip install PySide
-
-Regarding the `h5py` and `PyQt4` modules, you can find the wheels at
-Christoph Gohlke's repository:
-
-http://www.lfd.uci.edu/~gohlke/pythonlibs/
+All dependencies may be simply installed with pip::
-Download the appropriate `.whl` file for your system and install them with pip::
+.. code-block:: bash
- pip install h5py*.whl
- pip install PyQt4*.whl
-
-`PyQt5` can be downloaded as a binary package for `Python 3.5` on the
-`Riverbank Computing website <https://www.riverbankcomputing.com/software/pyqt/download5>`_.
-This package contains everything needed for `PyQt5`, including `Qt`.
+ pip install -r https://github.com/silx-kit/silx/raw/0.7/requirements.txt
Installing *silx*
@@ -219,52 +259,60 @@ Installing *silx*
Provided numpy is installed, you can install *silx* with::
- pip install silx
-
+.. code-block:: bash
-MacOS instructions
-------------------
+ pip install silx
-The easy way to install *silx* on MacOS, is::
- pip install silx
+MacOS
+-----
-This should work without issues, as binary wheels of *silx* are provided on
-PyPi.
+While Apple ships Python 2.7 by default on their operating systems, we recommand
+using Python 3.5 or newer to ease the installation of the Qt library.
+This can simply be performed by:
-Wheels are available for *h5py* on MacOS, so you can install it with::
+.. code-block:: bash
- pip install h5py
+ pip install -r https://github.com/silx-kit/silx/raw/0.7/requirements.txt
-If at the time of your installation a new version of *h5py* has been released but
-the corresponding MacOS wheel is not ready, you should install the latest version including
-a wheel: ``pip install h5py==2.6.0``
+Then install *silx* with:
-A PyQt5 wheel is now available for Python 3.5 on MacOS: https://pypi.python.org/simple/pyqt5/.
-Download it and install it with::
+.. code-block:: bash
- pip install PyQt5-5.6-cp35-cp35m-macosx_10_6_intel.whl
+ pip install silx
-This should work for all versions of MacOS from 10.6.
+This should work without issues, as binary wheels of *silx* are provided on
+PyPi.
Installing from source
----------------------
-Building *silx* from the source requires some `Build dependencies`_.
+Building *silx* from the source requires some `Build dependencies`_ which may be
+installed using:
+
+.. code-block:: bash
+
+ pip install -r https://github.com/silx-kit/silx/raw/0.7/requirements-dev.txt
+
Building from source
++++++++++++++++++++
-Source package of *silx* releases can be downloaded from `the pypi project page <https://pypi.python.org/pypi/silx>`_.
+Source package of *silx* releases can be downloaded from
+`the pypi project page <https://pypi.python.org/pypi/silx>`_.
After downloading the `silx-x.y.z.tar.gz` archive, extract its content::
tar xzvf silx-x.y.z.tar.gz
-Alternatively, you can get the latest source code from the master branch of the `git repository <https://github.com/silx-kit/silx>`_: https://github.com/silx-kit/silx/archive/master.zip
+Alternatively, you can get the latest source code from the master branch of the
+`git repository <https://github.com/silx-kit/silx/archive/master.zip>`_: https://github.com/silx-kit/silx
+
+You can now build and install *silx* from its sources:
+
-You can now build and install *silx* from its sources::
+.. code-block:: bash
cd silx-x.y.z
pip uninstall -y silx
@@ -278,21 +326,21 @@ There are specific issues related to MacOSX. If you get this error::
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1335: ordinal not in range(128)
This is related to the two environment variable LC_ALL and LANG not defined (or wrongly defined to UTF-8).
-To set the environment variable, type on the command line::
+To set the environment variable, type on the command line:
- export LC_ALL=en_US.UTF-8
- export LANG=en_US.UTF-8
+.. code-block:: bash
+
+ export LC_ALL=en_US.UTF-8
+ export LANG=en_US.UTF-8
Advanced build options
++++++++++++++++++++++
-In case you want more control over the build procedure, the build command is::
+In case you want more control over the build procedure, the build command is:
- python setup.py build
+.. code-block:: bash
-After this build, you will still need to install *silx* to be able to use it::
-
- python setup.py install [--user]
+ python setup.py build
There are few advanced options to ``setup.py build``:
@@ -301,7 +349,22 @@ There are few advanced options to ``setup.py build``:
* ``--no-openmp``: Recompiles the Cython code without OpenMP support (default for MacOSX).
* ``--openmp``: Recompiles the Cython code with OpenMP support (default for Windows and Linux).
-To build the documentation (this requires `Sphinx <http://www.sphinx-doc.org/>`_), run::
+Run the test suite of silx (may take a couple of minutes):
+
+.. code-block:: bash
+
+ python run_tests.py
+
+Package the built into a wheel and install it:
+
+.. code-block:: bash
+
+ python setup.py bdist_wheel
+ pip install dist/silx*.whl
+
+To build the documentation, using `Sphinx <http://www.sphinx-doc.org/>`_:
+
+.. code-block:: bash
python setup.py build build_doc
@@ -311,5 +374,14 @@ Testing
To run the tests of an installed version of *silx*, from the python interpreter, run:
->>> import silx.test
->>> silx.test.run_tests()
+.. code-block:: python
+
+ import silx.test
+ silx.test.run_tests()
+
+To run the test suite of a development version, use the *run_tests.py* script at
+the root of the source project.
+
+.. code-block:: bash
+
+ python ./run_tests.py
diff --git a/doc/source/modules/gui/dialog/abstractdatafiledialog.rst b/doc/source/modules/gui/dialog/abstractdatafiledialog.rst
new file mode 100644
index 0000000..ac395ae
--- /dev/null
+++ b/doc/source/modules/gui/dialog/abstractdatafiledialog.rst
@@ -0,0 +1,13 @@
+
+.. currentmodule:: silx.gui.dialog
+
+:mod:`AbstractDataFileDialog`
+=============================
+
+.. automodule:: silx.gui.dialog.AbstractDataFileDialog
+
+.. currentmodule:: silx.gui.dialog.AbstractDataFileDialog
+
+.. autoclass:: AbstractDataFileDialog
+ :members:
+ :show-inheritance:
diff --git a/doc/source/modules/gui/dialog/datafiledialog.rst b/doc/source/modules/gui/dialog/datafiledialog.rst
new file mode 100644
index 0000000..d815a0b
--- /dev/null
+++ b/doc/source/modules/gui/dialog/datafiledialog.rst
@@ -0,0 +1,13 @@
+
+.. currentmodule:: silx.gui.dialog
+
+:mod:`DataFileDialog`
+=====================
+
+.. automodule:: silx.gui.dialog.DataFileDialog
+
+.. currentmodule:: silx.gui.dialog.DataFileDialog
+
+.. autoclass:: DataFileDialog
+ :members:
+ :show-inheritance:
diff --git a/doc/source/modules/gui/dialog/imagefiledialog.rst b/doc/source/modules/gui/dialog/imagefiledialog.rst
new file mode 100644
index 0000000..cebd6e7
--- /dev/null
+++ b/doc/source/modules/gui/dialog/imagefiledialog.rst
@@ -0,0 +1,13 @@
+
+.. currentmodule:: silx.gui.dialog
+
+:mod:`ImageFileDialog`
+======================
+
+.. automodule:: silx.gui.dialog.ImageFileDialog
+
+.. currentmodule:: silx.gui.dialog.ImageFileDialog
+
+.. autoclass:: ImageFileDialog
+ :members:
+ :show-inheritance:
diff --git a/doc/source/modules/gui/dialog/img/datafiledialog.png b/doc/source/modules/gui/dialog/img/datafiledialog.png
new file mode 100644
index 0000000..f7c7fd5
--- /dev/null
+++ b/doc/source/modules/gui/dialog/img/datafiledialog.png
Binary files differ
diff --git a/doc/source/modules/gui/dialog/img/imagefiledialog_edf.png b/doc/source/modules/gui/dialog/img/imagefiledialog_edf.png
new file mode 100644
index 0000000..ed715b4
--- /dev/null
+++ b/doc/source/modules/gui/dialog/img/imagefiledialog_edf.png
Binary files differ
diff --git a/doc/source/modules/gui/dialog/img/imagefiledialog_h5.png b/doc/source/modules/gui/dialog/img/imagefiledialog_h5.png
new file mode 100644
index 0000000..33da51e
--- /dev/null
+++ b/doc/source/modules/gui/dialog/img/imagefiledialog_h5.png
Binary files differ
diff --git a/doc/source/modules/gui/dialog/index.rst b/doc/source/modules/gui/dialog/index.rst
new file mode 100644
index 0000000..a13ad31
--- /dev/null
+++ b/doc/source/modules/gui/dialog/index.rst
@@ -0,0 +1,33 @@
+
+.. currentmodule:: silx.gui
+
+:mod:`dialog`: Dialog widgets
+-----------------------------
+
+.. automodule:: silx.gui.dialog
+
+Snapshot of the widgets:
+
+
+.. |imgImageFileDialog| image:: ./img/imagefiledialog_h5.png
+ :height: 150px
+ :align: middle
+
+.. |imgDataFileDialog| image:: ./img/datafiledialog.png
+ :height: 150px
+ :align: middle
+
+======================== ==========================
+|imgImageFileDialog| |imgDataFileDialog|
+:class:`ImageFileDialog` :class:`DataFileDialog`
+======================== ==========================
+
+Public modules:
+
+.. toctree::
+ :maxdepth: 2
+
+ imagefiledialog.rst
+ datafiledialog.rst
+ abstractdatafiledialog.rst
+
diff --git a/doc/source/modules/gui/gallery.rst b/doc/source/modules/gui/gallery.rst
index 4ae83d6..40d8648 100644
--- a/doc/source/modules/gui/gallery.rst
+++ b/doc/source/modules/gui/gallery.rst
@@ -61,6 +61,29 @@ Widgets gallery
n-dimensional array, by fixing the index on some of the dimensions.
+:mod:`silx.gui.dialog` Widgets
+++++++++++++++++++++++++++++++
+
+.. currentmodule:: silx.gui.dialog
+
+.. list-table::
+ :widths: 1 4
+ :header-rows: 1
+
+ * - Widget
+ - Description
+ * - .. image:: dialog/img/datafiledialog.png
+ :height: 150px
+ :align: center
+ - :class:`DataFileDialog` is a dialog that allow users to select
+ any datasets or groups from an HDF5-like file.
+ * - .. image:: dialog/img/imagefiledialog_h5.png
+ :height: 150px
+ :align: center
+ - :class:`ImageFileDialog` is a dialog that allow users to select
+ an image from an HDF5-like file.
+
+
:mod:`silx.gui.fit` Widgets
+++++++++++++++++++++++++++
@@ -195,12 +218,24 @@ Additional widgets:
* - Widget
- Description
+ * - .. image:: plot3d/img/SceneWindow.png
+ :height: 150px
+ :align: center
+ - :class:`SceneWindow` is a :class:`QMainWindow` embedding a 3D data visualization :class:`SceneWidget`
+ and associated toolbars.
+ It can display 2D images, 2D scatter data, 3D scatter data and 3D volumes with different visualizations.
+ See ``plot3dSceneWindow.py`` in :ref:`plot3d-sample-code`.
+ * - .. image:: plot3d/img/SceneWidget.png
+ :height: 150px
+ :align: center
+ - :class:`SceneWidget` is a :class:`Plot3DWidget` providing a 3D scene for visualizing different kind of data.
+ It can display 2D images, 2D scatter data, 3D scatter data and 3D volumes with different visualizations.
+ See ``plot3dSceneWindow.py`` in :ref:`plot3d-sample-code`.
* - .. image:: plot3d/img/ScalarFieldView.png
:height: 150px
:align: center
- :class:`ScalarFieldView` is a :class:`Plot3DWindow` dedicated to display 3D scalar field.
It can display iso-surfaces and an interactive cutting plane.
- Sample code: :doc:`plot3d/viewer3dvolume_example`.
* - .. image:: plot3d/img/Plot3DWindow.png
:height: 150px
:align: center
@@ -216,7 +251,7 @@ Additional widgets:
:align: center
- :class:`SFViewParamTree` is a :class:`QTreeView` widget that can be attached to a :class:`ScalarFieldView`.
It displays current parameters of the :class:`ScalarFieldView` and allows to modify it.
- Sample code: :doc:`plot3d/viewer3dvolume_example`.
+ See :ref:`plot3d-sample-code`.
:mod:`silx.gui.widgets` Widgets
diff --git a/doc/source/modules/gui/icons.rst b/doc/source/modules/gui/icons.rst
index a1cd3d7..48fe95c 100644
--- a/doc/source/modules/gui/icons.rst
+++ b/doc/source/modules/gui/icons.rst
@@ -41,6 +41,12 @@ Available icons
- close
* - |colorbar|
- colorbar
+ * - |colormap-histogram|
+ - colormap-histogram
+ * - |colormap-none|
+ - colormap-none
+ * - |colormap-range|
+ - colormap-range
* - |colormap|
- colormap
* - |crop|
@@ -143,6 +149,8 @@ Available icons
- math-sigma
* - |math-smooth|
- math-smooth
+ * - |math-square-amplitude|
+ - math-square-amplitude
* - |math-substract|
- math-substract
* - |math-swap-sign|
@@ -281,6 +289,9 @@ Available icons
.. |clipboard| image:: ../../../../silx/resources/gui/icons/clipboard.png
.. |close| image:: ../../../../silx/resources/gui/icons/close.png
.. |colorbar| image:: ../../../../silx/resources/gui/icons/colorbar.png
+.. |colormap-histogram| image:: ../../../../silx/resources/gui/icons/colormap-histogram.png
+.. |colormap-none| image:: ../../../../silx/resources/gui/icons/colormap-none.png
+.. |colormap-range| image:: ../../../../silx/resources/gui/icons/colormap-range.png
.. |colormap| image:: ../../../../silx/resources/gui/icons/colormap.png
.. |crop| image:: ../../../../silx/resources/gui/icons/crop.png
.. |crosshair| image:: ../../../../silx/resources/gui/icons/crosshair.png
@@ -332,6 +343,7 @@ Available icons
.. |math-real| image:: ../../../../silx/resources/gui/icons/math-real.png
.. |math-sigma| image:: ../../../../silx/resources/gui/icons/math-sigma.png
.. |math-smooth| image:: ../../../../silx/resources/gui/icons/math-smooth.png
+.. |math-square-amplitude| image:: ../../../../silx/resources/gui/icons/math-square-amplitude.png
.. |math-substract| image:: ../../../../silx/resources/gui/icons/math-substract.png
.. |math-swap-sign| image:: ../../../../silx/resources/gui/icons/math-swap-sign.png
.. |math-ymin-to-zero| image:: ../../../../silx/resources/gui/icons/math-ymin-to-zero.png
diff --git a/doc/source/modules/gui/index.rst b/doc/source/modules/gui/index.rst
index 0b7f433..1f7ee4a 100644
--- a/doc/source/modules/gui/index.rst
+++ b/doc/source/modules/gui/index.rst
@@ -13,6 +13,7 @@ The ``silx.gui`` package provides a set of PyQt widgets.
console.rst
data/index.rst
fit/index.rst
+ dialog/index.rst
hdf5/index.rst
icons.rst
plot/index.rst
diff --git a/doc/source/modules/gui/plot/actions/examples.rst b/doc/source/modules/gui/plot/actions/examples.rst
index 125e9c5..f4679ba 100644
--- a/doc/source/modules/gui/plot/actions/examples.rst
+++ b/doc/source/modules/gui/plot/actions/examples.rst
@@ -3,29 +3,29 @@
Adding custom plot actions
==========================
-A :class:`PlotWindow` defines a number of standard plot actions that can be executed
+:class:`PlotWindow` defines a number of standard plot actions that can be executed
by clicking on toolbar icons.
Developers can design additional plot actions to be added as toolbar icons or as menu entries,
to be added to a :class:`PlotWindow` or to design their own plot window based on
:class:`PlotWidget`.
-This documentation pages provides examples on how to do this.
+This documentation pages provide examples on how to do this.
Simple example: Shift a curve
-----------------------------
-The following script is a simplistic example to show the basic required steps:
+The following script is a simplistic example to show the required basic steps:
- create a new class inheriting from :class:`silx.gui.plot.actions.PlotAction`
- define basic parameters such as the icon, the tooltip...
- - write a method that will be triggered by the action
- - initialize the new plot action by passing a reference to a plot window
- - add the action to a toolbar or a menu
+ - write a method that will be triggered by the plot action
+ - initialise the new plot action by passing a reference to a plot window
+ - add the plot action to a toolbar or a menu
The method implemented in this action interacts with the plot in a basic way. It gets the active curve,
-then it creates a new data array based on the curve data, and finally it replaces the original curve
-with a new one using the modified data array.
+then it creates a new data array based on the curve points, and finally it replaces the original curve
+by a new one using the modified data array.
.. literalinclude:: ../../../../../../examples/shiftPlotAction.py
:lines: 36-
@@ -47,23 +47,23 @@ with a new one using the modified data array.
- After triggering the action 3 times, the selected triangle shaped curve
is shifted up by 3 units
-Advanced example: Display amplitude spectrum
---------------------------------------------
+Advanced example: Display an amplitude spectrum
+-----------------------------------------------
-This more advanced example shows additional ways of interacting with the plot, by changing
-labels, storing additional data array along with the curve data.
+This more advanced example (see `figure below`_) shows additional ways of interacting with the plot, by changing
+labels, storing additional data arrays along with the curve coordinates.
This action is *checkable*, meaning that is has two states. When clicking the toolbar icon
-or the menu item, it remains in a *pushed* state until it is clicked again.
+or the menu item, this remains in a *pushed* state until it is clicked again.
In one state (*un-checked*), the original data is displayed. In the other state, the amplitude
spectrum of the original signal is displayed. When the state is changed, the triggered action
computes either the Fast Fourier Transform (FFT), or the reverse FFT.
-This example also illustrates how to store additional data, along with a curve.
-The FFT computation returns complex values, but we want to display real data, so we compute
-the amplitude spectrum. However, the inverse FFT requires the complete FFT data as input.
-We are therefore required to store the complex array of FFT data as curve metadata,
+This example also illustrates how to store additional data along with a curve.
+The FFT computation returns complex values, but you want to display real data, so you compute
+the spectrum of amplitudes. However, the inverse FFT requires the complete FFT data as input.
+You are therefore required to store the complex array of FFT data as curve metadata,
in order to be able to reverse the process when the action is unchecked.
.. literalinclude:: ../../../../../../examples/fftPlotAction.py
@@ -77,17 +77,19 @@ in order to be able to reverse the process when the action is unchecked.
:height: 300px
:align: middle
+.. _`figure below`:
+
.. list-table::
:widths: 1 2
* - |imgFftAction0|
- - Original signals (zoom applied). In red, a cosine wave at 7 Hz.
+ - Original signals (zoomed in). In red, a cosine wave at 7 Hz.
In black, a sum of sines with frequencies of 3, 20 and 42 Hz.
In green, a square wave with a fundamental frequency of 0.5 Hz
- (wavelength of 2 seconds).
+ (period of 2 seconds).
* - |imgFftAction1|
- - Amplitude spectra (zoom applied), with peaks visible at
+ - Amplitude spectra (zoomed in), with peaks visible at
the expected frequencies of 3, 7, 20 and 42 Hz for the sine and cosine
- signals. In green, we see the complete series of peaks related to the square wave,
+ signals, respectively. In green, one sees the complete series of peaks related to the square wave,
with a fundamental frequency at 0.5 Hz and harmonic frequencies at every
- odd multiple of the fundamental.
+ odd multiple of the fundamental frequency.
diff --git a/doc/source/modules/gui/plot/actions/index.rst b/doc/source/modules/gui/plot/actions/index.rst
index f95b1f8..b8b345b 100644
--- a/doc/source/modules/gui/plot/actions/index.rst
+++ b/doc/source/modules/gui/plot/actions/index.rst
@@ -1,14 +1,8 @@
-.. currentmodule:: silx.gui.plot
-:mod:`actions`: Actions for PlotWidget
-===========================================
+:mod:`~silx.gui.plot.actions`: Actions for PlotWidget
+=====================================================
-.. currentmodule:: silx.gui.plot.actions
-
-The :class:`PlotAction` is a base class used to define plot actions.
-
-Plot actions serve to add menu items or toolbar items that are associated with a method
-that can interact with the associated :class:`.PlotWidget`.
+.. automodule:: silx.gui.plot.actions
For an introduction to creating custom plot actions, see :doc:`examples`.
diff --git a/doc/source/modules/gui/plot/getting_started.rst b/doc/source/modules/gui/plot/getting_started.rst
index 484d3f7..bfea8f2 100644
--- a/doc/source/modules/gui/plot/getting_started.rst
+++ b/doc/source/modules/gui/plot/getting_started.rst
@@ -1,3 +1,7 @@
+
+.. role:: python(code)
+ :language: python
+
.. currentmodule:: silx.gui
Getting started with plot widgets
@@ -5,30 +9,40 @@ Getting started with plot widgets
This introduction to :mod:`silx.gui.plot` covers the following topics:
-- `Use silx.gui.plot from the console`_
+- `Use silx.gui.plot from (I)Python console`_
- `Use silx.gui.plot from a script`_
- `Plot curves in a widget`_
- `Plot images in a widget`_
-- `Control plot axes`_
+- `Configure plot axes`_
For a complete description of the API, see :mod:`silx.gui.plot`.
-Use :mod:`silx.gui.plot` from the console
------------------------------------------
+Use :mod:`silx.gui.plot` from (I)Python console
+-----------------------------------------------
+
+The simplest way is to import the :mod:`silx.sx` module:
+
+>>> from silx import sx
-From IPython
-++++++++++++
+The :mod:`silx.sx` module initialises Qt and provides access to :mod:`silx.gui.plot` widgets and extra plot functions.
-To run :mod:`silx.gui.plot` widgets from `IPython <http://ipython.org/>`_, IPython must be set to use Qt (and in case of using PyQt4 and Python 2.7, PyQt must be set ti use API version 2, see Explanation_ below).
+.. note:: The :mod:`silx.sx` module does NOT initialise Qt and does NOT expose silx widget in a notebook.
-As *silx* is performing some configuration of the Qt binding and `matplotlib <http://matplotlib.org/>`_, the safest way to use *silx* from IPython is to import :mod:`silx.gui.plot` first and then run either `%gui <http://ipython.org/ipython-doc/stable/interactive/magics.html#magic-gui>`_ qt or `%pylab <http://ipython.org/ipython-doc/stable/interactive/magics.html#magic-pylab>`_ qt::
+Compatibility with IPython
+++++++++++++++++++++++++++
+
+To run :mod:`silx.gui` widgets from `IPython <http://ipython.org/>`_,
+IPython must be set to use Qt (and in case of using PyQt4 and Python 2.7,
+PyQt must be set to use API version 2, see note below for explanation).
+
+As *silx* is configuring the Qt binding and `matplotlib <http://matplotlib.org/>`_, the safest way to use *silx* from IPython is to import :mod:`silx.gui.plot` first and then run either `%gui <http://ipython.org/ipython-doc/stable/interactive/magics.html#magic-gui>`_ qt or `%pylab <http://ipython.org/ipython-doc/stable/interactive/magics.html#magic-pylab>`_ qt::
In [1]: from silx.gui.plot import *
In [2]: %pylab qt
Alternatively, when using Python 2.7 and PyQt4, you can start IPython with the ``QT_API`` environment variable set to ``pyqt``.
-On Linux and MacOS X, run::
+On Linux and MacOS X, run from the command line::
QT_API=pyqt ipython
@@ -37,100 +51,33 @@ On Windows, run from the command line::
set QT_API=pyqt&&ipython
-Explanation
-...........
-
-PyQt4 used from Python 2.x provides 2 incompatible versions of QString and QVariant:
-
-- version 1, the legacy which is the default, and
-- version 2, a more pythonic one, which is the only one supported by *silx*.
+.. note:: PyQt4 used from Python 2.x provides 2 incompatible versions of QString and QVariant:
-All other configurations (i.e., PyQt4 on Python 3.x, PySide, PyQt5, IPython QtConsole widget) uses version 2 only or as the default.
+ - version 1, the legacy version which is also the default, and
+ - version 2, a more pythonic one, which is the only one supported by *silx*.
-For more information, see `IPython, PyQt and PySide <http://ipython.org/ipython-doc/stable/interactive/reference.html#pyqt-and-pyside>`_.
+ All other configurations (i.e., PyQt4 on Python 3.x, PySide, PyQt5, IPython QtConsole widget) uses version 2.
+ For more information, see `IPython, PyQt and PySide <http://ipython.org/ipython-doc/stable/interactive/reference.html#pyqt-and-pyside>`_.
-From Python
-+++++++++++
-
-The :mod:`silx.sx` package is a convenient module to use silx from the console.
-It sets-up Qt and provides functions for the main features of silx.
-
->>> from silx import sx
-
-Alternatively, you can create a QApplication before using silx widgets:
-
->>> from silx.gui import qt # Import Qt binding and do some set-up
->>> qapp = qt.QApplication([])
-
->>> from silx.gui.plot import * # Import plot widgets and set-up matplotlib
-
-.. currentmodule:: silx.sx
Plot functions
++++++++++++++
-The :mod:`silx.sx` package provides 2 functions to plot curves and images from the (I)Python console in a widget with a set of tools:
-
-- :func:`plot`, and
-- :func:`imshow`.
-
-For more features, use widgets directly (see `Plot curves in a widget`_ and `Plot images in a widget`_).
-
-
-Curve: :func:`plot`
-...................
-
-The following examples must run with a Qt QApplication initialized (see `Use silx.gui.plot from the console`_).
-
-First import :mod:`sx` function:
-
->>> from silx import sx
->>> import numpy
-
-Plot a single curve given some values:
-
->>> values = numpy.random.random(100)
->>> plot_1curve = sx.plot(values, title='Random data')
-
-Plot a single curve given the x and y values:
-
->>> angles = numpy.linspace(0, numpy.pi, 100)
->>> sin_a = numpy.sin(angles)
->>> plot_sinus = sx.plot(angles, sin_a,
-... xlabel='angle (radian)', ylabel='sin(a)')
-
-Plot many curves by giving a 2D array, provided xn, yn arrays:
-
->>> plot_curves = sx.plot(x0, y0, x1, y1, x2, y2, ...)
-
-Plot curve with style giving a style string:
-
->>> plot_styled = sx.plot(x0, y0, 'ro-', x1, y1, 'b.')
-
-See :func:`plot` for details.
+The :mod:`silx.sx` module provides functions to plot curves and images with :mod:`silx.gui.plot` widgets:
+- :func:`~silx.sx.plot` for curves, e.g., :python:`sx.plot(y)` or :python:`sx.plot(x, y)`
+- :func:`~silx.sx.imshow` for images, e.g., :python:`sx.imshow(image)`
-Image: :func:`imshow`
-.....................
+See :mod:`silx.sx` for documentation and how to use it.
-This example plot a single image.
-
-First, import :mod:`silx.sx`:
-
->>> from silx import sx
->>> import numpy
-
->>> data = numpy.random.random(1024 * 1024).reshape(1024, 1024)
->>> plt = sx.imshow(data, title='Random data')
-
-See :func:`imshow` for more details.
+For more features, use widgets directly (see `Plot curves in a widget`_ and `Plot images in a widget`_).
Use :mod:`silx.gui.plot` from a script
--------------------------------------
-A Qt GUI script must have a QApplication initialized before creating widgets:
+A Qt GUI script must have a QApplication initialised before creating widgets:
.. code-block:: python
@@ -146,27 +93,22 @@ A Qt GUI script must have a QApplication initialized before creating widgets:
[...]
qapp.exec_()
-Unless a Qt binding has already been loaded, :mod:`silx.gui.qt` uses the first Qt binding it founds by probing in the following order: PyQt5, PyQt4 and finally PySide.
+Unless a Qt binding has already been loaded, :mod:`silx.gui.qt` uses one of the supported Qt bindings (PyQt4, PySide or PyQt5).
If you prefer to choose the Qt binding yourself, import it before importing
a module from :mod:`silx.gui`:
.. code-block:: python
- import PySide # Importing PySide will force silx to use it
+ import PyQt5.QtCore # Importing PyQt5 will force silx to use it
from silx.gui import qt
-.. warning::
-
- :mod:`silx.gui.plot` widgets are not thread-safe.
- All calls to :mod:`silx.gui.plot` widgets must be made from the main thread.
-
Plot curves in a widget
-----------------------
-The :class:`Plot1D` widget provides a plotting area and a toolbar with tools useful for curves such as setting logarithmic scale or defining region of interest.
+The :class:`~silx.gui.plot.PlotWindow.Plot1D` widget provides a plotting area and a toolbar with tools useful for curves such as setting a logarithmic scale or defining a region of interest.
-First, create a :class:`Plot1D` widget:
+First, create a :class:`~silx.gui.plot.PlotWindow.Plot1D` widget:
.. code-block:: python
@@ -183,15 +125,17 @@ To display a single curve, use the :meth:`.PlotWidget.addCurve` method:
.. code-block:: python
- plot.addCurve(x=(1, 2, 3), y=(3, 2, 1)) # Add a curve with default style
+ plot.addCurve(x=(1, 2, 3), y=(3, 2, 1), legend='curve') # Add a curve named 'curve'
-When you need to update this curve, call :meth:`.PlotWidget.addCurve` again with the new values to display:
+When you need to update this curve, first get the curve invoking :meth:`.PlotWidget.getCurve` and
+update its points invoking the curve's :meth:`~silx.gui.plot.items.Curve.setData` method:
.. code-block:: python
- plot.addCurve(x=(1, 2, 3), y=(1, 2, 3)) # Replace the existing curve
+ mycurve = plot.getCurve('curve') # Retrieve the curve
+ mycurve.setData(x=(1, 2, 3), y=(1, 2, 3)) # Update its data
-To clear the plotting area, call :meth:`.PlotWidget.clear`:
+To clear the plot, call :meth:`.PlotWidget.clear`:
.. code-block:: python
@@ -201,7 +145,7 @@ To clear the plotting area, call :meth:`.PlotWidget.clear`:
Multiple curves
+++++++++++++++
-In order to display multiple curves at the same time, you need to provide a different ``legend`` string for each of them:
+In order to display multiple curves in a frame, you need to provide a different ``legend`` string for each of them:
.. code-block:: python
@@ -213,14 +157,15 @@ In order to display multiple curves at the same time, you need to provide a diff
plot.addCurve(x, numpy.random.random(len(x)), legend='random')
-To update a curve, call :meth:`.PlotWidget.addCurve` with the ``legend`` of the curve you want to udpdate.
-By default, the new curve will keep the same color (and style) as the curve it is updating:
+To update a curve, call :meth:`.PlotWidget.getCurve` with the ``legend`` of the curve you want to update,
+and update its data through :meth:`~silx.gui.plot.items.Curve.setData`:
.. code-block:: python
- plot.addCurve(x, numpy.random.random(len(x)) - 1., legend='random')
+ curve = plot.getCurve('random')
+ curve.setData(x, numpy.random.random(len(x)) - 1.)
-To remove a curve from the plot, call :meth:`.PlotWidget.remove` with the ``legend`` of the curve you want to remove from the plot:
+To remove a curve from the plot, call :meth:`.PlotWidget.remove` with the ``legend`` of the curve you want to remove:
.. code-block:: python
@@ -235,9 +180,9 @@ To clear the plotting area, call :meth:`.PlotWidget.clear`:
Curve style
+++++++++++
-By default, different curves will automatically use different styles to render, and keep the same style when updated.
+By default, different curves will automatically be displayed using different styles, and keep the same style when updating the plot.
-It is possible to specify the ``color`` of the curve, its ``linewidth`` and ``linestyle`` as well as the ``symbol`` to use as markers for data points (See :meth:`.PlotWidget.addCurve` for more details):
+It is possible to specify the ``color`` of the curve, its ``linewidth`` and ``linestyle`` as well as the ``symbol`` to use as marker for data points (See :meth:`.PlotWidget.addCurve` for more details):
.. code-block:: python
@@ -262,24 +207,32 @@ It is possible to specify the ``color`` of the curve, its ``linewidth`` and ``li
Histogram
+++++++++
-Data can be displayed as an histogram. This must be specified when calling the the addCurve function. (using ``histogram``, See :meth:`.PlotWidget.addCurve` for more details ).
+To display histograms, use :meth:`.PlotWidget.addHistogram`:
-Histogram steps can be centered on x values or set at the left or the right of the given x values.
+.. code-block:: python
+
+ import numpy
+ values = numpy.arange(20) # Values of the histogram
+ edges = numpy.arange(21) # Edges of the bins (number of values + 1)
+ plot.addHistogram(values, edges, legend='histo1', fill=True, color='green')
+
+Alternatively, :meth:`.PlotWidget.addCurve` can be used to display histograms with the ``histogram`` argument.
+(See :meth:`.PlotWidget.addCurve` for more details).
.. code-block:: python
import numpy
x = numpy.arange(0, 20, 1)
- plot.addCurve(x, x+1, histogram='center', fill=True, color='green')
+ plot.addCurve(x, x+1, legend='histo2', histogram='center', fill=False, color='black')
-.. note:: You can also give x as edges. For this you must have len(x) = len(y) + 1
+Histogram bins can be centred on x values or set on the left hand side or the right hand side of the given x values.
Plot images in a widget
-----------------------
-The :class:`Plot2D` widget provides a plotting area and a toolbar with tools useful for images, such as keeping aspect ratio, changing the colormap or defining a mask.
+The :class:`~silx.gui.plot.PlotWindow.Plot2D` widget provides a plotting area and a toolbar with tools useful for images, such as keeping the aspect ratio, changing the colormap or defining a mask.
-First, create a :class:`Plot2D` widget:
+First, create a :class:`~silx.gui.plot.PlotWindow.Plot2D` widget:
.. code-block:: python
@@ -288,7 +241,6 @@ First, create a :class:`Plot2D` widget:
plot = Plot2D() # Create the plot widget
plot.show() # Make the plot widget visible
-
One image
+++++++++
@@ -299,46 +251,36 @@ To display a single image, use the :meth:`.PlotWidget.addImage` method:
import numpy
data = numpy.random.random(512 * 512).reshape(512, -1) # Create 2D image
- plot.addImage(data) # Plot the 2D data set with default colormap
-
+ plot.addImage(data, legend='image') # Plot the 2D data set with default colormap
-To update this image, call :meth:`.PlotWidget.addImage` again with the new image to display:
+To update this image, call :meth:`.PlotWidget.getImage` with its ``legend`` and
+update its data with :meth:`~silx.gui.plot.items.Image.setData`:
.. code-block:: python
- # Create a RGB image
- rgb_image = (numpy.random.random(512*512*3) * 255).astype(numpy.uint8)
- rgb_image.shape = 512, 512, 3
+ data2 = numpy.arange(512*512).reshape(512, 512)
- plot.addImage(rgb_image) # Plot the RGB image instead of the previous data
+ image = plot.getImage('image') # Retrieve the image
+ image.setData(data2) # Update the displayed data
+:meth:`.PlotWidget.addImage` supports both 2D arrays of data displayed with a colormap and RGB(A) images as 3D arrays of shape (height, width, color channels).
-To clear the plotting area, call :meth:`.PlotWidget.clear`:
+To clear the plot area, call :meth:`.PlotWidget.clear`:
.. code-block:: python
plot.clear()
-
Origin and scale
++++++++++++++++
-:meth:`.PlotWidget.addImage` supports both 2D arrays of data displayed with a colormap and RGB(A) images as 3D arrays of shape (height, width, color channels).
-When displaying an image, it is possible to specify the ``origin`` and the ``scale`` of the image array in the plot area coordinates:
+When displaying an image, it is possible to define the ``origin`` and the ``scale`` of the image array in the plot area coordinates:
.. code-block:: python
data = numpy.random.random(512 * 512).reshape(512, -1)
- plot.addImage(data, origin=(100, 100), scale=(0.1, 0.1))
-
-When updating an image, if ``origin`` and ``scale`` are not provided, the previous values will be used:
-
-.. code-block:: python
-
- data = numpy.random.random(512 * 512).reshape(512, -1)
- plot.addImage(data) # Keep previous origin and scale
-
+ plot.addImage(data, legend='image', origin=(100, 100), scale=(0.1, 0.1))
Colormap
++++++++
@@ -347,6 +289,8 @@ A ``colormap`` is described with a :class:`.Colormap` class as follows:
.. code-block:: python
+ from silx.gui.plot.Colormap import Colormap
+
colormap = Colormap(name='gray', # Name of the colormap
normalization='linear', # Either 'linear' or 'log'
vmin=0.0, # If not autoscale, data value to bind to min of colormap
@@ -354,7 +298,7 @@ A ``colormap`` is described with a :class:`.Colormap` class as follows:
)
-At least the following colormap names are guaranteed to be available, but any colormap name from `matplotlib <http://matplotlib.org/>`_ (see `Choosing Colormaps <http://matplotlib.org/users/colormaps.html>`_) should work:
+The following colormap names are guaranteed to be available:
- gray
- reversed gray
@@ -367,14 +311,18 @@ At least the following colormap names are guaranteed to be available, but any co
- inferno
- plasma
-It is possible to change the default colormap of :meth:`.PlotWidget.addImage` for the plot widget with :meth:`.PlotWidget.setDefaultColormap` (and to get it with :meth:`.PlotWidget.getDefaultColormap`):
+Yet, any colormap name from `matplotlib <http://matplotlib.org/>`_ (see `Choosing Colormaps <http://matplotlib.org/users/colormaps.html>`_) should work.
+
+It is possible to change the default colormap of the plot widget by :meth:`.PlotWidget.setDefaultColormap` (and to get it with :meth:`.PlotWidget.getDefaultColormap`):
.. code-block:: python
+ from silx.gui.plot.Colormap import Colormap
+
colormap = Colormap(name='viridis',
normalization='linear',
vmin=0.0,
- vmax=1.0)
+ vmax=10000.0)
plot.setDefaultColormap(colormap)
data = numpy.arange(512 * 512.).reshape(512, -1)
@@ -386,25 +334,18 @@ It is also possible to provide a :class:`.Colormap` to :meth:`.PlotWidget.addIma
colormap = Colormap(name='magma',
normalization='log',
- vmin=1.2,
- vmax=1.8)
+ vmin=1.8,
+ vmax=2.2)
data = numpy.random.random(512 * 512).reshape(512, -1) + 1.
plot.addImage(data, colormap=colormap)
-As for `Origin and scale`_, when updating an image, if ``colormap`` is not provided, the previous colormap will be used:
-
-.. code-block:: python
-
- data = numpy.random.random(512 * 512).reshape(512, -1) + 1.
- plot.addImage(data) # Keep previous colormap
-
The colormap can be changed by the user from the widget's toolbar.
Multiple images
+++++++++++++++
-In order to display multiple images at the same time, you need to provide a different ``legend`` string for each of them and to set the ``replace`` argument to ``False``:
+In order to display multiple images in a frame, you need to provide a different ``legend`` string for each of them and to set the ``replace`` argument to ``False``:
.. code-block:: python
@@ -415,27 +356,27 @@ In order to display multiple images at the same time, you need to provide a diff
plot.addImage(data, legend='arange', replace=False, origin=(512, 512))
-To update an image, call :meth:`.PlotWidget.addImage` with the ``legend`` of the curve you want to udpdate.
-By default, the new image will keep the same colormap, origin and scale as the image it is updating:
+To update an image, call :meth:`.PlotWidget.getImage` with the ``legend`` to get the corresponding curve.
+Update its data values using :meth:`~silx.gui.plot.items.setData`.
.. code-block:: python
data = (512 * 512. - numpy.arange(512 * 512.)).reshape(512, -1)
- plot.addImage(data, legend='arange', replace=False) # Beware of replace=False
-
+ arange_image = plot.getImage('arange')
+ arange_image.setData(data)
-To remove an image from the plot, call :meth:`.PlotWidget.remove` with the ``legend`` of the image you want to remove:
+To remove an image from a plot, call :meth:`.PlotWidget.remove` with the ``legend`` of the image you want to remove:
.. code-block:: python
plot.remove('random')
-Control plot axes
------------------
+Configure plot axes
+-------------------
-The following examples illustrate the API to control the plot axes.
-:meth:`.PlotWidget.getXAxis` and :meth:`.PlotWidget.getYAxis` give access to each plot axis (:class:`.items.Axis`) in order to control them.
+The following examples illustrate the API to configure the plot axes.
+:meth:`.PlotWidget.getXAxis` and :meth:`.PlotWidget.getYAxis` give access to each plot axis (:class:`.items.Axis`) in order to configure them.
Labels and title
++++++++++++++++
@@ -453,7 +394,7 @@ Use :meth:`.PlotWidget.getXAxis` and :meth:`.PlotWidget.getYAxis` to get the axe
Axes limits
+++++++++++
-Different methods allows to get and set the data limits displayed on each axis.
+Different methods allow to retrieve and set the data limits displayed on each axis.
The following code moves the visible plot area to the right:
@@ -463,7 +404,7 @@ The following code moves the visible plot area to the right:
offset = 0.1 * (xmax - xmin)
plot.getXAxis().setLimits(xmin + offset, xmax + offset)
-:meth:`.PlotWidget.resetZoom` set the plot limits to the bounds of the data:
+:meth:`.PlotWidget.resetZoom` set the plot limits to the upper and lower bounds of the data:
.. code-block:: python
@@ -475,7 +416,7 @@ See :meth:`.PlotWidget.resetZoom`, :meth:`.PlotWidget.setLimits`, :meth:`.PlotWi
Axes
++++
-Different methods allow plot axes modifications:
+The axes of a plot can be modified via different methods:
.. code-block:: python
diff --git a/doc/source/modules/gui/plot/index.rst b/doc/source/modules/gui/plot/index.rst
index b77bbcc..ab1c7df 100644
--- a/doc/source/modules/gui/plot/index.rst
+++ b/doc/source/modules/gui/plot/index.rst
@@ -36,6 +36,7 @@ Public modules
colormap.rst
items.rst
actions/index.rst
+ plottoolbuttons.rst
plottools.rst
profile.rst
roi.rst
diff --git a/doc/source/modules/gui/plot/plotsignal.rst b/doc/source/modules/gui/plot/plotsignal.rst
new file mode 100644
index 0000000..c4cb003
--- /dev/null
+++ b/doc/source/modules/gui/plot/plotsignal.rst
@@ -0,0 +1,166 @@
+
+.. currentmodule:: silx.gui.plot.PlotWidget
+
+.. _plot_signal:
+
+Plot signal
+-----------
+
+The :class:`PlotWidget` sends events through its :attr:`PlotWidget.sigPlotSignal`
+signal.
+Those events are sent as a dictionary with a key 'event' describing the kind
+of event.
+
+.. note::
+
+ These dictionary events will be replaced by objects in the future.
+
+
+Drawing events
+..............
+
+'drawingProgress' and 'drawingFinished' events are sent during drawing
+interaction (See :meth:`PlotWidget.setInteractiveMode`).
+
+- 'event': 'drawingProgress' or 'drawingFinished'
+- 'parameters': dict of parameters used by the drawing mode.
+ It has the following keys: 'shape', 'label', 'color'.
+ See :meth:`PlotWidget.setInteractiveMode`.
+- 'points': Points (x, y) in data coordinates of the drawn shape.
+ For 'hline' and 'vline', it is the 2 points defining the line.
+ For 'line' and 'rectangle', it is the coordinates of the start
+ drawing point and the latest drawing point.
+ For 'polygon', it is the coordinates of all points of the shape.
+- 'type': The type of drawing in 'line', 'hline', 'polygon', 'rectangle',
+ 'vline'.
+- 'xdata' and 'ydata': X coords and Y coords of shape points in data
+ coordinates (as in 'points').
+
+When the type is 'rectangle', the following additional keys are provided:
+
+- 'x' and 'y': The origin of the rectangle in data coordinates
+- 'widht' and 'height': The size of the rectangle in data coordinates
+
+
+Mouse events
+............
+
+'mouseMoved', 'mouseClicked' and 'mouseDoubleClicked' events are sent for
+mouse events.
+
+They provide the following keys:
+
+- 'event': 'mouseMoved', 'mouseClicked' or 'mouseDoubleClicked'
+- 'button': the mouse button that was pressed in 'left', 'middle', 'right'
+- 'x' and 'y': The mouse position in data coordinates
+- 'xpixel' and 'ypixel': The mouse position in pixels
+
+
+Marker events
+.............
+
+'hover', 'markerClicked', 'markerMoving' and 'markerMoved' events are
+sent during interaction with markers.
+
+'hover' is sent when the mouse cursor is over a marker.
+'markerClicker' is sent when the user click on a selectable marker.
+'markerMoving' and 'markerMoved' are sent when a draggable marker is moved.
+
+They provide the following keys:
+
+- 'event': 'hover', 'markerClicked', 'markerMoving' or 'markerMoved'
+- 'button': the mouse button that is pressed in 'left', 'middle', 'right'
+- 'draggable': True if the marker is draggable, False otherwise
+- 'label': The legend associated with the clicked image or curve
+- 'selectable': True if the marker is selectable, False otherwise
+- 'type': 'marker'
+- 'x' and 'y': The mouse position in data coordinates
+- 'xdata' and 'ydata': The marker position in data coordinates
+
+'markerClicked' and 'markerMoving' events have a 'xpixel' and a 'ypixel'
+additional keys, that provide the mouse position in pixels.
+
+
+Image and curve events
+......................
+
+'curveClicked' and 'imageClicked' events are sent when a selectable curve
+or image is clicked.
+
+Both share the following keys:
+
+- 'event': 'curveClicked' or 'imageClicked'
+- 'button': the mouse button that was pressed in 'left', 'middle', 'right'
+- 'label': The legend associated with the clicked image or curve
+- 'type': The type of item in 'curve', 'image'
+- 'x' and 'y': The clicked position in data coordinates
+- 'xpixel' and 'ypixel': The clicked position in pixels
+
+'curveClicked' events have a 'xdata' and a 'ydata' additional keys, that
+provide the coordinates of the picked points of the curve.
+There can be more than one point of the curve being picked, and if a line of
+the curve is picked, only the first point of the line is included in the list.
+
+'imageClicked' have a 'col' and a 'row' additional keys, that provide
+the column and row index in the image array that was clicked.
+
+
+Limits changed events
+.....................
+
+.. warning::
+
+ This event is deprecated. Use :attr:`silx.gui.plot.items.axis.Axis.sigLimitsChanged`
+ instead. See :meth:`PlotWidget.getXAxis` and :meth:`PlotWidget.getYAxis`.
+
+'limitsChanged' events are sent when the limits of the plot are changed.
+This can results from user interaction or API calls.
+
+It provides the following keys:
+
+- 'event': 'limitsChanged'
+- 'source': id of the widget that emitted this event.
+- 'xdata': Range of X in graph coordinates: (xMin, xMax).
+- 'ydata': Range of Y in graph coordinates: (yMin, yMax).
+- 'y2data': Range of right axis in graph coordinates (y2Min, y2Max) or None.
+
+Plot state change events
+........................
+
+.. warning::
+
+ These events are deprecated.  
+ Use :attr:`PlotWidget.sigSetKeepDataAspectRatio`,
+ :attr:`PlotWidget.sigSetGraphGrid`, :attr:`PlotWidget.sigSetGraphCursor`,
+ :attr:`PlotWidget.sigContentChanged`, :attr:`PlotWidget.sigActiveCurveChanged`,
+ :attr:`PlotWidget.sigActiveImageChanged` and
+ :attr:`PlotWidget.sigInteractiveModeChanged` instead.
+
+
+The following events are emitted when the plot is modified.
+They provide the new state:
+
+- 'setGraphCursor' event with a 'state' key (bool)
+- 'setGraphGrid' event with a 'which' key (str), see :meth:`setGraphGrid`
+- 'setKeepDataAspectRatio' event with a 'state' key (bool)
+
+A 'contentChanged' event is triggered when the content of the plot is updated.
+It provides the following keys:
+
+- 'action': The change of the plot: 'add' or 'remove'
+- 'kind': The kind of primitive changed: 'curve', 'image', 'item' or 'marker'
+- 'legend': The legend of the primitive changed.
+
+'activeCurveChanged' and 'activeImageChanged' events with the following keys:
+
+- 'legend': Name (str) of the current active item or None if no active item.
+- 'previous': Name (str) of the previous active item or None if no item was
+ active. It is the same as 'legend' if 'updated' == True
+- 'updated': (bool) True if active item name did not changed,
+ but active item data or style was updated.
+
+'interactiveModeChanged' event with a 'source' key identifying the object
+setting the interactive mode.
+
+'defaultColormapChanged' event is triggered when the default colormap of
+the plot is updated.
diff --git a/doc/source/modules/gui/plot/plottoolbuttons.rst b/doc/source/modules/gui/plot/plottoolbuttons.rst
new file mode 100644
index 0000000..e1e1626
--- /dev/null
+++ b/doc/source/modules/gui/plot/plottoolbuttons.rst
@@ -0,0 +1,7 @@
+:mod:`~silx.gui.plot.PlotToolButtons`: QToolButtons for plot widgets
+====================================================================
+
+.. currentmodule:: silx.gui.plot.PlotToolButtons
+
+.. automodule:: silx.gui.plot.PlotToolButtons
+ :members:
diff --git a/doc/source/modules/gui/plot/plotwidget.rst b/doc/source/modules/gui/plot/plotwidget.rst
index a8e7831..d045f92 100644
--- a/doc/source/modules/gui/plot/plotwidget.rst
+++ b/doc/source/modules/gui/plot/plotwidget.rst
@@ -166,6 +166,11 @@ The :class:`PlotWidget` provides the following Qt signals:
.. autoattribute:: PlotWidget.sigActiveScatterChanged
.. autoattribute:: PlotWidget.sigInteractiveModeChanged
+.. toctree::
+ :hidden:
+
+ plotsignal.rst
+
.. PlotWidget public API that is not documented:
Could be added:
- addItem
diff --git a/doc/source/modules/gui/plot3d/actions.rst b/doc/source/modules/gui/plot3d/actions.rst
index c9e3af2..66086bc 100644
--- a/doc/source/modules/gui/plot3d/actions.rst
+++ b/doc/source/modules/gui/plot3d/actions.rst
@@ -12,4 +12,7 @@
.. automodule:: silx.gui.plot3d.actions.mode
:members:
+.. automodule:: silx.gui.plot3d.actions.viewpoint
+ :members:
+
.. autoclass:: Plot3DAction
diff --git a/doc/source/modules/gui/plot3d/dev.rst b/doc/source/modules/gui/plot3d/dev.rst
index 96704f8..f135767 100644
--- a/doc/source/modules/gui/plot3d/dev.rst
+++ b/doc/source/modules/gui/plot3d/dev.rst
@@ -12,10 +12,10 @@ Widget-level API
Widgets are available as modules of the :mod:`silx.gui.plot3d` packages.
The :mod:`.Plot3DWidget` module provides the OpenGL canvas where the scene is rendered.
-The :mod:`.Plot3DWindow` module provides a :class:`QMainWindow` with a :class:`Plot3DWindow` as its central widget,
-toolbars (:class:`InteractiveModeToolBar` and :class:`OutputToolBar`) and a :class:`ViewpointToolButton` in a toolbar.
-:class:`QAction` that can be associated with a :class:`Plot3DWidget` are defined in the :mod:`.actions` module.
-Those actions are used by the :class:`OutputToolBar` and the :class:`InteractiveModeToolBar` toolbars.
+The :mod:`.Plot3DWindow` module provides a :class:`QMainWindow` with a :class:`Plot3DWindow` as its central widget
+and toolbars: :class:`InteractiveModeToolBar`, :class:`ViewpointToolBar` and :class:`OutputToolBar`.
+:class:`QAction` that can be associated with a :class:`Plot3DWidget` are defined in the :mod:`.actions` package.
+Toolbars and tool buttons are available in :mod:`.tools` package.
The :mod:`.ScalarFieldView` module defines the :class:`ScalarFieldView` widget that displays iso-surfaces of a 3D scalar data set and the associated classes.
The :mod:`.SFViewParamTree` module defines a :class:`SFViewParamTree.TreeView` widget that can be attached to a :class:`ScalarFieldView` to control the display.
diff --git a/doc/source/modules/gui/plot3d/img/Plot3DWindow.png b/doc/source/modules/gui/plot3d/img/Plot3DWindow.png
index 0e562f5..6066d2a 100644
--- a/doc/source/modules/gui/plot3d/img/Plot3DWindow.png
+++ b/doc/source/modules/gui/plot3d/img/Plot3DWindow.png
Binary files differ
diff --git a/doc/source/modules/gui/plot3d/img/ScalarFieldView.png b/doc/source/modules/gui/plot3d/img/ScalarFieldView.png
index f40fdac..f8f61da 100644
--- a/doc/source/modules/gui/plot3d/img/ScalarFieldView.png
+++ b/doc/source/modules/gui/plot3d/img/ScalarFieldView.png
Binary files differ
diff --git a/doc/source/modules/gui/plot3d/img/SceneWidget.png b/doc/source/modules/gui/plot3d/img/SceneWidget.png
new file mode 100644
index 0000000..610c41a
--- /dev/null
+++ b/doc/source/modules/gui/plot3d/img/SceneWidget.png
Binary files differ
diff --git a/doc/source/modules/gui/plot3d/img/SceneWindow.png b/doc/source/modules/gui/plot3d/img/SceneWindow.png
new file mode 100644
index 0000000..c3c48af
--- /dev/null
+++ b/doc/source/modules/gui/plot3d/img/SceneWindow.png
Binary files differ
diff --git a/doc/source/modules/gui/plot3d/index.rst b/doc/source/modules/gui/plot3d/index.rst
index 38b8f02..e0a14f6 100644
--- a/doc/source/modules/gui/plot3d/index.rst
+++ b/doc/source/modules/gui/plot3d/index.rst
@@ -23,6 +23,8 @@ The following sub-modules are available:
plot3dwidget.rst
plot3dwindow.rst
+ scenewidget.rst
+ scenewindow.rst
scalarfieldview.rst
sfviewparamtree.rst
tools.rst
@@ -32,7 +34,7 @@ The following sub-modules are available:
Sample code
-----------
-- :doc:`viewer3dvolume_example`: Sample code using :class:`ScalarFieldView`
+See :ref:`plot3d-sample-code`
Internals
---------
@@ -41,8 +43,3 @@ Internals
:maxdepth: 2
dev.rst
-
-.. toctree::
- :hidden:
-
- viewer3dvolume_example.rst
diff --git a/doc/source/modules/gui/plot3d/items.rst b/doc/source/modules/gui/plot3d/items.rst
new file mode 100644
index 0000000..1162cb9
--- /dev/null
+++ b/doc/source/modules/gui/plot3d/items.rst
@@ -0,0 +1,173 @@
+.. currentmodule:: silx.gui.plot3d
+
+:mod:`items`: SceneWidget items
+===============================
+
+The following classes are items that describes the content of a :class:`SceneWidget`:
+
+.. currentmodule:: silx.gui.plot3d.items
+
+- :class:`~silx.gui.plot3d.items.image.ImageData`
+- :class:`~silx.gui.plot3d.items.image.ImageRgba`
+- :class:`~silx.gui.plot3d.items.scatter.Scatter2D`
+- :class:`~silx.gui.plot3d.items.scatter.Scatter3D`
+- :class:`~silx.gui.plot3d.items.volume.ScalarField3D`
+- :class:`~silx.gui.plot3d.items.clipplane.ClipPlane`
+- :class:`~silx.gui.plot3d.items.mesh.Mesh`
+- :class:`~silx.gui.plot3d.items.core.GroupItem`
+
+2D images
+---------
+
+.. currentmodule:: silx.gui.plot3d.core
+
+.. currentmodule:: silx.gui.plot3d.items.image
+
+:class:`ImageData`
+++++++++++++++++++
+
+:class:`ImageData` inherits from :class:`.DataItem3D` and also provides its API.
+
+.. autoclass:: ImageData
+ :members: getData, setData,
+ getColormap, setColormap,
+ getInterpolation, setInterpolation
+
+:class:`ImageRgba`
+++++++++++++++++++
+
+:class:`ImageRgba` inherits from :class:`.DataItem3D` and also provides its API.
+
+.. autoclass:: ImageRgba
+ :members: getData, setData,
+ getInterpolation, setInterpolation
+
+2D/3D scatter data
+------------------
+
+.. currentmodule:: silx.gui.plot3d.items.scatter
+
+:class:`Scatter2D`
+++++++++++++++++++
+
+:class:`Scatter2D` inherits from :class:`.DataItem3D` and also provides its API.
+
+.. autoclass:: Scatter2D
+ :members: getData, setData, getXData, getYData, getValues,
+ supportedVisualizations, isPropertyEnabled,
+ getVisualization, setVisualization,
+ isHeightMap, setHeightMap,
+ getLineWidth, setLineWidth,
+ getColormap, setColormap,
+ getSupportedSymbols, getSymbol, setSymbol
+
+:class:`Scatter3D`
+++++++++++++++++++
+
+:class:`Scatter3D` inherits from :class:`.DataItem3D` and also provides its API.
+
+.. autoclass:: Scatter3D
+ :members: getData, setData, getXData, getYData, getZData, getValues,
+ getColormap, setColormap,
+ getSupportedSymbols, getSymbol, setSymbol
+
+3D volume
+---------
+
+.. currentmodule:: silx.gui.plot3d.items.volume
+
+:class:`ScalarField3D`
+++++++++++++++++++++++
+
+:class:`ScalarField3D` inherits from :class:`.DataItem3D` and also provides its API.
+
+.. autoclass:: ScalarField3D
+ :members: getData, setData,
+ getCutPlanes,
+ sigIsosurfaceAdded, sigIsosurfaceRemoved,
+ addIsosurface, getIsosurfaces, removeIsosurface, clearIsosurfaces
+
+The following classes allows to configure :class:`ScalarField3D` visualization:
+
+:class:`IsoSurface`
++++++++++++++++++++
+
+:class:`IsoSurface` inherits from :class:`.Item3D` and also provides its API.
+
+.. autoclass:: Isosurface
+ :show-inheritance:
+ :members:
+
+:class:`CutPlane`
++++++++++++++++++
+
+:class:`CutPlane` inherits from :class:`.Item3D` and also provides its API.
+
+.. autoclass:: CutPlane
+ :members: getColormap, setColormap,
+ getInterpolation, setInterpolation,
+ moveToCenter, isValid,
+ getNormal, setNormal,
+ getPoint, setPoint,
+ getParameters, setParameters,
+ getDisplayValuesBelowMin, setDisplayValuesBelowMin
+
+Clipping plane
+--------------
+
+.. currentmodule:: silx.gui.plot3d.items.clipplane
+
+:class:`ClipPlane`
+++++++++++++++++++
+
+:class:`ClipPlane` inherits from :class:`.Item3D` and also provides its API.
+
+.. autoclass:: ClipPlane
+ :show-inheritance:
+ :members:
+
+3D mesh
+-------
+
+.. currentmodule:: silx.gui.plot3d.items.mesh
+
+:class:`Mesh`
++++++++++++++
+
+:class:`Mesh` inherits from :class:`.DataItem3D` and also provides its API.
+
+.. autoclass:: Mesh
+ :show-inheritance:
+ :members:
+
+Item base classes
+-----------------
+
+The following classes provides the base classes for other items.
+
+.. currentmodule:: silx.gui.plot3d.items.core
+
+:class:`Item3D`
++++++++++++++++
+
+.. autoclass:: Item3D
+ :show-inheritance:
+ :members:
+
+:class:`DataItem3D`
++++++++++++++++++++
+
+:class:`DataItem3D` inherits from :class:`.Item3D` and also provides its API.
+
+.. autoclass:: DataItem3D
+ :show-inheritance:
+ :members:
+
+:class:`GroupItem`
+++++++++++++++++++
+
+:class:`GroupItem` inherits from :class:`.DataItem3D` and also provides its API.
+
+.. autoclass:: GroupItem
+ :show-inheritance:
+ :members:
diff --git a/doc/source/modules/gui/plot3d/scalarfieldview.rst b/doc/source/modules/gui/plot3d/scalarfieldview.rst
index 80127ea..b2e1e67 100644
--- a/doc/source/modules/gui/plot3d/scalarfieldview.rst
+++ b/doc/source/modules/gui/plot3d/scalarfieldview.rst
@@ -5,7 +5,7 @@
.. automodule:: silx.gui.plot3d.ScalarFieldView
-For sample code using ScalarFieldView, see :doc:`viewer3dvolume_example`
+For sample code using ScalarFieldView, see :ref:`plot3d-sample-code`
.. currentmodule:: silx.gui.plot3d.ScalarFieldView
diff --git a/doc/source/modules/gui/plot3d/scenewidget.rst b/doc/source/modules/gui/plot3d/scenewidget.rst
new file mode 100644
index 0000000..5c6f411
--- /dev/null
+++ b/doc/source/modules/gui/plot3d/scenewidget.rst
@@ -0,0 +1,29 @@
+.. currentmodule:: silx.gui.plot3d
+
+:mod:`SceneWidget`: 3D data viewer widget
+=========================================
+
+.. automodule:: silx.gui.plot3d.SceneWidget
+
+.. image:: img/SceneWidget.png
+ :height: 150px
+ :align: center
+
+For sample code using :class:`SceneWidget`, see ``plot3dSceneWindow.py`` in :ref:`plot3d-sample-code`.
+
+.. currentmodule:: silx.gui.plot3d.SceneWidget
+
+:class:`SceneWidget`
+--------------------
+
+.. autoclass:: SceneWidget
+ :show-inheritance:
+ :members:
+
+:class:`SceneWidget` items
+--------------------------
+
+.. toctree::
+ :maxdepth: 2
+
+ items.rst \ No newline at end of file
diff --git a/doc/source/modules/gui/plot3d/scenewindow.rst b/doc/source/modules/gui/plot3d/scenewindow.rst
new file mode 100644
index 0000000..ee6a59b
--- /dev/null
+++ b/doc/source/modules/gui/plot3d/scenewindow.rst
@@ -0,0 +1,22 @@
+.. currentmodule:: silx.gui.plot3d.SceneWindow
+
+
+:mod:`SceneWindow`: 3D data viewer window
+=========================================
+
+.. automodule:: silx.gui.plot3d.SceneWindow
+
+.. image:: img/SceneWindow.png
+ :height: 150px
+ :align: center
+
+For sample code using :class:`SceneWindow`, see ``plot3dSceneWindow.py`` in :ref:`plot3d-sample-code`.
+
+See :class:`~silx.gui.plot3d.SceneWidget.SceneWidget` for the API to manage the visualized 3D data.
+
+:class:`SceneWindow`
+--------------------
+
+.. autoclass:: SceneWindow
+ :show-inheritance:
+ :members:
diff --git a/doc/source/modules/gui/plot3d/viewer3dvolume_example.rst b/doc/source/modules/gui/plot3d/viewer3dvolume_example.rst
deleted file mode 100644
index 5368e05..0000000
--- a/doc/source/modules/gui/plot3d/viewer3dvolume_example.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-viewer3DVolume.py
-=================
-
-Sample code demonstrating :mod:`silx.gui.plot3d.ScalarFieldView` widget:
-
-.. literalinclude:: ../../../../../examples/viewer3DVolume.py
- :lines: 38- \ No newline at end of file
diff --git a/doc/source/modules/index.rst b/doc/source/modules/index.rst
index b9a4753..b6e0036 100644
--- a/doc/source/modules/index.rst
+++ b/doc/source/modules/index.rst
@@ -8,7 +8,8 @@ API Reference
io/index.rst
image/index.rst
math/index.rst
+ opencl/index.rst
resources.rst
+ sx.rst
utils/index.rst
test/index.rst
-
diff --git a/doc/source/modules/io/index.rst b/doc/source/modules/io/index.rst
index 815a094..b504695 100644
--- a/doc/source/modules/io/index.rst
+++ b/doc/source/modules/io/index.rst
@@ -16,6 +16,7 @@
specfile.rst
specfilewrapper.rst
spech5.rst
+ url.rst
utils.rst
Top-level functions
@@ -23,6 +24,7 @@ Top-level functions
.. autofunction:: silx.io.open
.. autofunction:: silx.io.save1D
+.. autofunction:: silx.io.get_data
.. autofunction:: silx.io.is_dataset
.. autofunction:: silx.io.is_group
diff --git a/doc/source/modules/io/url.rst b/doc/source/modules/io/url.rst
new file mode 100644
index 0000000..6184904
--- /dev/null
+++ b/doc/source/modules/io/url.rst
@@ -0,0 +1,8 @@
+
+.. currentmodule:: silx.io
+
+:mod:`url`: Utils for data locators
+-----------------------------------
+
+.. automodule:: silx.io.url
+ :members:
diff --git a/doc/source/modules/opencl/codec_cbf.rst b/doc/source/modules/opencl/codec_cbf.rst
new file mode 100644
index 0000000..f39a484
--- /dev/null
+++ b/doc/source/modules/opencl/codec_cbf.rst
@@ -0,0 +1,9 @@
+
+.. currentmodule:: silx.opencl.codec
+
+:mod:`byte_offset`: Byte Offset compression/decompression
+---------------------------------------------------------
+
+.. automodule:: silx.opencl.codec.byte_offset
+ :members: ByteOffset
+ :show-inheritance:
diff --git a/doc/source/modules/opencl/fbp.rst b/doc/source/modules/opencl/fbp.rst
new file mode 100644
index 0000000..3c8c465
--- /dev/null
+++ b/doc/source/modules/opencl/fbp.rst
@@ -0,0 +1,10 @@
+
+.. currentmodule:: silx.opencl
+
+:mod:`backprojection`: (Filtered) Back-Projection
+--------------------------------------------------
+
+.. automodule:: silx.opencl.backprojection
+ :members: Backprojection
+ :show-inheritance:
+ :undoc-members:
diff --git a/doc/source/modules/opencl/index.rst b/doc/source/modules/opencl/index.rst
new file mode 100644
index 0000000..e17eecb
--- /dev/null
+++ b/doc/source/modules/opencl/index.rst
@@ -0,0 +1,15 @@
+
+.. py:module:: silx.opencl
+
+:mod:`silx.opencl`: OpenCL-based features
+=========================================
+
+
+.. toctree::
+ :maxdepth: 1
+
+ sift/index.rst
+ fbp.rst
+ medfilt.rst
+ codec_cbf.rst
+
diff --git a/doc/source/modules/opencl/medfilt.rst b/doc/source/modules/opencl/medfilt.rst
new file mode 100644
index 0000000..b1379f7
--- /dev/null
+++ b/doc/source/modules/opencl/medfilt.rst
@@ -0,0 +1,7 @@
+.. currentmodule:: silx.opencl
+
+:mod:`medianfilter`: OpenCL median filter
+------------------------------------------
+
+.. automodule:: silx.opencl.medfilt
+ :members: MedianFilter2D, medfilt2d
diff --git a/doc/source/modules/opencl/sift/align.rst b/doc/source/modules/opencl/sift/align.rst
new file mode 100644
index 0000000..01b9fd6
--- /dev/null
+++ b/doc/source/modules/opencl/sift/align.rst
@@ -0,0 +1,7 @@
+.. currentmodule:: silx.opencl.sift
+
+:mod:`alignment`: SIFT Plan for linear alignment
+-------------------------------------------------
+
+.. automodule:: silx.opencl.sift.alignment
+ :members: LinearAlign
diff --git a/doc/source/modules/opencl/sift/index.rst b/doc/source/modules/opencl/sift/index.rst
new file mode 100644
index 0000000..9ae0d6f
--- /dev/null
+++ b/doc/source/modules/opencl/sift/index.rst
@@ -0,0 +1,11 @@
+.. currentmodule:: silx.opencl.sift
+
+:mod:`sift`: SIFT image alignment
+==================================
+
+.. toctree::
+ :maxdepth: 1
+
+ plan.rst
+ match.rst
+ align.rst
diff --git a/doc/source/modules/opencl/sift/match.rst b/doc/source/modules/opencl/sift/match.rst
new file mode 100644
index 0000000..c64c7d3
--- /dev/null
+++ b/doc/source/modules/opencl/sift/match.rst
@@ -0,0 +1,7 @@
+.. currentmodule:: silx.opencl.sift
+
+:mod:`match`: SIFT Plan for keypoints matching
+------------------------------------------------------
+
+.. automodule:: silx.opencl.sift.match
+ :members: MatchPlan, match_py
diff --git a/doc/source/modules/opencl/sift/plan.rst b/doc/source/modules/opencl/sift/plan.rst
new file mode 100644
index 0000000..135495d
--- /dev/null
+++ b/doc/source/modules/opencl/sift/plan.rst
@@ -0,0 +1,7 @@
+.. currentmodule:: silx.opencl.sift
+
+:mod:`plan`: SIFT Plan
+-----------------------
+
+.. automodule:: silx.opencl.sift.plan
+ :members: SiftPlan
diff --git a/doc/source/modules/sx.rst b/doc/source/modules/sx.rst
new file mode 100644
index 0000000..d5e0288
--- /dev/null
+++ b/doc/source/modules/sx.rst
@@ -0,0 +1,77 @@
+
+:mod:`silx.sx`: Using silx from Python Interpreter
+==================================================
+
+.. currentmodule:: silx.sx
+
+.. automodule:: silx.sx
+
+Plot functions
+--------------
+
+The following functions plot curves and images with silx widgets:
+
+- :func:`plot` for curves
+- :func:`imshow` for images
+
+The :func:`ginput` function handles user selection on those widgets.
+
+
+.. note:: Those functions are not available from a notebook.
+
+:func:`plot`
+++++++++++++
+
+.. autofunction:: plot
+
+:func:`imshow`
+++++++++++++++
+
+.. autofunction:: imshow
+
+
+:func:`ginput`
+++++++++++++++
+
+.. autofunction:: ginput
+
+3D plot functions
+-----------------
+
+The following functions plot 3D data with silx widgets (it requires OpenGL):
+
+- :func:`contour3d` for isosurfaces (and cut plane) in a 3D scalar field
+- :func:`points3d` for 2D/3D scatter plots
+
+.. note:: Those functions are not available from a notebook.
+
+:func:`contour3d`
++++++++++++++++++
+
+.. autofunction:: contour3d
+
+:func:`points3d`
+++++++++++++++++
+
+.. autofunction:: points3d
+
+Widgets
+-------
+
+The widgets of the :mod:`silx.gui.plot` package are also exposed in this package.
+See :mod:`silx.gui.plot` for documentation.
+
+Input/Output
+------------
+
+The content of the :mod:`silx.io` package is also exposed in this package.
+See :mod:`silx.io` for documentation.
+
+Math
+----
+
+The following classes from :mod:`silx.math` are exposed in this package:
+
+- :class:`~silx.math.histogram.Histogramnd`
+- :class:`~silx.math.histogram.HistogramndLut`
+- :class:`~silx.math.fit.leastsq`
diff --git a/doc/source/modules/utils/index.rst b/doc/source/modules/utils/index.rst
index 4eac097..7dd10dd 100644
--- a/doc/source/modules/utils/index.rst
+++ b/doc/source/modules/utils/index.rst
@@ -7,5 +7,5 @@
array_like.rst
decorators.rst
html.rst
+ testutils.rst
weakref.rst
-
diff --git a/doc/source/modules/utils/testutils.rst b/doc/source/modules/utils/testutils.rst
new file mode 100644
index 0000000..854f4be
--- /dev/null
+++ b/doc/source/modules/utils/testutils.rst
@@ -0,0 +1,7 @@
+.. currentmodule:: silx.utils
+
+:mod:`testutils`
+----------------
+
+.. automodule:: silx.utils.testutils
+ :members:
diff --git a/doc/source/overview.rst b/doc/source/overview.rst
index 3cbdd54..50a5ffd 100644
--- a/doc/source/overview.rst
+++ b/doc/source/overview.rst
@@ -4,20 +4,23 @@ Overview
Releases
--------
-Source code, pre-built binaries (aka Python wheels) for Windows and Mac OS X and Debian packages of releases are made available at the following places:
+Source code, pre-built binaries (aka Python wheels) for Windows, MacOS and
+ManyLinux1.
+Debian packages of released versions are made available in the following places:
- `Wheels and source code on PyPi <https://pypi.python.org/pypi/silx>`_
- `Debian 8 packages <http://www.silx.org/pub/debian/>`_
-- `Documentation on PythonHosted <http://pythonhosted.org/silx/>`_
+- `Documentation on silx.org <http://www.silx.org/doc/silx/latest/>`_
- :doc:`changelog`
Nightly builds
--------------
-Debian 8 packages and documentation are automatically generated from the tip of the project's repository on a daily basis:
+Debian 8 packages and documentation are automatically generated from the tip of
+the project's repository on a daily basis:
- `Debian 8 packages <http://www.silx.org/pub/debian/>`_
-- `Documentation <http://www.silx.org/doc/silx/>`_
+- `Documentation <http://www.silx.org/doc/silx/dev/>`_
Project
-------
@@ -25,13 +28,13 @@ Project
- `Homepage <http://www.silx.org/>`_
- `Source repository <https://github.com/silx-kit/silx>`_
- `Issue tracker <https://github.com/silx-kit/silx/issues>`_
-- Mailing list: silx@esrf.fr (`Archive <http://www.silx.org/lurker/list/silx.en.html>`_)
- To register:
+- Mailing list: silx@esrf.fr (`Archive <http://www.silx.org/lurker/list/silx.en.html>`_):
- - from inside ESRF use the `sympa web page <http://sympa.esrf.fr>`_,
- - from outside ESRF, send an email to `silx-subscribe@esrf.fr <mailto:silx-subscribe@esrf.fr>`_.
+ - To register from inside ESRF use the `sympa web page <http://sympa.esrf.fr>`_,
+ - To register from outside ESRF, send an email to `silx-subscribe@esrf.fr <mailto:silx-subscribe@esrf.fr>`_.
-- Continuous integration
+- Continuous integration: *silx* is continuously tested on all three major
+ operating systems:
- Linux and MacOS X: `Travis <https://travis-ci.org/silx-kit/silx>`_
- Windows: `AppVeyor <https://ci.appveyor.com/project/ESRF/silx>`_
diff --git a/doc/source/sample_code/img/colormapDialog.png b/doc/source/sample_code/img/colormapDialog.png
new file mode 100644
index 0000000..6dd0322
--- /dev/null
+++ b/doc/source/sample_code/img/colormapDialog.png
Binary files differ
diff --git a/doc/source/sample_code/img/customDataView.png b/doc/source/sample_code/img/customDataView.png
new file mode 100644
index 0000000..6622cd9
--- /dev/null
+++ b/doc/source/sample_code/img/customDataView.png
Binary files differ
diff --git a/doc/source/sample_code/img/fileDialog.png b/doc/source/sample_code/img/fileDialog.png
new file mode 100644
index 0000000..80b7ea6
--- /dev/null
+++ b/doc/source/sample_code/img/fileDialog.png
Binary files differ
diff --git a/doc/source/sample_code/img/plot3dContextMenu.png b/doc/source/sample_code/img/plot3dContextMenu.png
index a01c884..e70998c 100644
--- a/doc/source/sample_code/img/plot3dContextMenu.png
+++ b/doc/source/sample_code/img/plot3dContextMenu.png
Binary files differ
diff --git a/doc/source/sample_code/img/plot3dSceneWindow.png b/doc/source/sample_code/img/plot3dSceneWindow.png
new file mode 100644
index 0000000..c3c48af
--- /dev/null
+++ b/doc/source/sample_code/img/plot3dSceneWindow.png
Binary files differ
diff --git a/doc/source/sample_code/img/plotClearAction.png b/doc/source/sample_code/img/plotClearAction.png
new file mode 100644
index 0000000..1712cec
--- /dev/null
+++ b/doc/source/sample_code/img/plotClearAction.png
Binary files differ
diff --git a/doc/source/sample_code/img/viewer3DVolume.png b/doc/source/sample_code/img/viewer3DVolume.png
index 69abf26..83e6d99 100644
--- a/doc/source/sample_code/img/viewer3DVolume.png
+++ b/doc/source/sample_code/img/viewer3DVolume.png
Binary files differ
diff --git a/doc/source/sample_code/index.rst b/doc/source/sample_code/index.rst
index a091e58..933d162 100644
--- a/doc/source/sample_code/index.rst
+++ b/doc/source/sample_code/index.rst
@@ -13,6 +13,9 @@ All sample codes can be downloaded as a zip file: |sample_code_archive|.
:mod:`silx.gui` sample code
+++++++++++++++++++++++++++
+:mod:`silx.gui.icons`
+.....................
+
.. list-table::
:widths: 1 1 4
:header-rows: 1
@@ -20,16 +23,32 @@ All sample codes can be downloaded as a zip file: |sample_code_archive|.
* - Source
- Screenshot
- Description
- * - :download:`animatedicons.py <../../../examples/animatedicons.py>`
- - .. image:: img/animatedicons.png
+ * - :download:`icons.py <../../../examples/icons.py>`
+ - .. image:: img/icons.png
:height: 150px
:align: center
- - Display available project icons using Qt.
+ - Display icons and animated icons provided by silx.
+
+:mod:`silx.gui.data` and :mod:`silx.gui.hdf5`
+.............................................
+
+.. list-table::
+ :widths: 1 1 4
+ :header-rows: 1
+
+ * - Source
+ - Screenshot
+ - Description
* - :download:`customHdf5TreeModel.py <../../../examples/customHdf5TreeModel.py>`
- .. image:: img/customHdf5TreeModel.png
:height: 150px
:align: center
- Qt Hdf5 widget examples
+ * - :download:`customDataView.py <../../../examples/customDataView.py>`
+ - .. image:: img/customDataView.png
+ :height: 150px
+ :align: center
+ - Qt data view example
* - :download:`hdf5widget.py <../../../examples/hdf5widget.py>`
- .. image:: img/hdf5widget.png
:height: 150px
@@ -39,11 +58,33 @@ All sample codes can be downloaded as a zip file: |sample_code_archive|.
.. note:: This module has a dependency on the `h5py <http://www.h5py.org/>`_
library, which is not a mandatory dependency for `silx`. You might need
to install it if you don't already have it.
- * - :download:`icons.py <../../../examples/icons.py>`
- - .. image:: img/icons.png
+
+:mod:`silx.gui.dialog`
+......................
+
+.. list-table::
+ :widths: 1 1 4
+ :header-rows: 1
+
+ * - Source
+ - Screenshot
+ - Description
+ * - :download:`fileDialog.py <../../../examples/fileDialog.py>`
+ - .. image:: img/fileDialog.png
:height: 150px
:align: center
- - Display available project icons using Qt.
+ - Example for the use of the ImageFileDialog.
+
+:mod:`silx.gui.widgets`
+.......................
+
+.. list-table::
+ :widths: 1 1 4
+ :header-rows: 1
+
+ * - Source
+ - Screenshot
+ - Description
* - :download:`periodicTable.py <../../../examples/periodicTable.py>`
- .. image:: img/periodicTable.png
:height: 150px
@@ -58,11 +99,15 @@ All sample codes can be downloaded as a zip file: |sample_code_archive|.
It shows the following widgets:
- - :class:WaitingPushButton: A button with a progress-like waiting animated icon
+ - :class:`~silx.gui.widgets.WaitingPushButton`:
+ A button with a progress-like waiting animated icon.
:mod:`silx.gui.plot` sample code
++++++++++++++++++++++++++++++++
+Widgets
+.......
+
.. list-table::
:widths: 1 1 4
:header-rows: 1
@@ -70,13 +115,71 @@ All sample codes can be downloaded as a zip file: |sample_code_archive|.
* - Source
- Screenshot
- Description
+ * - :download:`imageview.py <../../../examples/imageview.py>`
+ - .. image:: img/imageview.png
+ :height: 150px
+ :align: center
+ - Example to show the use of :mod:`~silx.gui.plot.ImageView` widget.
+
+ It can be used to open an EDF or TIFF file from the shell command line.
+
+ To view an image file with the current installed silx library:
+ ``python examples/imageview.py <file to open>``
+ To get help:
+ ``python examples/imageview.py -h``
+
+ For developers with a git clone you can use it with the bootstrap
+ To view an image file with the current installed silx library:
+
+ ``./bootstrap.py python examples/imageview.py <file to open>``
+ * - :download:`stackView.py <../../../examples/stackView.py>`
+ - .. image:: img/stackView.png
+ :height: 150px
+ :align: center
+ - This script is a simple example to illustrate how to use the
+ :mod:`~silx.gui.plot.StackView` widget.
+ * - :download:`colormapDialog.py <../../../examples/colormapDialog.py>`
+ - .. image:: img/colormapDialog.png
+ :height: 150px
+ :align: center
+ - This script shows the features of a :mod:`~silx.gui.plot.ColormapDialog`.
+
+:class:`silx.gui.plot.actions.PlotAction`
+.........................................
+
+Sample code that adds buttons to the toolbar of a silx plot widget.
+
+.. list-table::
+ :widths: 1 1 4
+ :header-rows: 1
+
+ * - Source
+ - Screenshot
+ - Description
+ * - :download:`plotClearAction.py <../../../examples/plotClearAction.py>`
+ - .. image:: img/plotClearAction.png
+ :height: 150px
+ :align: center
+ - This script shows how to create a minimalistic
+ :class:`~silx.gui.plot.actions.PlotAction` that clear the plot.
+
+ This illustrates how to add more buttons in a plot widget toolbar.
+ * - :download:`shiftPlotAction.py <../../../examples/shiftPlotAction.py>`
+ - .. image:: img/shiftPlotAction.png
+ :height: 150px
+ :align: center
+ - This script is a simple (trivial) example of how to create a :class:`~silx.gui.plot.PlotWindow`,
+ create a custom :class:`~silx.gui.plot.actions.PlotAction` and add it to the toolbar.
+
+ The action simply shifts the selected curve up by 1 unit by adding 1 to each
+ value of y.
* - :download:`fftPlotAction.py <../../../examples/fftPlotAction.py>`,
:download:`fft.png <../../../examples/fft.png>`
- .. image:: img/fftPlotAction.png
:height: 150px
:align: center
- - This script is a simple example of how to create a PlotWindow with a custom
- PlotAction added to the toolbar.
+ - This script is a simple example of how to create a :class:`~silx.gui.plot.PlotWindow`
+ with a custom :class:`~silx.gui.plot.actions.PlotAction` added to the toolbar.
The action computes the FFT of all curves and plots their amplitude spectrum.
It also performs the reverse transform.
@@ -88,35 +191,47 @@ All sample codes can be downloaded as a zip file: |sample_code_archive|.
- how to add your own icon as a PNG file
See shiftPlotAction.py for a simpler example with more basic comments.
- * - :download:`imageview.py <../../../examples/imageview.py>`
- - .. image:: img/imageview.png
+
+Add features to :class:`~silx.gui.plot.PlotWidget`
+..................................................
+
+Sample code that adds specific tools or functions to plot widgets.
+
+.. list-table::
+ :widths: 1 1 4
+ :header-rows: 1
+
+ * - Source
+ - Screenshot
+ - Description
+ * - :download:`plotWidget.py <../../../examples/plotWidget.py>`
+ - .. image:: img/plotWidget.png
:height: 150px
:align: center
- - Example to show the use of `ImageView` widget. It can be used to open an EDF
- or TIFF file from the shell command line.
-
- To view an image file with the current installed silx library:
- ``python examples/imageview.py <file to open>``
- To get help:
- ``python examples/imageview.py -h``
+ - This script shows how to subclass :class:`~silx.gui.plot.PlotWidget` to tune its tools.
- For developers with a git clone you can use it with the bootstrap
- To view an image file with the current installed silx library:
+ It subclasses a :class:`~silx.gui.plot.PlotWidget` and adds toolbars and
+ a colorbar by using pluggable widgets:
- ``./bootstrap.py python examples/imageview.py <file to open>``
+ - QAction from :mod:`silx.gui.plot.actions`
+ - QToolButton from :mod:`silx.gui.plot.PlotToolButtons`
+ - QToolBar from :mod:`silx.gui.plot.PlotTools`
+ - :class:`silx.gui.plot.ColorBar.ColorBarWidget`
* - :download:`plotContextMenu.py <../../../examples/plotContextMenu.py>`
- .. image:: img/plotContextMenu.png
:height: 150px
:align: center
- - This script illustrates the addition of a context menu to a PlotWidget.
+ - This script illustrates the addition of a context menu to a
+ :class:`~silx.gui.plot.PlotWidget`.
This is done by adding a custom context menu to the plot area of PlotWidget:
-
- set the context menu policy of the plot area to Qt.CustomContextMenu.
- connect to the plot area customContextMenuRequested signal.
- The same method works with PlotWindow, Plot1D and Plot2D widgets as they
- inherit from PlotWidget.
+ The same method works with :class:`~silx.gui.plot.PlotWindow.PlotWindow`,
+ :class:`~silx.gui.plot.PlotWindow.Plot1D` and
+ :class:`~silx.gui.plot.PlotWindow.Plot2D` widgets as they
+ inherit from :class:`~silx.gui.plot.PlotWidget`.
For more information on context menus, see Qt documentation.
* - :download:`plotItemsSelector.py <../../../examples/plotItemsSelector.py>`
@@ -124,7 +239,7 @@ All sample codes can be downloaded as a zip file: |sample_code_archive|.
:height: 150px
:align: center
- This example illustrates how to use a :class:`ItemsSelectionDialog` widget
- associated with a :class:`PlotWidget`.
+ associated with a :class:`~silx.gui.plot.PlotWidget`
* - :download:`plotLimits.py <../../../examples/plotLimits.py>`
- .. image:: img/plotLimits.png
:height: 150px
@@ -135,62 +250,35 @@ All sample codes can be downloaded as a zip file: |sample_code_archive|.
- .. image:: img/plotUpdateFromThread.png
:height: 150px
:align: center
- - This script illustrates the update of a silx.gui.plot widget from a thread.
+ - This script illustrates the update of a :mod:`silx.gui.plot` widget from a thread.
The problem is that plot and GUI methods should be called from the main thread.
To safely update the plot from another thread, one need to make the update
asynchronously from the main thread.
In this example, this is achieved through a Qt signal.
- In this example we create a subclass of :class:`silx.gui.plot.Plot1D`
+ In this example we create a subclass of :class:`~silx.gui.plot.PlotWindow.Plot1D`
that adds a thread-safe method to add curves:
:meth:`ThreadSafePlot1D.addCurveThreadSafe`.
- This thread-safe method is then called from a thread to update the plot.
- * - :download:`plotWidget.py <../../../examples/plotWidget.py>`
- - .. image:: img/plotWidget.png
- :height: 150px
- :align: center
- - This script shows how to subclass :class:`PlotWidget` to tune its tools.
-
- It subclasses a :class:`silx.gui.plot.PlotWidget` and adds toolbars and
- a colorbar by using pluggable widgets:
-
- - QAction from :mod:`silx.gui.plot.actions`
- - QToolButton from :mod:`silx.gui.plot.PlotToolButtons`
- - QToolBar from :mod:`silx.gui.plot.PlotTools`
- - :class:`ColorBarWidget` from :mod:`silx.gui.plot.ColorBar`.
+ This thread-safe method is then called from a thread to update the plot..
* - :download:`printPreview.py <../../../examples/printPreview.py>`
- .. image:: img/printPreview.png
:height: 150px
:align: center
- This script illustrates how to add a print preview tool button to any plot
- widget inheriting :class:`PlotWidget`.
+ widget inheriting :class:`~silx.gui.plot.PlotWidget`.
Three plot widgets are instantiated. One of them uses a standalone
- :class:`PrintPreviewToolButton`, while the other two use a
- :class:`SingletonPrintPreviewToolButton` which allows them to send their content
- to the same print preview page.
+ :class:`~silx.gui.plot.PrintPreviewToolButton.PrintPreviewToolButton`,
+ while the other two use a
+ :class:`~silx.gui.plot.PrintPreviewToolButton.SingletonPrintPreviewToolButton`
+ which allows them to send their content to the same print preview page.
* - :download:`scatterMask.py <../../../examples/scatterMask.py>`
- .. image:: img/scatterMask.png
:height: 150px
:align: center
- This example demonstrates how to use ScatterMaskToolsWidget
and NamedScatterAlphaSlider with a PlotWidget.
- * - :download:`shiftPlotAction.py <../../../examples/shiftPlotAction.py>`
- - .. image:: img/shiftPlotAction.png
- :height: 150px
- :align: center
- - This script is a simple (trivial) example of how to create a PlotWindow,
- create a custom :class:`PlotAction` and add it to the toolbar.
-
- The action simply shifts the selected curve up by 1 unit by adding 1 to each
- value of y.
- * - :download:`stackView.py <../../../examples/stackView.py>`
- - .. image:: img/stackView.png
- :height: 150px
- :align: center
- - This script is a simple example to illustrate how to use the StackView
- widget.
* - :download:`syncaxis.py <../../../examples/syncaxis.py>`
- .. image:: img/syncaxis.png
:height: 150px
@@ -198,6 +286,8 @@ All sample codes can be downloaded as a zip file: |sample_code_archive|.
- This script is an example to illustrate how to use axis synchronization
tool.
+.. _plot3d-sample-code:
+
:mod:`silx.gui.plot3d` sample code
++++++++++++++++++++++++++++++++++
@@ -229,6 +319,23 @@ All sample codes can be downloaded as a zip file: |sample_code_archive|.
It loads a 3D scalar data set from a file and displays iso-surfaces and
an interactive cutting plane.
It can also be started without providing a file.
+ * - :download:`plot3dSceneWindow.py <../../../examples/plot3dSceneWindow.py>`
+ - .. image:: img/plot3dSceneWindow.png
+ :height: 150px
+ :align: center
+ - This script displays the different items of :class:`~silx.gui.plot3d.SceneWindow`.
+
+ It shows the different visualizations of :class:`~silx.gui.plot3d.SceneWindow`
+ and :class:`~silx.gui.plot3d.SceneWidget`.
+ It illustrates the API to set those items.
+
+ It features:
+
+ - 2D images: data and RGBA images
+ - 2D scatter data, displayed either as markers, wireframe or surface.
+ - 3D scatter plot
+ - 3D scalar field with iso-surface and cutting plane.
+ - A clipping plane.
:mod:`silx.io` sample code
++++++++++++++++++++++++++
@@ -242,15 +349,5 @@ All sample codes can be downloaded as a zip file: |sample_code_archive|.
- Description
* - :download:`writetoh5.py <../../../examples/writetoh5.py>`
-
- - This script converts a supported data file (SPEC, EDF...) to a HDF5 file.
-
- By default, it creates a new output file or fails if the output file given
- on the command line already exist, but the user can choose to overwrite
- an existing file, or append data to an existing HDF5 file.
-
- In case of appending data to HDF5 files, the user can choose between ignoring
- input data if a corresponding dataset already exists in the output file, or
- overwriting the existing dataset.
-
- By default, new scans are written to the root (/) of the HDF5 file, but it is
- possible to specify a different target path.
+ - This script is an example of how to use the :mod:`silx.io.convert` module.
+ See the following tutorial for more information: :doc:`../Tutorials/convert`
diff --git a/doc/source/tutorials.rst b/doc/source/tutorials.rst
index 97698cd..c4d7daa 100644
--- a/doc/source/tutorials.rst
+++ b/doc/source/tutorials.rst
@@ -9,8 +9,10 @@ Tutorials and cookbooks:
modules/gui/plot/getting_started.rst
modules/gui/plot/actions/examples.rst
modules/gui/designer.rst
- Tutorials/Sift/sift.rst
+ Tutorials/Image
+ Tutorials/Sift/sift
Tutorials/io.rst
+ Tutorials/convert.rst
Tutorials/specfile_to_hdf5.rst
modules/gui/hdf5/getting_started.rst
Tutorials/fit.rst
diff --git a/examples/animatedicons.py b/examples/animatedicons.py
deleted file mode 100644
index 5a5cad6..0000000
--- a/examples/animatedicons.py
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-"""
-Display available project icons using Qt.
-"""
-from silx.gui import qt
-import silx.gui.icons
-import functools
-
-
-class AnimatedToolButton(qt.QToolButton):
- """ToolButton which support animated icons"""
-
- def __init__(self, parent=None):
- super(AnimatedToolButton, self).__init__(parent)
- self.__animatedIcon = None
-
- def setIcon(self, icon):
- if isinstance(icon, silx.gui.icons.AbstractAnimatedIcon):
- self._setAnimatedIcon(icon)
- else:
- self._setAnimatedIcon(None)
- super(AnimatedToolButton, self).setIcon(icon)
-
- def _setAnimatedIcon(self, icon):
- if self.__animatedIcon is not None:
- self.__animatedIcon.unregister(self)
- self.__animatedIcon.iconChanged.disconnect(self.__updateIcon)
- self.__animatedIcon = icon
- if self.__animatedIcon is not None:
- self.__animatedIcon.register(self)
- self.__animatedIcon.iconChanged.connect(self.__updateIcon)
- i = self.__animatedIcon.currentIcon()
- else:
- i = qt.QIcon()
- super(AnimatedToolButton, self).setIcon(i)
-
- def __updateIcon(self, icon):
- super(AnimatedToolButton, self).setIcon(icon)
-
- def icon(self):
- if self.__animatedIcon is not None:
- return self.__animatedIcon
- else:
- return super(AnimatedToolButton, self).icon()
-
-
-class AnimatedIconPreview(qt.QMainWindow):
-
- def __init__(self, *args, **kwargs):
- qt.QMainWindow.__init__(self, *args, **kwargs)
-
- widget = qt.QWidget(self)
- self.iconPanel = self.createIconPanel(widget)
- self.sizePanel = self.createSizePanel(widget)
-
- layout = qt.QVBoxLayout(widget)
- layout.addWidget(self.sizePanel)
- layout.addWidget(self.iconPanel)
- layout.addStretch()
- self.setCentralWidget(widget)
-
- def createSizePanel(self, parent):
- group = qt.QButtonGroup()
- group.setExclusive(True)
- panel = qt.QWidget(parent)
- panel.setLayout(qt.QHBoxLayout())
-
- buttons = {}
- for size in [16, 24, 32]:
- button = qt.QPushButton("%spx" % size, panel)
- button.clicked.connect(functools.partial(self.setIconSize, size))
- button.setCheckable(True)
- panel.layout().addWidget(button)
- group.addButton(button)
- buttons[size] = button
-
- self.__sizeGroup = group
- buttons[24].setChecked(True)
- return panel
-
- def createIconPanel(self, parent):
- panel = qt.QWidget(parent)
- layout = qt.QVBoxLayout()
- panel.setLayout(layout)
-
- self.tools = []
-
- # wait icon
- icon = silx.gui.icons.getWaitIcon()
- tool = AnimatedToolButton(panel)
- tool.setIcon(icon)
- tool.setText("getWaitIcon")
- tool.setToolButtonStyle(qt.Qt.ToolButtonTextBesideIcon)
- self.tools.append(tool)
-
- icon = silx.gui.icons.getAnimatedIcon("process-working")
- tool = AnimatedToolButton(panel)
- tool.setIcon(icon)
- tool.setText("getAnimatedIcon")
- tool.setToolButtonStyle(qt.Qt.ToolButtonTextBesideIcon)
- self.tools.append(tool)
-
- icon = silx.gui.icons.MovieAnimatedIcon("process-working", self)
- tool = AnimatedToolButton(panel)
- tool.setIcon(icon)
- tool.setText("MovieAnimatedIcon")
- tool.setToolButtonStyle(qt.Qt.ToolButtonTextBesideIcon)
- self.tools.append(tool)
-
- icon = silx.gui.icons.MultiImageAnimatedIcon("process-working", self)
- tool = AnimatedToolButton(panel)
- tool.setIcon(icon)
- tool.setText("MultiImageAnimatedIcon")
- tool.setToolButtonStyle(qt.Qt.ToolButtonTextBesideIcon)
- self.tools.append(tool)
-
- for t in self.tools:
- layout.addWidget(t)
-
- return panel
-
- def setIconSize(self, size):
- for tool in self.tools:
- tool.setIconSize(qt.QSize(size, size))
-
-
-if __name__ == "__main__":
- app = qt.QApplication([])
- window = AnimatedIconPreview()
- window.setVisible(True)
- app.exec_()
diff --git a/examples/colormapDialog.py b/examples/colormapDialog.py
new file mode 100644
index 0000000..c663591
--- /dev/null
+++ b/examples/colormapDialog.py
@@ -0,0 +1,272 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This script shows the features of a :mod:`~silx.gui.plot.ColormapDialog`.
+"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "19/01/2018"
+
+import functools
+import numpy
+
+try:
+ import scipy
+except ImportError:
+ scipy = None
+
+from silx.gui import qt
+from silx.gui.plot.ColormapDialog import ColormapDialog
+from silx.gui.plot.Colormap import Colormap
+from silx.gui.plot.ColorBar import ColorBarWidget
+
+
+class ColormapDialogExample(qt.QMainWindow):
+ """PlotWidget with an ad hoc toolbar and a colorbar"""
+
+ def __init__(self, parent=None):
+ super(ColormapDialogExample, self).__init__(parent)
+ self.setWindowTitle("Colormap dialog example")
+
+ self.colormap1 = Colormap("viridis")
+ self.colormap2 = Colormap("gray")
+
+ self.colorBar = ColorBarWidget(self)
+
+ self.colorDialogs = []
+
+ options = qt.QWidget(self)
+ options.setLayout(qt.QVBoxLayout())
+ self.createOptions(options.layout())
+
+ mainWidget = qt.QWidget(self)
+ mainWidget.setLayout(qt.QHBoxLayout())
+ mainWidget.layout().addWidget(options)
+ mainWidget.layout().addWidget(self.colorBar)
+ self.mainWidget = mainWidget
+
+ self.setCentralWidget(mainWidget)
+ self.createColorDialog()
+
+ def createOptions(self, layout):
+ button = qt.QPushButton("Create a new dialog")
+ button.clicked.connect(self.createColorDialog)
+ layout.addWidget(button)
+
+ layout.addSpacing(10)
+
+ button = qt.QPushButton("Set editable")
+ button.clicked.connect(self.setEditable)
+ layout.addWidget(button)
+ button = qt.QPushButton("Set non-editable")
+ button.clicked.connect(self.setNonEditable)
+ layout.addWidget(button)
+
+ layout.addSpacing(10)
+
+ button = qt.QPushButton("Set no colormap")
+ button.clicked.connect(self.setNoColormap)
+ layout.addWidget(button)
+ button = qt.QPushButton("Set colormap 1")
+ button.clicked.connect(self.setColormap1)
+ layout.addWidget(button)
+ button = qt.QPushButton("Set colormap 2")
+ button.clicked.connect(self.setColormap2)
+ layout.addWidget(button)
+ button = qt.QPushButton("Create new colormap")
+ button.clicked.connect(self.setNewColormap)
+ layout.addWidget(button)
+
+ layout.addSpacing(10)
+
+ button = qt.QPushButton("Set no histogram")
+ button.clicked.connect(self.setNoHistogram)
+ layout.addWidget(button)
+ button = qt.QPushButton("Set positive histogram")
+ button.clicked.connect(self.setPositiveHistogram)
+ layout.addWidget(button)
+ button = qt.QPushButton("Set neg-pos histogram")
+ button.clicked.connect(self.setNegPosHistogram)
+ layout.addWidget(button)
+ button = qt.QPushButton("Set negative histogram")
+ button.clicked.connect(self.setNegativeHistogram)
+ layout.addWidget(button)
+
+ layout.addSpacing(10)
+
+ button = qt.QPushButton("Set no range")
+ button.clicked.connect(self.setNoRange)
+ layout.addWidget(button)
+ button = qt.QPushButton("Set positive range")
+ button.clicked.connect(self.setPositiveRange)
+ layout.addWidget(button)
+ button = qt.QPushButton("Set neg-pos range")
+ button.clicked.connect(self.setNegPosRange)
+ layout.addWidget(button)
+ button = qt.QPushButton("Set negative range")
+ button.clicked.connect(self.setNegativeRange)
+ layout.addWidget(button)
+
+ layout.addSpacing(10)
+
+ button = qt.QPushButton("Set no data")
+ button.clicked.connect(self.setNoData)
+ layout.addWidget(button)
+ button = qt.QPushButton("Set shepp logan phantom")
+ button.clicked.connect(self.setSheppLoganPhantom)
+ layout.addWidget(button)
+ button = qt.QPushButton("Set data with non finite")
+ button.clicked.connect(self.setDataWithNonFinite)
+ layout.addWidget(button)
+
+ layout.addStretch()
+
+ def createColorDialog(self):
+ newDialog = ColormapDialog(self)
+ newDialog.finished.connect(functools.partial(self.removeColorDialog, newDialog))
+ self.colorDialogs.append(newDialog)
+ self.mainWidget.layout().addWidget(newDialog)
+
+ def removeColorDialog(self, dialog):
+ self.colorDialogs.remove(dialog)
+
+ def setNoColormap(self):
+ self.colorBar.setColormap(None)
+ for dialog in self.colorDialogs:
+ dialog.setColormap(None)
+
+ def setColormap1(self):
+ self.colorBar.setColormap(self.colormap1)
+ for dialog in self.colorDialogs:
+ dialog.setColormap(self.colormap1)
+
+ def setColormap2(self):
+ self.colorBar.setColormap(self.colormap2)
+ for dialog in self.colorDialogs:
+ dialog.setColormap(self.colormap2)
+
+ def setEditable(self):
+ for dialog in self.colorDialogs:
+ colormap = dialog.getColormap()
+ if colormap is not None:
+ colormap.setEditable(True)
+
+ def setNonEditable(self):
+ for dialog in self.colorDialogs:
+ colormap = dialog.getColormap()
+ if colormap is not None:
+ colormap.setEditable(False)
+
+ def setNewColormap(self):
+ self.colormap = Colormap("inferno")
+ self.colorBar.setColormap(self.colormap)
+ for dialog in self.colorDialogs:
+ dialog.setColormap(self.colormap)
+
+ def setNoHistogram(self):
+ for dialog in self.colorDialogs:
+ dialog.setHistogram()
+
+ def setPositiveHistogram(self):
+ histo = [5, 10, 50, 10, 5]
+ pos = 1
+ edges = list(range(pos, pos + len(histo)))
+ for dialog in self.colorDialogs:
+ dialog.setHistogram(histo, edges)
+
+ def setNegPosHistogram(self):
+ histo = [5, 10, 50, 10, 5]
+ pos = -2
+ edges = list(range(pos, pos + len(histo)))
+ for dialog in self.colorDialogs:
+ dialog.setHistogram(histo, edges)
+
+ def setNegativeHistogram(self):
+ histo = [5, 10, 50, 10, 5]
+ pos = -30
+ edges = list(range(pos, pos + len(histo)))
+ for dialog in self.colorDialogs:
+ dialog.setHistogram(histo, edges)
+
+ def setNoRange(self):
+ for dialog in self.colorDialogs:
+ dialog.setDataRange()
+
+ def setPositiveRange(self):
+ for dialog in self.colorDialogs:
+ dialog.setDataRange(1, 1, 10)
+
+ def setNegPosRange(self):
+ for dialog in self.colorDialogs:
+ dialog.setDataRange(-10, 1, 10)
+
+ def setNegativeRange(self):
+ for dialog in self.colorDialogs:
+ dialog.setDataRange(-10, float("nan"), -1)
+
+ def setNoData(self):
+ for dialog in self.colorDialogs:
+ dialog.setData(None)
+
+ def setSheppLoganPhantom(self):
+ from silx.image import phantomgenerator
+ data = phantomgenerator.PhantomGenerator.get2DPhantomSheppLogan(256)
+ data = data * 1000
+ if scipy is not None:
+ from scipy import ndimage
+ data = ndimage.gaussian_filter(data, sigma=20)
+ data = numpy.random.poisson(data)
+ self.data = data
+ for dialog in self.colorDialogs:
+ dialog.setData(data)
+
+ def setDataWithNonFinite(self):
+ from silx.image import phantomgenerator
+ data = phantomgenerator.PhantomGenerator.get2DPhantomSheppLogan(256)
+ data = data * 1000
+ if scipy is not None:
+ from scipy import ndimage
+ data = ndimage.gaussian_filter(data, sigma=20)
+ data = numpy.random.poisson(data)
+ data[10] = float("nan")
+ data[50] = float("+inf")
+ data[100] = float("-inf")
+ self.data = data
+ for dialog in self.colorDialogs:
+ dialog.setData(data)
+
+
+def main():
+ app = qt.QApplication([])
+
+ # Create the ad hoc plot widget and change its default colormap
+ example = ColormapDialogExample()
+ example.show()
+
+ app.exec_()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/examples/customDataView.py b/examples/customDataView.py
new file mode 100644
index 0000000..6db5c3e
--- /dev/null
+++ b/examples/customDataView.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Qt data view example
+"""
+
+import logging
+import sys
+
+logging.basicConfig()
+_logger = logging.getLogger("customDataView")
+"""Module logger"""
+
+from silx.gui import qt
+from silx.gui.data.DataViewerFrame import DataViewerFrame
+from silx.gui.data.DataViews import DataView
+from silx.third_party import enum
+
+
+class Color(enum.Enum):
+ RED = 1
+ BLUE = 2
+ GREEN = 3
+
+
+class MyColorView(DataView):
+
+ def __init__(self, parent):
+ DataView.__init__(self, parent)
+
+ def label(self):
+ return "Color"
+
+ def icon(self):
+ pixmap = qt.QPixmap(2, 2)
+ painter = qt.QPainter(pixmap)
+ painter.setPen(qt.QColor(255, 0, 0))
+ painter.drawPoint(qt.QPoint(0, 0))
+ painter.setPen(qt.QColor(255, 255, 0))
+ painter.drawPoint(qt.QPoint(1, 0))
+ painter.setPen(qt.QColor(0, 255, 0))
+ painter.drawPoint(qt.QPoint(0, 1))
+ painter.setPen(qt.QColor(0, 255, 255))
+ painter.drawPoint(qt.QPoint(1, 1))
+ painter.end()
+ pixmap = pixmap.scaled(32, 32, qt.Qt.IgnoreAspectRatio, qt.Qt.FastTransformation)
+ return qt.QIcon(pixmap)
+
+ def setData(self, data):
+ widget = self.getWidget()
+ colors = {Color.RED: "#FF0000",
+ Color.GREEN: "#00FF00",
+ Color.BLUE: "#0000FF"}
+ color = colors.get(data, "#000000")
+ text = "<span style='color:%s'>%s</span>" % (color, str(data))
+ widget.setText(text)
+
+ def axesNames(self, data, info):
+ return None
+
+ def createWidget(self, parent):
+ return qt.QLabel(parent)
+
+ def getDataPriority(self, data, info):
+ if isinstance(data, Color):
+ return 100
+ return self.UNSUPPORTED
+
+
+def main():
+ app = qt.QApplication([])
+
+ widget = DataViewerFrame()
+ widget.addView(MyColorView(widget))
+ widget.setData(Color.GREEN)
+ widget.show()
+ result = app.exec_()
+ # remove ending warnings relative to QTimer
+ app.deleteLater()
+ sys.exit(result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/customHdf5TreeModel.py b/examples/customHdf5TreeModel.py
index 8bd444a..fde76c5 100644
--- a/examples/customHdf5TreeModel.py
+++ b/examples/customHdf5TreeModel.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -101,7 +101,6 @@ _file_cache = {}
def get_hdf5_with_all_types():
- global _file_cache
ID = "alltypes"
if ID in _file_cache:
return _file_cache[ID].name
diff --git a/examples/fftPlotAction.py b/examples/fftPlotAction.py
index 66ecfbd..877225f 100755
--- a/examples/fftPlotAction.py
+++ b/examples/fftPlotAction.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,8 +23,8 @@
# THE SOFTWARE.
#
# ###########################################################################*/
-"""This script is a simple example of how to create a PlotWindow with a custom
-PlotAction added to the toolbar.
+"""This script is a simple example of how to create a :class:`~silx.gui.plot.PlotWindow`
+with a custom :class:`~silx.gui.plot.actions.PlotAction` added to the toolbar.
The action computes the FFT of all curves and plots their amplitude spectrum.
It also performs the reverse transform.
@@ -179,7 +179,7 @@ y2 = numpy.cos(twopi * 7 * (x - numpy.pi / 3))
# 5 periods of square wave, amplitude 2
y3 = numpy.zeros_like(x)
for i in [0, 2, 4, 6, 8]:
- y3[i * len(x) / 10:(i + 1) * len(x) / 10] = 2
+ y3[i * len(x) // 10:(i + 1) * len(x) // 10] = 2
plotwin.addCurve(x, y1, legend="sin")
plotwin.addCurve(x, y2, legend="cos")
diff --git a/examples/fileDialog.py b/examples/fileDialog.py
new file mode 100644
index 0000000..9730b9a
--- /dev/null
+++ b/examples/fileDialog.py
@@ -0,0 +1,262 @@
+#!/usr/bin/env python
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+Example for the use of the ImageFileDialog.
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "14/02/2018"
+
+import logging
+from silx.gui import qt
+from silx.gui.dialog.ImageFileDialog import ImageFileDialog
+from silx.gui.dialog.DataFileDialog import DataFileDialog
+import silx.io
+from silx.third_party import enum
+
+
+logging.basicConfig(level=logging.DEBUG)
+
+
+class Mode(enum.Enum):
+ DEFAULT_FILEDIALOG = 0
+ IMAGEFILEDIALOG = 1
+ DATAFILEDIALOG = 2
+ DATAFILEDIALOG_DATASET = 3
+ DATAFILEDIALOG_GROUP = 4
+ DATAFILEDIALOG_NXENTRY = 5
+
+
+class DialogExample(qt.QMainWindow):
+
+ def __init__(self, parent=None):
+ super(DialogExample, self).__init__(parent)
+
+ self.__state = {}
+
+ centralWidget = qt.QWidget(self)
+ layout = qt.QHBoxLayout()
+ centralWidget.setLayout(layout)
+
+ options = self.createOptions()
+ layout.addWidget(options)
+
+ buttonGroup = qt.QGroupBox()
+ buttonGroup.setTitle("Create dialog")
+ layout.addWidget(buttonGroup)
+ buttonLayout = qt.QVBoxLayout()
+ buttonGroup.setLayout(buttonLayout)
+
+ # ImageFileDialog
+
+ b1 = qt.QPushButton(self)
+ b1.setMinimumHeight(50)
+ b1.setText("Open a dialog")
+ b1.clicked.connect(self.openDialog)
+ buttonLayout.addWidget(b1)
+
+ b2 = qt.QPushButton(self)
+ b2.setMinimumHeight(50)
+ b2.setText("Open a dialog with state stored")
+ b2.clicked.connect(self.openDialogStoredState)
+ buttonLayout.addWidget(b2)
+
+ b3 = qt.QPushButton(self)
+ b3.setMinimumHeight(50)
+ b3.setText("Open a dialog at home")
+ b3.clicked.connect(self.openDialogAtHome)
+ buttonLayout.addWidget(b3)
+
+ b4 = qt.QPushButton(self)
+ b4.setMinimumHeight(50)
+ b4.setText("Open a dialog at computer root")
+ b4.clicked.connect(self.openDialogAtComputer)
+ buttonLayout.addWidget(b4)
+
+ self.setCentralWidget(centralWidget)
+
+ def createOptions(self):
+ panel = qt.QGroupBox()
+ panel.setTitle("Options")
+ layout = qt.QVBoxLayout()
+ panel.setLayout(layout)
+ group = qt.QButtonGroup(panel)
+
+ radio = qt.QRadioButton(panel)
+ radio.setText("Qt QFileDialog")
+ radio.setProperty("Mode", Mode.DEFAULT_FILEDIALOG)
+ group.addButton(radio)
+ layout.addWidget(radio)
+
+ radio = qt.QRadioButton(panel)
+ radio.setText("silx ImageFileDialog")
+ radio.setProperty("Mode", Mode.IMAGEFILEDIALOG)
+ group.addButton(radio)
+ layout.addWidget(radio)
+
+ radio = qt.QRadioButton(panel)
+ radio.setChecked(True)
+ radio.setText("silx DataFileDialog")
+ radio.setProperty("Mode", Mode.DATAFILEDIALOG)
+ group.addButton(radio)
+ layout.addWidget(radio)
+
+ radio = qt.QRadioButton(panel)
+ radio.setText("silx DataFileDialog (filter=dataset)")
+ radio.setProperty("Mode", Mode.DATAFILEDIALOG_DATASET)
+ group.addButton(radio)
+ layout.addWidget(radio)
+
+ radio = qt.QRadioButton(panel)
+ radio.setText("silx DataFileDialog (filter=group)")
+ radio.setProperty("Mode", Mode.DATAFILEDIALOG_GROUP)
+ group.addButton(radio)
+ layout.addWidget(radio)
+
+ radio = qt.QRadioButton(panel)
+ radio.setText("silx DataFileDialog (filter=NXentry)")
+ radio.setProperty("Mode", Mode.DATAFILEDIALOG_NXENTRY)
+ group.addButton(radio)
+ layout.addWidget(radio)
+
+ self.__options = group
+ return panel
+
+ def printResult(self, dialog, result):
+ if not result:
+ print("Nothing selected")
+ return
+
+ print("Selection:")
+ if isinstance(dialog, qt.QFileDialog):
+ print("- Files: %s" % dialog.selectedFiles())
+ elif isinstance(dialog, ImageFileDialog):
+ print("- File: %s" % dialog.selectedFile())
+ print("- URL: %s" % dialog.selectedUrl())
+ print("- Data URL: %s" % dialog.selectedDataUrl())
+ image = dialog.selectedImage()
+ print("- Image: <dtype: %s, shape: %s>" % (image.dtype, image.shape))
+ elif isinstance(dialog, DataFileDialog):
+ print("- File: %s" % dialog.selectedFile())
+ print("- URL: %s" % dialog.selectedUrl())
+ print("- Data URL: %s" % dialog.selectedDataUrl())
+ try:
+ data = dialog.selectedData()
+ print("- Data: <dtype: %s, shape: %s>" % (data.dtype, data.shape))
+ except Exception as e:
+ print("- Data: %s" % e)
+
+ url = dialog.selectedDataUrl()
+ with silx.io.open(url.file_path()) as h5:
+ node = h5[url.data_path()]
+ print("- Node: %s" % node)
+ else:
+ assert(False)
+
+ def createDialog(self):
+ print("")
+ print("-------------------------")
+ print("----- Create dialog -----")
+ print("-------------------------")
+ button = self.__options.checkedButton()
+ mode = button.property("Mode")
+ if mode == Mode.DEFAULT_FILEDIALOG:
+ dialog = qt.QFileDialog(self)
+ dialog.setAcceptMode(qt.QFileDialog.AcceptOpen)
+ elif mode == Mode.IMAGEFILEDIALOG:
+ dialog = ImageFileDialog(self)
+ elif mode == Mode.DATAFILEDIALOG:
+ dialog = DataFileDialog(self)
+ elif mode == Mode.DATAFILEDIALOG_DATASET:
+ dialog = DataFileDialog(self)
+ dialog.setFilterMode(DataFileDialog.FilterMode.ExistingDataset)
+ elif mode == Mode.DATAFILEDIALOG_GROUP:
+ dialog = DataFileDialog(self)
+ dialog.setFilterMode(DataFileDialog.FilterMode.ExistingGroup)
+ elif mode == Mode.DATAFILEDIALOG_NXENTRY:
+ def customFilter(obj):
+ if "NX_class" in obj.attrs:
+ return obj.attrs["NX_class"] in [b"NXentry", u"NXentry"]
+ return False
+ dialog = DataFileDialog(self)
+ dialog.setFilterMode(DataFileDialog.FilterMode.ExistingGroup)
+ dialog.setFilterCallback(customFilter)
+ else:
+ assert(False)
+ return dialog
+
+ def openDialog(self):
+ # Clear the dialog
+ dialog = self.createDialog()
+
+ # Execute the dialog as modal
+ result = dialog.exec_()
+ self.printResult(dialog, result)
+
+ def openDialogStoredState(self):
+ # Clear the dialog
+ dialog = self.createDialog()
+ if dialog.__class__ in self.__state:
+ dialog.restoreState(self.__state[dialog.__class__])
+
+ # Execute the dialog as modal
+ result = dialog.exec_()
+ self.__state[dialog.__class__] = dialog.saveState()
+ self.printResult(dialog, result)
+
+ def openDialogAtHome(self):
+ # Clear the dialog
+ path = qt.QDir.homePath()
+ dialog = self.createDialog()
+ dialog.setDirectory(path)
+
+ # Execute the dialog as modal
+ result = dialog.exec_()
+ self.printResult(dialog, result)
+
+ def openDialogAtComputer(self):
+ # Clear the dialog
+ path = ""
+ dialog = self.createDialog()
+ dialog.setDirectory(path)
+
+ # Execute the dialog as modal
+ result = dialog.exec_()
+ self.printResult(dialog, result)
+
+
+def main():
+ app = qt.QApplication([])
+ example = DialogExample()
+ example.show()
+ app.exec_()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/hdf5widget.py b/examples/hdf5widget.py
index 95607ff..7a8e7ae 100755
--- a/examples/hdf5widget.py
+++ b/examples/hdf5widget.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -50,6 +50,7 @@ import h5py
import silx.gui.hdf5
import silx.utils.html
+from silx.third_party import six
from silx.gui import qt
from silx.gui.data.DataViewerFrame import DataViewerFrame
from silx.gui.widgets.ThreadPoolPushButton import ThreadPoolPushButton
@@ -62,8 +63,13 @@ except ImportError:
_file_cache = {}
+def str_attrs(str_list):
+ """Return a numpy array of unicode strings"""
+ text_dtype = h5py.special_dtype(vlen=six.text_type)
+ return numpy.array(str_list, dtype=text_dtype)
+
+
def get_hdf5_with_all_types():
- global _file_cache
ID = "alltypes"
if ID in _file_cache:
return _file_cache[ID].name
@@ -105,7 +111,6 @@ def get_hdf5_with_all_types():
def get_hdf5_with_all_links():
- global _file_cache
ID = "alllinks"
if ID in _file_cache:
return _file_cache[ID].name
@@ -138,7 +143,6 @@ def get_hdf5_with_all_links():
def get_hdf5_with_1000_datasets():
- global _file_cache
ID = "dataset1000"
if ID in _file_cache:
return _file_cache[ID].name
@@ -157,7 +161,6 @@ def get_hdf5_with_1000_datasets():
def get_hdf5_with_10000_datasets():
- global _file_cache
ID = "dataset10000"
if ID in _file_cache:
return _file_cache[ID].name
@@ -176,7 +179,6 @@ def get_hdf5_with_10000_datasets():
def get_hdf5_with_100000_datasets():
- global _file_cache
ID = "dataset100000"
if ID in _file_cache:
return _file_cache[ID].name
@@ -195,7 +197,6 @@ def get_hdf5_with_100000_datasets():
def get_hdf5_with_recursive_links():
- global _file_cache
ID = "recursive_links"
if ID in _file_cache:
return _file_cache[ID].name
@@ -222,7 +223,6 @@ def get_hdf5_with_recursive_links():
def get_hdf5_with_external_recursive_links():
- global _file_cache
ID = "external_recursive_links"
if ID in _file_cache:
return _file_cache[ID][0].name
@@ -254,7 +254,6 @@ def get_hdf5_with_external_recursive_links():
def get_hdf5_with_nxdata():
- global _file_cache
ID = "nxdata"
if ID in _file_cache:
return _file_cache[ID].name
@@ -267,50 +266,55 @@ def get_hdf5_with_nxdata():
g0d = h5.create_group("scalars")
g0d0 = g0d.create_group("0D_scalar")
- g0d0.attrs["NX_class"] = "NXdata"
- g0d0.attrs["signal"] = "scalar"
+ g0d0.attrs["NX_class"] = u"NXdata"
+ g0d0.attrs["signal"] = u"scalar"
g0d0.create_dataset("scalar", data=10)
g0d1 = g0d.create_group("2D_scalars")
- g0d1.attrs["NX_class"] = "NXdata"
- g0d1.attrs["signal"] = "scalars"
+ g0d1.attrs["NX_class"] = u"NXdata"
+ g0d1.attrs["signal"] = u"scalars"
ds = g0d1.create_dataset("scalars", data=numpy.arange(3*10).reshape((3, 10)))
- ds.attrs["interpretation"] = "scalar"
+ ds.attrs["interpretation"] = u"scalar"
g0d1 = g0d.create_group("4D_scalars")
- g0d1.attrs["NX_class"] = "NXdata"
- g0d1.attrs["signal"] = "scalars"
+ g0d1.attrs["NX_class"] = u"NXdata"
+ g0d1.attrs["signal"] = u"scalars"
ds = g0d1.create_dataset("scalars", data=numpy.arange(2*2*3*10).reshape((2, 2, 3, 10)))
- ds.attrs["interpretation"] = "scalar"
+ ds.attrs["interpretation"] = u"scalar"
# SPECTRA
g1d = h5.create_group("spectra")
g1d0 = g1d.create_group("1D_spectrum")
- g1d0.attrs["NX_class"] = "NXdata"
- g1d0.attrs["signal"] = "count"
- g1d0.attrs["axes"] = "energy_calib"
- g1d0.attrs["uncertainties"] = b"energy_errors",
+ g1d0.attrs["NX_class"] = u"NXdata"
+ g1d0.attrs["signal"] = u"count"
+ g1d0.attrs["auxiliary_signals"] = str_attrs(["count.5", "count2"])
+ g1d0.attrs["axes"] = u"energy_calib"
+ g1d0.attrs["uncertainties"] = str_attrs(["energy_errors"])
g1d0.create_dataset("count", data=numpy.arange(10))
+ g1d0.create_dataset("count.5", data=.5*numpy.arange(10))
+ d2 = g1d0.create_dataset("count2", data=2*numpy.arange(10))
+ d2.attrs["long_name"] = u"count multiplied by 2"
g1d0.create_dataset("energy_calib", data=(10, 5)) # 10 * idx + 5
g1d0.create_dataset("energy_errors", data=3.14*numpy.random.rand(10))
+ g1d0.create_dataset("title", data="Title example provided as dataset")
g1d1 = g1d.create_group("2D_spectra")
- g1d1.attrs["NX_class"] = "NXdata"
- g1d1.attrs["signal"] = "counts"
+ g1d1.attrs["NX_class"] = u"NXdata"
+ g1d1.attrs["signal"] = u"counts"
ds = g1d1.create_dataset("counts", data=numpy.arange(3*10).reshape((3, 10)))
- ds.attrs["interpretation"] = "spectrum"
+ ds.attrs["interpretation"] = u"spectrum"
g1d2 = g1d.create_group("4D_spectra")
- g1d2.attrs["NX_class"] = "NXdata"
- g1d2.attrs["signal"] = "counts"
- g1d2.attrs["axes"] = b"energy",
+ g1d2.attrs["NX_class"] = u"NXdata"
+ g1d2.attrs["signal"] = u"counts"
+ g1d2.attrs["axes"] = str_attrs(["energy"])
ds = g1d2.create_dataset("counts", data=numpy.arange(2*2*3*10).reshape((2, 2, 3, 10)))
- ds.attrs["interpretation"] = "spectrum"
- ds = g1d2.create_dataset("errors", data=4.5*numpy.random.rand(2, 2, 3, 10))
+ ds.attrs["interpretation"] = u"spectrum"
+ g1d2.create_dataset("errors", data=4.5*numpy.random.rand(2, 2, 3, 10))
ds = g1d2.create_dataset("energy", data=5+10*numpy.arange(15),
shuffle=True, compression="gzip")
- ds.attrs["long_name"] = "Calibrated energy"
+ ds.attrs["long_name"] = u"Calibrated energy"
ds.attrs["first_good"] = 3
ds.attrs["last_good"] = 12
g1d2.create_dataset("energy_errors", data=10*numpy.random.rand(15))
@@ -319,34 +323,54 @@ def get_hdf5_with_nxdata():
g2d = h5.create_group("images")
g2d0 = g2d.create_group("2D_regular_image")
- g2d0.attrs["NX_class"] = "NXdata"
- g2d0.attrs["signal"] = "image"
- g2d0.attrs["axes"] = b"rows_calib", b"columns_coordinates"
+ g2d0.attrs["NX_class"] = u"NXdata"
+ g2d0.attrs["signal"] = u"image"
+ g2d0.attrs["auxiliary_signals"] = str_attrs(["image2", "image3"])
+ g2d0.attrs["axes"] = str_attrs(["rows_calib", "columns_coordinates"])
+ g2d0.attrs["title"] = u"Title example provided as group attr"
g2d0.create_dataset("image", data=numpy.arange(4*6).reshape((4, 6)))
+ g2d0.create_dataset("image2", data=1/(1.+numpy.arange(4*6).reshape((4, 6))))
+ ds = g2d0.create_dataset("image3", data=-numpy.arange(4*6).reshape((4, 6)))
+ ds.attrs["long_name"] = u"3rd image (2nd auxiliary)"
ds = g2d0.create_dataset("rows_calib", data=(10, 5))
- ds.attrs["long_name"] = "Calibrated Y"
+ ds.attrs["long_name"] = u"Calibrated Y"
g2d0.create_dataset("columns_coordinates", data=0.5+0.02*numpy.arange(6))
+ g2d4 = g2d.create_group("RGBA_image")
+ g2d4.attrs["NX_class"] = u"NXdata"
+ g2d4.attrs["signal"] = u"image"
+ g2d4.attrs["auxiliary_signals"] = u"squared image"
+ g2d4.attrs["axes"] = str_attrs(["rows_calib", "columns_coordinates"])
+ rgba_image = numpy.linspace(0, 1, num=7*8*3).reshape((7, 8, 3))
+ rgba_image[:, :, 1] = 1 - rgba_image[:, :, 1] # invert G channel to add some color
+ ds = g2d4.create_dataset("image", data=rgba_image)
+ ds.attrs["interpretation"] = u"rgba-image"
+ ds = g2d4.create_dataset("squared image", data=rgba_image**2)
+ ds.attrs["interpretation"] = u"rgba-image"
+ ds = g2d4.create_dataset("rows_calib", data=(10, 5))
+ ds.attrs["long_name"] = u"Calibrated Y"
+ g2d4.create_dataset("columns_coordinates", data=0.5+0.02*numpy.arange(8))
+
g2d1 = g2d.create_group("2D_irregular_data")
- g2d1.attrs["NX_class"] = "NXdata"
- g2d1.attrs["signal"] = "data"
- g2d1.attrs["axes"] = b"rows_coordinates", b"columns_coordinates"
+ g2d1.attrs["NX_class"] = u"NXdata"
+ g2d1.attrs["signal"] = u"data"
+ g2d1.attrs["axes"] = str_attrs(["rows_coordinates", "columns_coordinates"])
g2d1.create_dataset("data", data=numpy.arange(64*128).reshape((64, 128)))
g2d1.create_dataset("rows_coordinates", data=numpy.arange(64) + numpy.random.rand(64))
g2d1.create_dataset("columns_coordinates", data=numpy.arange(128) + 2.5 * numpy.random.rand(128))
g2d2 = g2d.create_group("3D_images")
- g2d2.attrs["NX_class"] = "NXdata"
- g2d2.attrs["signal"] = "images"
+ g2d2.attrs["NX_class"] = u"NXdata"
+ g2d2.attrs["signal"] = u"images"
ds = g2d2.create_dataset("images", data=numpy.arange(2*4*6).reshape((2, 4, 6)))
- ds.attrs["interpretation"] = "image"
+ ds.attrs["interpretation"] = u"image"
g2d3 = g2d.create_group("5D_images")
- g2d3.attrs["NX_class"] = "NXdata"
- g2d3.attrs["signal"] = "images"
- g2d3.attrs["axes"] = b"rows_coordinates", b"columns_coordinates"
+ g2d3.attrs["NX_class"] = u"NXdata"
+ g2d3.attrs["signal"] = u"images"
+ g2d3.attrs["axes"] = str_attrs(["rows_coordinates", "columns_coordinates"])
ds = g2d3.create_dataset("images", data=numpy.arange(2*2*2*4*6).reshape((2, 2, 2, 4, 6)))
- ds.attrs["interpretation"] = "image"
+ ds.attrs["interpretation"] = u"image"
g2d3.create_dataset("rows_coordinates", data=5+10*numpy.arange(4))
g2d3.create_dataset("columns_coordinates", data=0.5+0.02*numpy.arange(6))
@@ -354,42 +378,65 @@ def get_hdf5_with_nxdata():
g = h5.create_group("scatters")
gd0 = g.create_group("x_y_scatter")
- gd0.attrs["NX_class"] = "NXdata"
- gd0.attrs["signal"] = "y"
- gd0.attrs["axes"] = b"x",
+ gd0.attrs["NX_class"] = u"NXdata"
+ gd0.attrs["signal"] = u"y"
+ gd0.attrs["axes"] = str_attrs(["x"])
+ gd0.attrs["title"] = u"simple y = f(x) scatters cannot be distinguished from curves"
gd0.create_dataset("y", data=numpy.random.rand(128) - 0.5)
gd0.create_dataset("x", data=2*numpy.random.rand(128))
gd0.create_dataset("x_errors", data=0.05*numpy.random.rand(128))
gd0.create_dataset("errors", data=0.05*numpy.random.rand(128))
gd1 = g.create_group("x_y_value_scatter")
- gd1.attrs["NX_class"] = "NXdata"
- gd1.attrs["signal"] = "values"
- gd1.attrs["axes"] = b"x", b"y"
+ gd1.attrs["NX_class"] = u"NXdata"
+ gd1.attrs["signal"] = u"values"
+ gd1.attrs["auxiliary_signals"] = str_attrs(["values.5", "values2"])
+ gd1.attrs["axes"] = str_attrs(["x", "y"])
+ gd1.attrs["title"] = u"x, y, values scatter with asymmetric y_errors"
gd1.create_dataset("values", data=3.14*numpy.random.rand(128))
+ gd1.create_dataset("values.5", data=0.5*3.14*numpy.random.rand(128))
+ gd1.create_dataset("values2", data=2.*3.14*numpy.random.rand(128))
gd1.create_dataset("y", data=numpy.random.rand(128))
- gd1.create_dataset("y_errors", data=0.02*numpy.random.rand(128))
- gd1.create_dataset("x", data=numpy.random.rand(128))
+ y_errors = [0.03*numpy.random.rand(128), 0.04*numpy.random.rand(128)]
+ gd1.create_dataset("y_errors", data=y_errors)
+ ds = gd1.create_dataset("x", data=2*numpy.random.rand(128))
+ ds.attrs["long_name"] = u"horizontal axis"
gd1.create_dataset("x_errors", data=0.02*numpy.random.rand(128))
# NDIM > 3
g = h5.create_group("cubes")
gd0 = g.create_group("3D_cube")
- gd0.attrs["NX_class"] = "NXdata"
- gd0.attrs["signal"] = "cube"
- gd0.attrs["axes"] = b"img_idx", b"rows_coordinates", b"cols_coordinates"
+ gd0.attrs["NX_class"] = u"NXdata"
+ gd0.attrs["signal"] = u"cube"
+ gd0.attrs["axes"] = str_attrs(["img_idx", "rows_coordinates", "cols_coordinates"])
gd0.create_dataset("cube", data=numpy.arange(4*5*6).reshape((4, 5, 6)))
gd0.create_dataset("img_idx", data=numpy.arange(4))
gd0.create_dataset("rows_coordinates", data=0.1*numpy.arange(5))
gd0.create_dataset("cols_coordinates", data=[0.2, 0.3]) # linear calibration
gd1 = g.create_group("5D")
- gd1.attrs["NX_class"] = "NXdata"
- gd1.attrs["signal"] = "hypercube"
+ gd1.attrs["NX_class"] = u"NXdata"
+ gd1.attrs["signal"] = u"hypercube"
gd1.create_dataset("hypercube",
data=numpy.arange(2*3*4*5*6).reshape((2, 3, 4, 5, 6)))
+ # invalid NXdata
+ g = h5.create_group("invalid")
+ g0 = g.create_group("invalid NXdata")
+ g0.attrs["NX_class"] = u"NXdata"
+
+ g1 = g.create_group("invalid NXentry")
+ g1.attrs["NX_class"] = u"NXentry"
+ g1.attrs["default"] = u"missing NXdata group"
+
+ g2 = g.create_group("invalid NXroot")
+ g2.attrs["NX_class"] = u"NXroot"
+ g2.attrs["default"] = u"invalid NXentry in NXroot"
+ g20 = g2.create_group("invalid NXentry in NXroot")
+ g20.attrs["NX_class"] = u"NXentry"
+ g20.attrs["default"] = u"missing NXdata group"
+
h5.close()
_file_cache[ID] = tmp
@@ -397,7 +444,6 @@ def get_hdf5_with_nxdata():
def get_edf_with_all_types():
- global _file_cache
ID = "alltypesedf"
if ID in _file_cache:
return _file_cache[ID].name
@@ -422,7 +468,6 @@ def get_edf_with_all_types():
def get_edf_with_100000_frames():
- global _file_cache
ID = "frame100000"
if ID in _file_cache:
return _file_cache[ID].name
@@ -586,7 +631,7 @@ class Hdf5TreeViewExample(qt.QMainWindow):
hasDataset = True
break
- if len(menu.children()):
+ if not menu.isEmpty():
menu.addSeparator()
if hasDataset:
@@ -602,7 +647,7 @@ class Hdf5TreeViewExample(qt.QMainWindow):
selectedObjects = event.source().selectedH5Nodes()
menu = event.menu()
- if len(menu.children()):
+ if not menu.isEmpty():
menu.addSeparator()
for obj in selectedObjects:
diff --git a/examples/icons.py b/examples/icons.py
index a6f0ada..673ca6f 100644
--- a/examples/icons.py
+++ b/examples/icons.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,12 +24,52 @@
#
# ###########################################################################*/
"""
-Display available project icons using Qt.
+Display icons available in silx.
"""
+
import functools
+import os.path
from silx.gui import qt
import silx.gui.icons
+import silx.resources
+
+
+class AnimatedToolButton(qt.QToolButton):
+ """ToolButton which support animated icons"""
+
+ def __init__(self, parent=None):
+ super(AnimatedToolButton, self).__init__(parent)
+ self.__animatedIcon = None
+
+ def setIcon(self, icon):
+ if isinstance(icon, silx.gui.icons.AbstractAnimatedIcon):
+ self._setAnimatedIcon(icon)
+ else:
+ self._setAnimatedIcon(None)
+ super(AnimatedToolButton, self).setIcon(icon)
+
+ def _setAnimatedIcon(self, icon):
+ if self.__animatedIcon is not None:
+ self.__animatedIcon.unregister(self)
+ self.__animatedIcon.iconChanged.disconnect(self.__updateIcon)
+ self.__animatedIcon = icon
+ if self.__animatedIcon is not None:
+ self.__animatedIcon.register(self)
+ self.__animatedIcon.iconChanged.connect(self.__updateIcon)
+ i = self.__animatedIcon.currentIcon()
+ else:
+ i = qt.QIcon()
+ super(AnimatedToolButton, self).setIcon(i)
+
+ def __updateIcon(self, icon):
+ super(AnimatedToolButton, self).setIcon(icon)
+
+ def icon(self):
+ if self.__animatedIcon is not None:
+ return self.__animatedIcon
+ else:
+ return super(AnimatedToolButton, self).icon()
class IconPreview(qt.QMainWindow):
@@ -66,6 +106,28 @@ class IconPreview(qt.QMainWindow):
button.setChecked(True)
return panel
+ def getAllAvailableIcons(self):
+ def isAnIcon(name):
+ if silx.resources.is_dir("gui/icons/" + name):
+ return False
+ _, ext = os.path.splitext(name)
+ return ext in [".svg", ".png"]
+ icons = silx.resources.list_dir("gui/icons")
+ # filter out sub-directories
+ icons = filter(isAnIcon, icons)
+ # remove extension
+ icons = [i.split(".")[0] for i in icons]
+ # remove duplicated names
+ icons = set(icons)
+ # sort by names
+ return icons
+
+ def getAllAvailableAnimatedIcons(self):
+ icons = silx.resources.list_dir("gui/icons")
+ icons = filter(lambda x: silx.resources.exists("gui/icons/%s/00.png" % x), icons)
+ icons = filter(lambda x: not silx.resources.is_dir("gui/icons/%s/00.png" % x), icons)
+ return icons
+
def createIconPanel(self, parent):
panel = qt.QWidget(parent)
layout = qt.QGridLayout()
@@ -74,25 +136,33 @@ class IconPreview(qt.QMainWindow):
self.tools = []
- import silx.resources
-
- icons = silx.resources.list_dir("gui/icons")
- # filter out sub-directories
- icons = filter(lambda x: not silx.resources.is_dir("gui/icons/" + x), icons)
- # remove extension
- icons = [i.split(".")[0] for i in icons]
- # remove duplicated names
- icons = set(icons)
- # sort by names
+ # Sort together animated and non animated icons
+ fix_icons = self.getAllAvailableIcons()
+ animated_icons = self.getAllAvailableAnimatedIcons()
+ icons = []
+ icons.extend([(i, "_") for i in fix_icons])
+ icons.extend([(i, "anim") for i in animated_icons])
icons = sorted(icons)
- for i, icon_name in enumerate(icons):
+ for i, icon_info in enumerate(icons):
+ icon_name, icon_kind = icon_info
col, line = i / 10, i % 10
- icon = silx.gui.icons.getQIcon(icon_name)
- tool = qt.QToolButton(panel)
+ if icon_kind == "anim":
+ tool = AnimatedToolButton(panel)
+ try:
+ icon = silx.gui.icons.getAnimatedIcon(icon_name)
+ except ValueError:
+ icon = qt.QIcon()
+ tool.setToolTip("Animated icon '%s'" % icon_name)
+ else:
+ tool = qt.QToolButton(panel)
+ try:
+ icon = silx.gui.icons.getQIcon(icon_name)
+ except ValueError:
+ icon = qt.QIcon()
+ tool.setToolTip("Icon '%s'" % icon_name)
tool.setIcon(icon)
tool.setIconSize(qt.QSize(32, 32))
- tool.setToolTip(icon_name)
layout.addWidget(tool, col, line)
self.tools.append(tool)
diff --git a/examples/imageview.py b/examples/imageview.py
index 34595e2..c4f80bd 100755
--- a/examples/imageview.py
+++ b/examples/imageview.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,8 +24,9 @@
#
# ###########################################################################*/
"""
-Example to show the use of `ImageView` widget. It can be used to open an EDF
-or TIFF file from the shell command line.
+Example to show the use of :class:`~silx.gui.plot.ImageView.ImageView` widget.
+
+It can be used to open an EDF or TIFF file from the shell command line.
To view an image file with the current installed silx library:
``python examples/imageview.py <file to open>``
diff --git a/examples/plot3dSceneWindow.py b/examples/plot3dSceneWindow.py
new file mode 100644
index 0000000..efffcd3
--- /dev/null
+++ b/examples/plot3dSceneWindow.py
@@ -0,0 +1,197 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This script displays the different items of :class:`~silx.gui.plot3d.SceneWindow`.
+
+It shows the different visualizations of :class:`~silx.gui.plot3d.SceneWindow`
+and :class:`~silx.gui.plot3d.SceneWidget`.
+It illustrates the API to set those items.
+
+It features:
+
+- 2D images: data and RGBA images
+- 2D scatter data, displayed either as markers, wireframe or surface.
+- 3D scatter plot
+- 3D scalar field with iso-surface and cutting plane.
+- A clipping plane.
+
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "17/11/2017"
+
+import numpy
+
+from silx.gui import qt
+from silx.gui.plot3d.SceneWindow import SceneWindow, items
+
+SIZE = 1024
+
+# Create QApplication
+qapp = qt.QApplication([])
+
+# Create a SceneWindow widget
+window = SceneWindow()
+
+# Get the SceneWidget contained in the window and set its colors
+sceneWidget = window.getSceneWidget()
+sceneWidget.setBackgroundColor((0.8, 0.8, 0.8, 1.))
+sceneWidget.setForegroundColor((1., 1., 1., 1.))
+sceneWidget.setTextColor((0.1, 0.1, 0.1, 1.))
+
+
+# 2D Image ###
+
+# Add a dummy RGBA image
+img = numpy.random.random(3 * SIZE ** 2).reshape(SIZE, SIZE, 3) # Dummy image
+
+imageRgba = sceneWidget.addImage(img) # Add ImageRgba item to the scene
+
+# Set imageRgba transform
+imageRgba.setTranslation(SIZE*.15, SIZE*.15, 0.) # Translate the image
+# Rotate the image by 45 degrees around its center
+imageRgba.setRotationCenter('center', 'center', 0.)
+imageRgba.setRotation(45., axis=(0., 0., 1.))
+imageRgba.setScale(0.7, 0.7, 0.7) # Scale down image
+
+
+# Add a data image
+data = numpy.arange(SIZE ** 2).reshape(SIZE, SIZE) # Dummy data
+imageData = sceneWidget.addImage(data) # Add ImageData item to the scene
+
+# Set imageData transform
+imageData.setTranslation(0., SIZE, 0.) # Translate the image
+
+# Set imageData properties
+imageData.setInterpolation('linear') # 'linear' or 'nearest' interpolation
+imageData.getColormap().setName('magma') # Use magma colormap
+
+
+# 2D scatter data ###
+
+# Create 2D scatter dummy data
+x = numpy.random.random(10 ** 3)
+y = numpy.random.random(len(x))
+values = numpy.exp(- 11. * ((x - .5) ** 2 + (y - .5) ** 2))
+
+# Add 2D scatter data with 6 different visualisations
+for row, heightMap in enumerate((False, True)):
+ for col, mode in enumerate(('points', 'lines', 'solid')):
+ # Add a new scatter
+ item = sceneWidget.add2DScatter(x, y, values)
+
+ # Set 2D scatter item tranform
+ item.setTranslation(SIZE + col * SIZE, row * SIZE, 0.)
+ item.setScale(SIZE, SIZE, SIZE)
+
+ # Set 2D scatter item properties
+ item.setHeightMap(heightMap)
+ item.setVisualization(mode)
+ item.getColormap().setName('viridis')
+ item.setLineWidth(2.)
+
+
+# Group ###
+
+# Create a group item and add it to the scene
+# The group children share the group transform
+group = items.GroupItem() # Create a new group item
+group.setTranslation(SIZE * 4, 0., 0.) # Translate the group
+
+
+# Clipping plane ###
+
+# Add a clipping plane to the group (and thus to the scene)
+# This item hides part of other items in the half space defined by the plane.
+# Clipped items are those belonging to the same group (i.e., brothers) that
+# comes after the clipping plane.
+clipPlane = items.ClipPlane() # Create a new clipping plane item
+clipPlane.setNormal((1., -0.35, 0.)) # Set its normal
+clipPlane.setPoint((0., 0., 0.)) # Set a point on the plane
+group.addItem(clipPlane) # Add clipping plane to the group
+
+
+# 3D scatter data ###
+
+# Create dummy data
+x = numpy.random.random(10**3)
+y = numpy.random.random(len(x))
+z = numpy.random.random(len(x))
+values = numpy.random.random(len(x))
+
+# Create a 3D scatter item and set its data
+scatter3d = items.Scatter3D()
+scatter3d.setData(x, y, z, values)
+
+# Set scatter3d transform
+scatter3d.setScale(SIZE, SIZE, SIZE)
+
+# Set scatter3d properties
+scatter3d.getColormap().setName('magma') # Use 'magma' colormap
+scatter3d.setSymbol('d') # Use diamond markers
+scatter3d.setSymbolSize(11) # Set the size of the markers
+
+# Add scatter3d to the group (and thus to the scene)
+group.addItem(scatter3d)
+
+
+# 3D scalar volume ###
+
+# Create dummy 3D array data
+x, y, z = numpy.meshgrid(numpy.linspace(-10, 10, 64),
+ numpy.linspace(-10, 10, 64),
+ numpy.linspace(-10, 10, 64))
+data = numpy.sin(x * y * z) / (x * y * z)
+
+# Create a 3D scalar field item and set its data
+volume = items.ScalarField3D() # Create a new 3D volume item
+volume.setData(data) # Set its data
+group.addItem(volume) # Add it to the group (and thus to the scene)
+
+# Set volume tranform
+volume.setTranslation(0., SIZE, 0.)
+volume.setScale(SIZE/data.shape[2], SIZE/data.shape[1], SIZE/data.shape[0])
+
+# Add isosurfaces to the volume item given isolevel and color
+volume.addIsosurface(0.2, '#FF000080')
+volume.addIsosurface(0.5, '#0000FFFF')
+
+# Set the volume cut plane
+cutPlane = volume.getCutPlanes()[0] # Get the volume's cut plane
+cutPlane.setVisible(True) # Set it to be visible
+cutPlane.getColormap().setName('jet') # Set cut plane's colormap
+cutPlane.setNormal((0., 0., 1.)) # Set cut plane's normal
+cutPlane.moveToCenter() # Place the cut plane at the center of the volume
+
+sceneWidget.addItem(group) # Add the group as an item of the scene
+
+# Show the SceneWidget widget
+window.show()
+
+# Run Qt event loop
+qapp.exec_()
diff --git a/examples/plotClearAction.py b/examples/plotClearAction.py
new file mode 100644
index 0000000..e1130cb
--- /dev/null
+++ b/examples/plotClearAction.py
@@ -0,0 +1,75 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This script shows how to create a minimalistic
+:class:`~silx.gui.plot.actions.PlotAction` that clear the plot.
+
+This illustrates how to add more buttons in a plot widget toolbar.
+"""
+
+__authors__ = ["T. VINCENT"]
+__license__ = "MIT"
+__date__ = "14/02/2018"
+
+
+from silx.gui.plot.actions import PlotAction
+
+
+class ClearPlotAction(PlotAction):
+ """A QAction that can be added to PlotWidget toolbar to clear the plot"""
+
+ def __init__(self, plot, parent=None):
+ super(ClearPlotAction, self).__init__(
+ plot,
+ icon='close',
+ text='Clear',
+ tooltip='Clear the plot',
+ triggered=self._clear,
+ parent=parent)
+
+ def _clear(self):
+ """Handle action triggered and clear the plot"""
+ self.plot.clear()
+
+
+if __name__ == '__main__':
+ from silx.gui import qt
+ from silx.gui.plot import Plot1D
+
+ app = qt.QApplication([]) # First create QApplication
+
+ plot = Plot1D() # Create plotting widget
+
+ # Create a toolbar and add it to the plot widget
+ toolbar = qt.QToolBar()
+ plot.addToolBar(toolbar)
+
+ # Create clear action and add it to the toolbar
+ action = ClearPlotAction(plot, parent=plot)
+ toolbar.addAction(action)
+
+ plot.addCurve((0, 1, 2, 3, 4), (0, 1, 1.5, 1, 0)) # Add a curve to the plot
+
+ plot.show() # Show the plot widget
+ app.exec_() # Start Qt application
diff --git a/examples/plotContextMenu.py b/examples/plotContextMenu.py
index 3e9af1e..5f02f5f 100644
--- a/examples/plotContextMenu.py
+++ b/examples/plotContextMenu.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,14 +23,17 @@
# THE SOFTWARE.
#
# ###########################################################################*/
-"""This script illustrates the addition of a context menu to a PlotWidget.
+"""This script illustrates the addition of a context menu to a
+:class:`~silx.gui.plot.PlotWidget`.
This is done by adding a custom context menu to the plot area of PlotWidget:
- set the context menu policy of the plot area to Qt.CustomContextMenu.
- connect to the plot area customContextMenuRequested signal.
-The same method works with PlotWindow, Plot1D and Plot2D widgets as they
-inherit from PlotWidget.
+The same method works with :class:`~silx.gui.plot.PlotWindow.PlotWindow`,
+:class:`~silx.gui.plot.PlotWindow.Plot1D` and
+:class:`~silx.gui.plot.PlotWindow.Plot2D` widgets as they
+inherit from :class:`~silx.gui.plot.PlotWidget`.
For more information on context menus, see Qt documentation.
"""
diff --git a/examples/plotItemsSelector.py b/examples/plotItemsSelector.py
index 8f29457..458bbeb 100755
--- a/examples/plotItemsSelector.py
+++ b/examples/plotItemsSelector.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,7 +24,7 @@
#
# ###########################################################################*/
"""This example illustrates how to use a :class:`ItemsSelectionDialog` widget
-associated with a :class:`PlotWidget`.
+associated with a :class:`~silx.gui.plot.PlotWidget`.
"""
__authors__ = ["P. Knobel"]
diff --git a/examples/plotUpdateFromThread.py b/examples/plotUpdateFromThread.py
index d36bc48..36df63f 100644
--- a/examples/plotUpdateFromThread.py
+++ b/examples/plotUpdateFromThread.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -22,14 +22,14 @@
# THE SOFTWARE.
#
# ###########################################################################*/
-"""This script illustrates the update of a silx.gui.plot widget from a thread.
+"""This script illustrates the update of a :mod:`silx.gui.plot` widget from a thread.
The problem is that plot and GUI methods should be called from the main thread.
To safely update the plot from another thread, one need to make the update
asynchronously from the main thread.
In this example, this is achieved through a Qt signal.
-In this example we create a subclass of :class:`silx.gui.plot.Plot1D`
+In this example we create a subclass of :class:`~silx.gui.plot.PlotWindow.Plot1D`
that adds a thread-safe method to add curves:
:meth:`ThreadSafePlot1D.addCurveThreadSafe`.
This thread-safe method is then called from a thread to update the plot.
diff --git a/examples/plotWidget.py b/examples/plotWidget.py
index 698fe56..24de519 100644
--- a/examples/plotWidget.py
+++ b/examples/plotWidget.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -22,15 +22,15 @@
# THE SOFTWARE.
#
# ###########################################################################*/
-"""This script shows how to subclass :class:`PlotWidget` to tune its tools.
+"""This script shows how to subclass :class:`~silx.gui.plot.PlotWidget` to tune its tools.
-It subclasses a :class:`silx.gui.plot.PlotWidget` and adds toolbars and
+It subclasses a :class:`~silx.gui.plot.PlotWidget` and adds toolbars and
a colorbar by using pluggable widgets:
- QAction from :mod:`silx.gui.plot.actions`
- QToolButton from :mod:`silx.gui.plot.PlotToolButtons`
- QToolBar from :mod:`silx.gui.plot.PlotTools`
-- :class:`ColorBarWidget` from :mod:`silx.gui.plot.ColorBar`.
+- :class:`silx.gui.plot.ColorBar.ColorBarWidget`
"""
__authors__ = ["T. Vincent"]
diff --git a/examples/printPreview.py b/examples/printPreview.py
index 187ad84..7567adb 100755
--- a/examples/printPreview.py
+++ b/examples/printPreview.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,12 +24,13 @@
#
# ###########################################################################*/
"""This script illustrates how to add a print preview tool button to any plot
-widget inheriting :class:`PlotWidget`.
+widget inheriting :class:`~silx.gui.plot.PlotWidget`.
Three plot widgets are instantiated. One of them uses a standalone
-:class:`PrintPreviewToolButton`, while the other two use a
-:class:`SingletonPrintPreviewToolButton` which allows them to send their content
-to the same print preview page.
+:class:`~silx.gui.plot.PrintPreviewToolButton.PrintPreviewToolButton`,
+while the other two use a
+:class:`~silx.gui.plot.PrintPreviewToolButton.SingletonPrintPreviewToolButton`
+which allows them to send their content to the same print preview page.
"""
__authors__ = ["P. Knobel"]
__license__ = "MIT"
diff --git a/examples/shiftPlotAction.py b/examples/shiftPlotAction.py
index 7cac08c..f272cda 100755
--- a/examples/shiftPlotAction.py
+++ b/examples/shiftPlotAction.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,8 +23,8 @@
# THE SOFTWARE.
#
# ###########################################################################*/
-"""This script is a simple (trivial) example of how to create a PlotWindow,
-create a custom :class:`PlotAction` and add it to the toolbar.
+"""This script is a simple (trivial) example of how to create a :class:`~silx.gui.plot.PlotWindow`,
+create a custom :class:`~silx.gui.plot.actions.PlotAction` and add it to the toolbar.
The action simply shifts the selected curve up by 1 unit by adding 1 to each
value of y.
diff --git a/examples/simplewidget.py b/examples/simplewidget.py
index 605beb3..8bfe7d5 100755
--- a/examples/simplewidget.py
+++ b/examples/simplewidget.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -27,7 +27,8 @@
It shows the following widgets:
-- :class:WaitingPushButton: A button with a progress-like waiting animated icon
+- :class:`~silx.gui.widgets.WaitingPushButton`:
+ A button with a progress-like waiting animated icon.
"""
__authors__ = ["V. Valls"]
diff --git a/examples/stackView.py b/examples/stackView.py
index 0447cea..4737251 100644
--- a/examples/stackView.py
+++ b/examples/stackView.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,8 +23,8 @@
# THE SOFTWARE.
#
# ###########################################################################*/
-"""This script is a simple example to illustrate how to use the StackView
-widget.
+"""This script is a simple example to illustrate how to use the
+:mod:`~silx.gui.plot.StackView` widget.
"""
import numpy
import sys
diff --git a/examples/syncaxis.py b/examples/syncaxis.py
index 1033738..02505c9 100644
--- a/examples/syncaxis.py
+++ b/examples/syncaxis.py
@@ -97,5 +97,6 @@ class SyncPlot(qt.QMainWindow):
if __name__ == "__main__":
app = qt.QApplication([])
window = SyncPlot()
+ window.setAttribute(qt.Qt.WA_DeleteOnClose, True)
window.setVisible(True)
app.exec_()
diff --git a/package/debian8/control b/package/debian8/control
index f10cd97..212266a 100644
--- a/package/debian8/control
+++ b/package/debian8/control
@@ -25,7 +25,6 @@ Build-Depends: cython,
python-pyopencl-dbg,
python-mako,
ipython,
- ipython-qtconsole,
python-matplotlib,
python-matplotlib-dbg,
python-opengl,
@@ -38,6 +37,7 @@ Build-Depends: cython,
python-sphinx,
python-sphinxcontrib.programoutput,
python-enum34,
+ python-concurrent.futures,
python3-all-dev,
python3-all-dbg,
python3-numpy,
@@ -50,7 +50,6 @@ Build-Depends: cython,
python3-pyopencl-dbg,
python3-mako,
ipython3,
- ipython3-qtconsole,
python3-matplotlib,
python3-matplotlib-dbg,
python3-opengl,
@@ -94,7 +93,6 @@ Depends: ${misc:Depends},
python-pyopencl,
python-mako,
ipython,
- ipython-qtconsole,
python-matplotlib,
python-opengl,
python-pyqt5,
@@ -102,6 +100,7 @@ Depends: ${misc:Depends},
python-scipy,
python-six,
python-enum34,
+ python-concurrent.futures,
# Recommends:
Suggests: python-rfoo
Description: Toolbox for X-Ray data analysis - Python2 library
@@ -123,7 +122,6 @@ Depends: ${misc:Depends},
python-pyopencl-dbg,
python-mako,
ipython,
- ipython-qtconsole,
python-matplotlib-dbg,
python-opengl,
python-pyqt5-dbg,
@@ -131,6 +129,7 @@ Depends: ${misc:Depends},
python-scipy-dbg,
python-six,
python-enum34,
+ python-concurrent.futures,
Description: Toolbox for X-Ray data analysis - python2 debug
.
This package contains the extension built for the Python 2 debug
@@ -149,7 +148,6 @@ Depends: ${misc:Depends},
python3-pyopencl,
python3-mako,
ipython3,
- ipython3-qtconsole,
python3-matplotlib,
python3-opengl,
python3-pyqt5,
@@ -177,7 +175,6 @@ Depends: ${misc:Depends},
python3-pyopencl-dbg,
python3-mako,
ipython3,
- ipython3-qtconsole,
python3-matplotlib-dbg,
python3-opengl,
python3-pyqt5-dbg,
diff --git a/package/debian8/rules b/package/debian8/rules
index d6cd69b..f72ed66 100755
--- a/package/debian8/rules
+++ b/package/debian8/rules
@@ -35,6 +35,7 @@ override_dh_install:
dh_install -p silx package/desktop/*.desktop usr/share/applications
dh_install -p silx package/desktop/silx.png usr/share/icons/hicolor/48x48/apps
dh_install -p silx package/desktop/silx.svg usr/share/icons/hicolor/scalable/apps
+ dh_install -p silx package/desktop/silx.xml usr/share/mime/packages
rm -rf debian/python-silx/usr/bin
rm -rf debian/python3-silx/usr/bin
diff --git a/package/debian9/control b/package/debian9/control
index 193b844..4c244f1 100644
--- a/package/debian9/control
+++ b/package/debian9/control
@@ -6,8 +6,7 @@ Section: science
Priority: extra
Build-Depends: cython,
cython3,
- libstdc++-4.9-dev,
- libstdc++6,
+ libstdc++-4.9-dev|libstdc++6,
debhelper (>=9.20150101+deb8u2),
dh-python,
python-all-dev,
@@ -26,6 +25,7 @@ Build-Depends: cython,
python-sphinx,
python-sphinxcontrib.programoutput,
python-enum34,
+ python-concurrent.futures,
python3-all-dev,
python3-numpy,
python3-fabio,
@@ -82,6 +82,7 @@ Depends: ${misc:Depends},
python-scipy,
python-six,
python-enum34,
+ python-concurrent.futures,
# Recommends:
Suggests: python-rfoo
Description: Toolbox for X-Ray data analysis - Python2 library
diff --git a/package/debian9/rules b/package/debian9/rules
index b348c51..160147b 100755
--- a/package/debian9/rules
+++ b/package/debian9/rules
@@ -35,6 +35,7 @@ override_dh_install:
dh_install -p silx package/desktop/*.desktop usr/share/applications
dh_install -p silx package/desktop/silx.png usr/share/icons/hicolor/48x48/apps
dh_install -p silx package/desktop/silx.svg usr/share/icons/hicolor/scalable/apps
+ dh_install -p silx package/desktop/silx.xml usr/share/mime/packages
rm -rf debian/python-silx/usr/bin
rm -rf debian/python3-silx/usr/bin
diff --git a/package/desktop/org.silx.SilxView.desktop b/package/desktop/org.silx.SilxView.desktop
index 577c0c8..02d615e 100644
--- a/package/desktop/org.silx.SilxView.desktop
+++ b/package/desktop/org.silx.SilxView.desktop
@@ -1,9 +1,11 @@
[Desktop Entry]
+Version=1.0
Type=Application
-Encoding=UTF-8
-Name=silx Data Viewer
+Name=silx data viewer
Comment=HDF5 EDF SPEC Data Viewer
Exec=silx view %F
-Terminal=false
+TryExec=silx
Icon=silx
-Categories=Education;Science;DataVisualization;Qt
+Terminal=false
+Categories=Education;Science;DataVisualization;Qt;
+MimeType=image/tiff;application/x-hdf;application/x-silx-hdf5;application/x-silx-nexus;application/x-silx-specfile;image/x-silx-marccd;image/x-silx-cbf;image/x-silx-edf;image/x-silx-numpy;
diff --git a/package/desktop/silx.xml b/package/desktop/silx.xml
new file mode 100644
index 0000000..e98d6a3
--- /dev/null
+++ b/package/desktop/silx.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+
+ <!-- HDF5 -->
+
+ <mime-type type="application/x-silx-hdf5">
+ <comment>Hierarchical Data Format</comment>
+ <sub-class-of type="application/x-hdf"/>
+ <glob pattern="*.h5"/>
+ <glob pattern="*.hdf"/>
+ <glob pattern="*.hdf5"/>
+ </mime-type>
+
+ <mime-type type="application/x-silx-nexus">
+ <comment>NeXus file</comment>
+ <sub-class-of type="application/x-silx-hdf5"/>
+ <glob pattern="*.nx"/>
+ <glob pattern="*.nxs"/>
+ <glob pattern="*.h5"/>
+ <glob pattern="*.hdf"/>
+ </mime-type>
+
+ <!-- Spec formats -->
+
+ <mime-type type="application/x-silx-specfile">
+ <comment>Spec file</comment>
+ <glob pattern="*.spec"/>
+ <glob pattern="*.mca"/>
+ <glob pattern="*.dat"/>
+ </mime-type>
+
+ <!-- Image formats -->
+
+ <mime-type type="image/x-silx-marccd">
+ <comment>MarCCD image file</comment>
+ <sub-class-of type="image/tiff"/>
+ <glob pattern="*.mccd"/>
+ </mime-type>
+
+ <mime-type type="image/x-silx-cbf">
+ <comment>CBF image file</comment>
+ <acronym>CBF</acronym>
+ <expanded-acronym>Crystallographic Information File</expanded-acronym>
+ <glob pattern="*.cbf"/>
+ </mime-type>
+
+ <mime-type type="image/x-silx-edf">
+ <comment>EDF image file</comment>
+ <acronym>EDF</acronym>
+ <expanded-acronym>ESRF data format</expanded-acronym>
+ <glob pattern="*.edf"/>
+ </mime-type>
+
+ <mime-type type="image/x-silx-numpy">
+ <comment>Numpy data file</comment>
+ <glob pattern="*.npz"/>
+ <glob pattern="*.npy"/>
+ </mime-type>
+
+</mime-info> \ No newline at end of file
diff --git a/requirements-dev.txt b/requirements-dev.txt
index d3c36e3..5333b0d 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -1,7 +1,12 @@
# List of silx development dependencies
# Those ARE NOT required for installation, at runtime or to build from source (except for the doc)
+numpy >= 1.8
+setuptools # Advanced packaging tools
+wheel # To build wheels
Cython >= 0.21.1 # To regenerate .c/.cpp files from .pyx
Sphinx # To build the documentation in doc/
lxml # For test coverage in run_test.py
coverage # For test coverage in run_test.py
+pillow # For loading images in documentation generation
+nbsphinx # For converting ipynb in documentation \ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 9e46ba1..fa6c806 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,7 +6,8 @@
--only-binary numpy,h5py,scipy,PyQt4,PyQt5,PySide
numpy >= 1.8
-fabio >= 0.4 # For silx.io
+scipy # For silx.math.fit demo, silx.image.sift demo, silx.image.sift.test
+fabio >= 0.6 # For silx.io
h5py # For silx.io
pyopencl # For silx.opencl
Mako # For pyopencl reduction
@@ -14,9 +15,9 @@ ipython # For silx.gui.console
qtconsole # For silx.gui.console
matplotlib >= 1.2.0 # For silx.gui.plot
PyOpenGL # For silx.gui.plot3d
-# PyQt4, PyQt5 or PySide # For silx.gui
-# scipy # For silx.math.fit demo, silx.image.sift demo, silx.image.sift.test
+Pillow # for silx.opencl.image.test
+# PyQt4, PyQt5 or PySide # For silx.gui
# Try to install a Qt binding from a wheel
# This is no available for all configurations
@@ -24,6 +25,3 @@ PyOpenGL # For silx.gui.plot3d
PyQt5; python_version >= '3.5'
PyQt4; sys_platform == 'win32' and python_version == '2.7' # From silx.org
PyQt4; sys_platform == 'darwin' and python_version == '2.7' # From silx.org
-
-# Require scipy when wheel is available
-scipy; sys_platform != 'win32'
diff --git a/run_tests.py b/run_tests.py
index f01ea84..04b0510 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -32,7 +32,7 @@ Test coverage dependencies: coverage, lxml.
"""
__authors__ = ["Jérôme Kieffer", "Thomas Vincent"]
-__date__ = "03/08/2017"
+__date__ = "29/01/2018"
__license__ = "MIT"
import distutils.util
@@ -42,6 +42,8 @@ import subprocess
import sys
import time
import unittest
+import collections
+from argparse import ArgumentParser
class StreamHandlerUnittestReady(logging.StreamHandler):
@@ -90,10 +92,16 @@ except ImportError:
try:
import importlib
-except:
- importer = __import__
-else:
importer = importlib.import_module
+except ImportError:
+ def importer(name):
+ module = __import__(name)
+ # returns the leaf module, instead of the root module
+ subnames = name.split(".")
+ subnames.pop(0)
+ for subname in subnames:
+ module = getattr(module, subname)
+ return module
try:
@@ -126,11 +134,6 @@ def get_project_name(root_dir):
return name.split()[-1].decode('ascii')
-PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
-PROJECT_NAME = get_project_name(PROJECT_DIR)
-logger.info("Project name: %s", PROJECT_NAME)
-
-
class TextTestResultWithSkipList(unittest.TextTestResult):
"""Override default TextTestResult to display list of skipped tests at the
end
@@ -139,7 +142,23 @@ class TextTestResultWithSkipList(unittest.TextTestResult):
def printErrors(self):
unittest.TextTestResult.printErrors(self)
# Print skipped tests at the end
- self.printErrorList("SKIPPED", self.skipped)
+ self.printGroupedList("SKIPPED", self.skipped)
+
+ def printGroupedList(self, flavour, errors):
+ grouped = collections.OrderedDict()
+
+ for test, err in errors:
+ if err in grouped:
+ grouped[err] = grouped[err] + [test]
+ else:
+ grouped[err] = [test]
+
+ for err, tests in grouped.items():
+ self.stream.writeln(self.separator1)
+ for test in tests:
+ self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
+ self.stream.writeln(self.separator2)
+ self.stream.writeln("%s" % err)
class ProfileTextTestResult(unittest.TextTestRunner.resultclass):
@@ -170,7 +189,8 @@ class ProfileTextTestResult(unittest.TextTestRunner.resultclass):
else:
memusage = 0
self.logger.info("Time: %.3fs \t RAM: %.3f Mb\t%s",
- time.time() - self.__time_start, memusage, test.id())
+ time.time() - self.__time_start,
+ memusage, test.id())
def report_rst(cov, package, version="0.0.0", base=""):
@@ -231,6 +251,20 @@ def report_rst(cov, package, version="0.0.0", base=""):
return os.linesep.join(res)
+def is_debug_python():
+ """Returns true if the Python interpreter is in debug mode."""
+ try:
+ import sysconfig
+ except ImportError: # pragma nocover
+ # Python < 2.7
+ import distutils.sysconfig as sysconfig
+
+ if sysconfig.get_config_var("Py_DEBUG"):
+ return True
+
+ return hasattr(sys, "gettotalrefcount")
+
+
def build_project(name, root_dir):
"""Run python setup.py build for the project.
@@ -243,6 +277,8 @@ def build_project(name, root_dir):
platform = distutils.util.get_platform()
architecture = "lib.%s-%i.%i" % (platform,
sys.version_info[0], sys.version_info[1])
+ if is_debug_python():
+ architecture += "-pydebug"
if os.environ.get("PYBUILD_NAME") == name:
# we are in the debian packaging way
@@ -259,7 +295,55 @@ def build_project(name, root_dir):
return home
-from argparse import ArgumentParser
+def import_project_module(project_name, project_dir):
+ """Import project module, from the system of from the project directory"""
+ # Prevent importing from source directory
+ if (os.path.dirname(os.path.abspath(__file__)) == os.path.abspath(sys.path[0])):
+ removed_from_sys_path = sys.path.pop(0)
+ logger.info("Patched sys.path, removed: '%s'", removed_from_sys_path)
+
+ if "--installed" in sys.argv:
+ try:
+ module = importer(project_name)
+ except ImportError:
+ raise ImportError(
+ "%s not installed: Cannot run tests on installed version" %
+ PROJECT_NAME)
+ else: # Use built source
+ build_dir = build_project(project_name, project_dir)
+
+ sys.path.insert(0, build_dir)
+ logger.warning("Patched sys.path, added: '%s'", build_dir)
+ module = importer(project_name)
+ return module
+
+
+def get_test_options(project_module):
+ """Returns the test options if available, else None"""
+ module_name = project_module.__name__ + '.test.utils'
+ logger.info('Import %s', module_name)
+ try:
+ test_utils = importer(module_name)
+ except ImportError:
+ logger.warning("No module named '%s'. No test options available.", module_name)
+ return None
+
+ test_options = getattr(test_utils, "test_options", None)
+ return test_options
+
+
+PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
+PROJECT_NAME = get_project_name(PROJECT_DIR)
+logger.info("Project name: %s", PROJECT_NAME)
+
+project_module = import_project_module(PROJECT_NAME, PROJECT_DIR)
+PROJECT_VERSION = getattr(project_module, 'version', '')
+PROJECT_PATH = project_module.__path__[0]
+
+test_options = get_test_options(project_module)
+"""Contains extra configuration for the tests."""
+
+
epilog = """Environment variables:
WITH_QT_TEST=False to disable graphical tests
SILX_OPENCL=False to disable OpenCL tests
@@ -286,20 +370,10 @@ parser.add_argument("-v", "--verbose", default=0,
help="Increase verbosity. Option -v prints additional " +
"INFO messages. Use -vv for full verbosity, " +
"including debug messages and test help strings.")
-parser.add_argument("-x", "--no-gui", dest="gui", default=True,
- action="store_false",
- help="Disable the test of the graphical use interface")
-parser.add_argument("-g", "--no-opengl", dest="opengl", default=True,
- action="store_false",
- help="Disable tests using OpenGL")
-parser.add_argument("-o", "--no-opencl", dest="opencl", default=True,
- action="store_false",
- help="Disable the test of the OpenCL part")
-parser.add_argument("-l", "--low-mem", dest="low_mem", default=False,
- action="store_true",
- help="Disable test with large memory consumption (>100Mbyte")
parser.add_argument("--qt-binding", dest="qt_binding", default=None,
help="Force using a Qt binding, from 'PyQt4', 'PyQt5', or 'PySide'")
+if test_options is not None:
+ test_options.add_parser_argument(parser)
default_test_name = "%s.test.suite" % PROJECT_NAME
parser.add_argument("test_name", nargs='*',
@@ -322,18 +396,6 @@ elif options.verbose > 1:
test_verbosity = 2
use_buffer = False
-if not options.gui:
- os.environ["WITH_QT_TEST"] = "False"
-
-if not options.opencl:
- os.environ["SILX_OPENCL"] = "False"
-
-if not options.opengl:
- os.environ["WITH_GL_TEST"] = "False"
-
-if options.low_mem:
- os.environ["SILX_TEST_LOW_MEM"] = "True"
-
if options.coverage:
logger.info("Running test-coverage")
import coverage
@@ -353,10 +415,9 @@ if options.qt_binding:
if sys.version < "3.0.0":
try:
import sip
-
sip.setapi("QString", 2)
sip.setapi("QVariant", 2)
- except:
+ except Exception:
logger.warning("Cannot set sip API")
import PyQt4.QtCore # noqa
elif binding == "pyqt5":
@@ -365,36 +426,12 @@ if options.qt_binding:
elif binding == "pyside":
logger.info("Force using PySide")
import PySide.QtCore # noqa
+ elif binding == "pyside2":
+ logger.info("Force using PySide2")
+ import PySide2.QtCore # noqa
else:
raise ValueError("Qt binding '%s' is unknown" % options.qt_binding)
-# Prevent importing from source directory
-if (os.path.dirname(os.path.abspath(__file__)) ==
- os.path.abspath(sys.path[0])):
- removed_from_sys_path = sys.path.pop(0)
- logger.info("Patched sys.path, removed: '%s'", removed_from_sys_path)
-
-
-# import module
-if options.installed: # Use installed version
- try:
- module = importer(PROJECT_NAME)
- except:
- raise ImportError(
- "%s not installed: Cannot run tests on installed version" %
- PROJECT_NAME)
-else: # Use built source
- build_dir = build_project(PROJECT_NAME, PROJECT_DIR)
-
- sys.path.insert(0, build_dir)
- logger.warning("Patched sys.path, added: '%s'", build_dir)
- module = importer(PROJECT_NAME)
-
-
-PROJECT_VERSION = getattr(module, 'version', '')
-PROJECT_PATH = module.__path__[0]
-
-
# Run the tests
runnerArgs = {}
runnerArgs["verbosity"] = test_verbosity
@@ -411,9 +448,15 @@ logger.warning("Test %s %s from %s",
test_module_name = PROJECT_NAME + '.test'
logger.info('Import %s', test_module_name)
test_module = importer(test_module_name)
-
test_suite = unittest.TestSuite()
+if test_options is not None:
+ # Configure the test options according to the command lines and the the environment
+ test_options.configure(options)
+else:
+ logger.warning("No test options available.")
+
+
if not options.test_name:
# Do not use test loader to avoid cryptic exception
# when an error occur during import
diff --git a/setup.py b/setup.py
index bede4df..08e4f90 100644
--- a/setup.py
+++ b/setup.py
@@ -25,21 +25,20 @@
# ###########################################################################*/
__authors__ = ["Jérôme Kieffer", "Thomas Vincent"]
-__date__ = "02/10/2017"
+__date__ = "27/02/2018"
__license__ = "MIT"
-# This import is here only to fix a bug on Debian 7 with python2.7
-# Without this, the system io module is not loaded from numpy.distutils
-# the silx.io module seems to be loaded instead
-import io
-
import sys
import os
import platform
import shutil
import logging
import glob
+# io import has to be here also to fix a bug on Debian 7 with python2.7
+# Without this, the system io module is not loaded from numpy.distutils.
+# The silx.io module seems to be loaded instead.
+import io
logging.basicConfig(level=logging.INFO)
@@ -188,6 +187,64 @@ class BuildMan(Command):
def finalize_options(self):
pass
+ def entry_points_iterator(self):
+ """Iterate other entry points available on the project."""
+ entry_points = self.distribution.entry_points
+ console_scripts = entry_points.get('console_scripts', [])
+ gui_scripts = entry_points.get('gui_scripts', [])
+ scripts = []
+ scripts.extend(console_scripts)
+ scripts.extend(gui_scripts)
+ for script in scripts:
+ # Remove ending extra dependencies
+ script = script.split("[")[0]
+ elements = script.split("=")
+ target_name = elements[0].strip()
+ elements = elements[1].split(":")
+ module_name = elements[0].strip()
+ function_name = elements[1].strip()
+ yield target_name, module_name, function_name
+
+ def run_targeted_script(self, target_name, script_name, env, log_output=False):
+ """Execute targeted script using --help and --version to help checking
+ errors. help2man is not very helpful to do it for us.
+
+ :return: True is both return code are equal to 0
+ :rtype: bool
+ """
+ import subprocess
+
+ if log_output:
+ extra_args = {}
+ else:
+ try:
+ # Python 3
+ from subprocess import DEVNULL
+ except ImportError:
+ # Python 2
+ import os
+ DEVNULL = open(os.devnull, 'wb')
+ extra_args = {'stdout': DEVNULL, 'stderr': DEVNULL}
+
+ succeeded = True
+ command_line = [sys.executable, script_name, "--help"]
+ if log_output:
+ logger.info("See the following execution of: %s", " ".join(command_line))
+ p = subprocess.Popen(command_line, env=env, **extra_args)
+ status = p.wait()
+ if log_output:
+ logger.info("Return code: %s", status)
+ succeeded = succeeded and status == 0
+ command_line = [sys.executable, script_name, "--version"]
+ if log_output:
+ logger.info("See the following execution of: %s", " ".join(command_line))
+ p = subprocess.Popen(command_line, env=env, **extra_args)
+ status = p.wait()
+ if log_output:
+ logger.info("Return code: %s", status)
+ succeeded = succeeded and status == 0
+ return succeeded
+
def run(self):
build = self.get_finalized_command('build')
path = sys.path
@@ -200,34 +257,52 @@ class BuildMan(Command):
import subprocess
import tempfile
import stat
+ script_name = None
- try:
- script_name = None
-
+ entry_points = self.entry_points_iterator()
+ for target_name, module_name, function_name in entry_points:
+ logger.info("Build man for entry-point target '%s'" % target_name)
# help2man expect a single executable file to extract the help
# we create it, execute it, and delete it at the end
- # create a launcher using the right python interpreter
- script_fid, script_name = tempfile.mkstemp(prefix="%s_" % PROJECT, text=True)
- script = os.fdopen(script_fid, 'wt')
- script.write("#!%s\n" % sys.executable)
- script.write("import runpy\n")
- script.write("runpy.run_module('%s', run_name='__main__')\n" % PROJECT)
- script.close()
-
- # make it executable
- mode = os.stat(script_name).st_mode
- os.chmod(script_name, mode + stat.S_IEXEC)
-
- # execute help2man
- p = subprocess.Popen(["help2man", script_name, "-o", "build/man/silx.1"], env=env)
- status = p.wait()
- if status != 0:
- raise RuntimeError("Fail to generate man documentation")
- finally:
- # clean up the script
- if script_name is not None:
- os.remove(script_name)
+ py3 = sys.version_info >= (3, 0)
+ try:
+ # create a launcher using the right python interpreter
+ script_fid, script_name = tempfile.mkstemp(prefix="%s_" % target_name, text=True)
+ script = os.fdopen(script_fid, 'wt')
+ script.write("#!%s\n" % sys.executable)
+ script.write("import %s as app\n" % module_name)
+ script.write("app.%s()\n" % function_name)
+ script.close()
+ # make it executable
+ mode = os.stat(script_name).st_mode
+ os.chmod(script_name, mode + stat.S_IEXEC)
+
+ # execute help2man
+ man_file = "build/man/%s.1" % target_name
+ command_line = ["help2man", script_name, "-o", man_file]
+ if not py3:
+ # Before Python 3.4, ArgParser --version was using
+ # stderr to print the version
+ command_line.append("--no-discard-stderr")
+ # Then we dont know if the documentation will contains
+ # durtty things
+ succeeded = self.run_targeted_script(target_name, script_name, env, False)
+ if not succeeded:
+ logger.info("Error while generating man file for target '%s'.", target_name)
+ self.run_targeted_script(target_name, script_name, env, True)
+ raise RuntimeError("Fail to generate '%s' man documentation" % target_name)
+
+ p = subprocess.Popen(command_line, env=env)
+ status = p.wait()
+ if status != 0:
+ logger.info("Error while generating man file for target '%s'.", target_name)
+ self.run_targeted_script(target_name, script_name, env, True)
+ raise RuntimeError("Fail to generate '%s' man documentation" % target_name)
+ finally:
+ # clean up the script
+ if script_name is not None:
+ os.remove(script_name)
if sphinx is not None:
@@ -640,7 +715,7 @@ class sdist_debian(sdist):
Tailor made sdist for debian
* remove auto-generated doc
* remove cython generated .c files
- * remove cython generated .c files
+ * remove cython generated .cpp files
* remove .bat files
* include .l man files
"""
@@ -716,7 +791,9 @@ def get_project_configuration(dry_run):
'gui/icons/*.gif',
'gui/icons/*/*.png',
'opencl/*.cl',
+ 'opencl/image/*.cl',
'opencl/sift/*.cl',
+ 'opencl/codec/*.cl',
'gui/colormaps/*.npy'],
}
@@ -753,7 +830,7 @@ def get_project_configuration(dry_run):
author="data analysis unit",
author_email="silx@esrf.fr",
classifiers=classifiers,
- description="Software library for X-Ray data analysis",
+ description="Software library for X-ray data analysis",
long_description=get_readme(),
install_requires=install_requires,
setup_requires=setup_requires,
diff --git a/silx.egg-info/PKG-INFO b/silx.egg-info/PKG-INFO
index ed985dc..907a50f 100644
--- a/silx.egg-info/PKG-INFO
+++ b/silx.egg-info/PKG-INFO
@@ -1,7 +1,7 @@
Metadata-Version: 1.1
Name: silx
-Version: 0.6.1
-Summary: Software library for X-Ray data analysis
+Version: 0.7.0
+Summary: Software library for X-ray data analysis
Home-page: http://www.silx.org/
Author: data analysis unit
Author-email: silx@esrf.fr
@@ -10,127 +10,77 @@ Description:
silx toolkit
============
- The silx project aims at providing a collection of Python packages to support the
+ The purpose of the *silx* project is to provide a collection of Python packages to support the
development of data assessment, reduction and analysis applications at synchrotron
radiation facilities.
It aims at providing reading/writing different file formats, data reduction routines
- and a set of Qt widgets to browse and visualize data.
+ and a set of Qt widgets to browse and visualise data.
- The current version provides:
+ The current version features:
- * reading `HDF5 <https://www.hdfgroup.org/HDF5/>`_ file format (with support of
- `SPEC <https://certif.com/spec.html>`_ file format and
+ * Support of `HDF5 <https://www.hdfgroup.org/HDF5/>`_,
+ `SPEC <https://certif.com/spec.html>`_ and
`FabIO <http://www.silx.org/doc/fabio/dev/getting_started.html#list-of-file-formats-that-fabio-can-read-and-write>`_
- images)
- * histogramming
- * fitting
- * 1D and 2D visualization widgets using multiple backends (matplotlib or OpenGL)
- * an OpenGL-based widget to display 3D scalar field with isosurface and cutting plane
- * an image plot widget with a set of associated tools
- * a unified browser for HDF5, SPEC and image file formats supporting inspection and
- visualization of n-dimensional datasets.
- * a unified viewer (*silx view filename*) for HDF5, SPEC and image file formats
- * a unified converter to HDF5 format (*silx convert filename*)
- * median filters on images (C and OpenCL implementations)
- * image alignement (sift - OpenCL implementation)
- * filtered backprojection and forward projection for tomography
+ images file formats.
+ * OpenCL-based data processing: image alignment (SIFT),
+ image processing (median filter, histogram),
+ filtered backprojection for tomography
+ * Data reduction: histogramming, fitting, median filter
+ * A set of Qt widgets, including:
+
+ * 1D and 2D visualization widgets with a set of associated tools using multiple backends (matplotlib or OpenGL)
+ * OpenGL-based widgets to visualize data in 3D (scalar field with isosurface and cut plane, scatter plot)
+ * a unified browser for HDF5, SPEC and image file formats supporting inspection and
+ visualization of n-dimensional datasets.
+
+ * a set of applications:
+
+ * a unified viewer (*silx view filename*) for HDF5, SPEC and image file formats
+ * a unified converter to HDF5 format (*silx convert filename*)
Installation
------------
- To install silx, run::
+ To install silx, run:
+
+ .. code-block:: bash
pip install silx
- Or with Anaconda on Linux and MacOS::
+ Or using Anaconda on Linux and MacOS:
+
+ .. code-block:: bash
conda install silx -c conda-forge
- To install silx locally, run::
-
- pip install silx --user
-
- Unofficial packages for different distributions are available :
+ Unofficial packages for different distributions are available:
- Unofficial Debian8 packages are available at http://www.silx.org/pub/debian/
- - CentOS 7 rpm packages are provided by Max IV at the following url: http://pubrepo.maxiv.lu.se/rpm/el7/x86_64/
+ - CentOS 7 rpm packages are provided by Max IV at: http://pubrepo.maxiv.lu.se/rpm/el7/x86_64/
- Fedora 23 rpm packages are provided by Max IV at http://pubrepo.maxiv.lu.se/rpm/fc23/x86_64/
- Arch Linux (AUR) packages are also available: https://aur.archlinux.org/packages/python-silx
- Beside this, we provide a certain number of wheels (pre-compiled binary packages) to be installed
- onto a pre-existing Python installation:
-
- - On Windows, binary wheels are available for Python 2.7, 3.5 and 3.6.
- - On MacOS, binary wheels are available for Python 2.7, 3.5 and 3.6.
- - On Linux, manylinux1 binary wheels are available for Python 2.7, 3.4, 3.5 and 3.6.
-
- Those builds are made from "up-date" systems at the time of the release, i.e. they use
- the latest stable version of numpy (and cython).
- Hence your system should use a fairly recent version of numpy to be compatible with silx.
- This can be achieved simply by::
-
- pip install numpy --upgrade
-
-
- The latest development version can be obtained from the git repository::
-
- git clone https://github.com/silx-kit/silx.git
- cd silx
- pip install . [--user]
-
- Dependencies
- ------------
-
- * `Python <https://www.python.org/>`_ 2.7, 3.4 or above.
- * `numpy <http://www.numpy.org>`_
-
- The GUI widgets of the silx package depend on the following extra packages:
-
- * A Qt binding: `PyQt5, PyQt4 <https://riverbankcomputing.com/software/pyqt/intro>`_ (using API version 2) or `PySide <https://pypi.python.org/pypi/PySide/>`_
- * `matplotlib <http://matplotlib.org/>`_ for the silx.gui.plot package
- * `PyOpenGL <http://pyopengl.sourceforge.net/>`_ for the silx.gui.plot3d package
-
- Most modules and functions dealing with `HDF5 <https://www.hdfgroup.org/HDF5/>`_ input/output depend on:
-
- * `h5py <http://www.h5py.org/>`_
-
- Parallel algorithms depend on:
-
- * `PyOpenCL <https://documen.tician.de/pyopencl/>`_
-
- The console widgets depend on:
-
- * `ipython <https://ipython.org/>`_
- * `qtconsole <https://pypi.python.org/pypi/qtconsole>`_
-
-
- Supported platforms: Linux, Windows, Mac OS X.
+ `Detailed installation instructions <http://www.silx.org/doc/silx/dev/install.html>`_
+ are available in the documentation.
Documentation
-------------
- Documentation of latest release is available at http://www.silx.org/doc/silx/latest/
-
- Documentation of previous releases and nightly build is available at http://www.silx.org/doc/silx/
-
- To build the documentation from the source (requires `Sphinx <http://www.sphinx-doc.org>`_), run::
-
- python setup.py build build_doc
+ The documentation of `latest release <http://www.silx.org/doc/silx/latest/>`_ and
+ the documentation of `the nightly build <http://www.silx.org/doc/silx/dev>`_ are
+ available at http://www.silx.org/doc/silx/
Testing
-------
+ *silx* features a comprehensive test-suite used in continuous integration for
+ all major operating systems:
+
- Travis CI status: |Travis Status|
- Appveyor CI status: |Appveyor Status|
- To run the tests from the python interpreter, run:
-
- >>> import silx.test
- >>> silx.test.run_tests()
-
- To run the tests, from the source directory, run::
-
- python run_tests.py
+ Please refer to the `documentation on testing <http://www.silx.org/doc/silx/dev/install.html#testing>`_
+ for details.
Examples
--------
@@ -142,13 +92,14 @@ Description:
License
-------
- The source code of silx is licensed under the MIT license.
- See the `LICENSE <https://github.com/silx-kit/silx/blob/master/LICENSE>`_ and `copyright <https://github.com/silx-kit/silx/blob/master/copyright>`_ files for details.
+ The source code of *silx* is licensed under the MIT license.
+ See the `LICENSE <https://github.com/silx-kit/silx/blob/master/LICENSE>`_ and
+ `copyright <https://github.com/silx-kit/silx/blob/master/copyright>`_ files for details.
Citation
--------
- silx releases can be cited by their DOI on Zenodo: |zenodo DOI|
+ *silx* releases can be cited via their DOI on Zenodo: |zenodo DOI|
.. |Travis Status| image:: https://travis-ci.org/silx-kit/silx.svg?branch=master
:target: https://travis-ci.org/silx-kit/silx
diff --git a/silx.egg-info/SOURCES.txt b/silx.egg-info/SOURCES.txt
index 5de21ae..734f4b2 100644
--- a/silx.egg-info/SOURCES.txt
+++ b/silx.egg-info/SOURCES.txt
@@ -19,11 +19,11 @@ doc/source/overview.rst
doc/source/tutorials.rst
doc/source/virtualenv.rst
doc/source/Tutorials/array_widget.rst
+doc/source/Tutorials/convert.rst
doc/source/Tutorials/fit.rst
doc/source/Tutorials/fitconfig.rst
doc/source/Tutorials/io.rst
doc/source/Tutorials/specfile_to_hdf5.rst
-doc/source/Tutorials/Sift/sift.rst
doc/source/Tutorials/img/arraywidget3D_0.png
doc/source/Tutorials/img/arraywidget3D_1.png
doc/source/Tutorials/img/arraywidget5D_0.png
@@ -39,6 +39,12 @@ doc/source/Tutorials/img/fitwidget5.png
doc/source/Tutorials/img/silx_view_edf.png
doc/source/Tutorials/img/stripbg_plot1.png
doc/source/Tutorials/img/stripbg_plot2.png
+doc/source/applications/convert.rst
+doc/source/applications/index.rst
+doc/source/applications/view.rst
+doc/source/applications/img/silx-view-hdf5.png
+doc/source/applications/img/silx-view-image.png
+doc/source/applications/img/silx-view-table.png
doc/source/description/index.rst
doc/source/description/sift.rst
doc/source/description/img/sift_bench_cpu0.png
@@ -58,6 +64,7 @@ doc/source/img/silx_large.png
doc/source/img/silx_small.png
doc/source/modules/index.rst
doc/source/modules/resources.rst
+doc/source/modules/sx.rst
doc/source/modules/gui/console.rst
doc/source/modules/gui/designer.rst
doc/source/modules/gui/gallery.rst
@@ -75,6 +82,13 @@ doc/source/modules/gui/data/img/ArrayTableWidget.png
doc/source/modules/gui/data/img/DataViewer.png
doc/source/modules/gui/data/img/DataViewerFrame.png
doc/source/modules/gui/data/img/NumpyAxesSelector.png
+doc/source/modules/gui/dialog/abstractdatafiledialog.rst
+doc/source/modules/gui/dialog/datafiledialog.rst
+doc/source/modules/gui/dialog/imagefiledialog.rst
+doc/source/modules/gui/dialog/index.rst
+doc/source/modules/gui/dialog/img/datafiledialog.png
+doc/source/modules/gui/dialog/img/imagefiledialog_edf.png
+doc/source/modules/gui/dialog/img/imagefiledialog_h5.png
doc/source/modules/gui/fit/backgroundwidget.rst
doc/source/modules/gui/fit/fitwidget.rst
doc/source/modules/gui/fit/index.rst
@@ -99,6 +113,8 @@ doc/source/modules/gui/plot/getting_started.rst
doc/source/modules/gui/plot/imageview.rst
doc/source/modules/gui/plot/index.rst
doc/source/modules/gui/plot/items.rst
+doc/source/modules/gui/plot/plotsignal.rst
+doc/source/modules/gui/plot/plottoolbuttons.rst
doc/source/modules/gui/plot/plottools.rst
doc/source/modules/gui/plot/plotwidget.rst
doc/source/modules/gui/plot/plotwindow.rst
@@ -141,18 +157,22 @@ doc/source/modules/gui/plot3d/actions.rst
doc/source/modules/gui/plot3d/dev.rst
doc/source/modules/gui/plot3d/glutils.rst
doc/source/modules/gui/plot3d/index.rst
+doc/source/modules/gui/plot3d/items.rst
doc/source/modules/gui/plot3d/plot3dwidget.rst
doc/source/modules/gui/plot3d/plot3dwindow.rst
doc/source/modules/gui/plot3d/scalarfieldview.rst
doc/source/modules/gui/plot3d/scene.rst
+doc/source/modules/gui/plot3d/scenewidget.rst
+doc/source/modules/gui/plot3d/scenewindow.rst
doc/source/modules/gui/plot3d/sfviewparamtree.rst
doc/source/modules/gui/plot3d/tools.rst
doc/source/modules/gui/plot3d/utils.rst
-doc/source/modules/gui/plot3d/viewer3dvolume_example.rst
doc/source/modules/gui/plot3d/img/Plot3DWidget.png
doc/source/modules/gui/plot3d/img/Plot3DWindow.png
doc/source/modules/gui/plot3d/img/SFViewParamTree.png
doc/source/modules/gui/plot3d/img/ScalarFieldView.png
+doc/source/modules/gui/plot3d/img/SceneWidget.png
+doc/source/modules/gui/plot3d/img/SceneWindow.png
doc/source/modules/gui/widgets/framebrowser.rst
doc/source/modules/gui/widgets/index.rst
doc/source/modules/gui/widgets/periodictable.rst
@@ -185,6 +205,7 @@ doc/source/modules/io/octaveh5.rst
doc/source/modules/io/specfile.rst
doc/source/modules/io/specfilewrapper.rst
doc/source/modules/io/spech5.rst
+doc/source/modules/io/url.rst
doc/source/modules/io/utils.rst
doc/source/modules/math/combo.rst
doc/source/modules/math/histogram.rst
@@ -199,21 +220,35 @@ doc/source/modules/math/fit/functions.rst
doc/source/modules/math/fit/index.rst
doc/source/modules/math/fit/leastsq.rst
doc/source/modules/math/fit/peaksearch.rst
+doc/source/modules/opencl/codec_cbf.rst
+doc/source/modules/opencl/fbp.rst
+doc/source/modules/opencl/index.rst
+doc/source/modules/opencl/medfilt.rst
+doc/source/modules/opencl/sift/align.rst
+doc/source/modules/opencl/sift/index.rst
+doc/source/modules/opencl/sift/match.rst
+doc/source/modules/opencl/sift/plan.rst
doc/source/modules/test/index.rst
doc/source/modules/utils/array_like.rst
doc/source/modules/utils/decorators.rst
doc/source/modules/utils/html.rst
doc/source/modules/utils/index.rst
+doc/source/modules/utils/testutils.rst
doc/source/modules/utils/weakref.rst
doc/source/sample_code/index.rst
doc/source/sample_code/img/animatedicons.png
+doc/source/sample_code/img/colormapDialog.png
+doc/source/sample_code/img/customDataView.png
doc/source/sample_code/img/customHdf5TreeModel.png
doc/source/sample_code/img/fftPlotAction.png
+doc/source/sample_code/img/fileDialog.png
doc/source/sample_code/img/hdf5widget.png
doc/source/sample_code/img/icons.png
doc/source/sample_code/img/imageview.png
doc/source/sample_code/img/periodicTable.png
doc/source/sample_code/img/plot3dContextMenu.png
+doc/source/sample_code/img/plot3dSceneWindow.png
+doc/source/sample_code/img/plotClearAction.png
doc/source/sample_code/img/plotContextMenu.png
doc/source/sample_code/img/plotItemsSelector.png
doc/source/sample_code/img/plotLimits.png
@@ -226,15 +261,19 @@ doc/source/sample_code/img/simplewidget.png
doc/source/sample_code/img/stackView.png
doc/source/sample_code/img/syncaxis.png
doc/source/sample_code/img/viewer3DVolume.png
-examples/animatedicons.py
+examples/colormapDialog.py
+examples/customDataView.py
examples/customHdf5TreeModel.py
examples/fft.png
examples/fftPlotAction.py
+examples/fileDialog.py
examples/hdf5widget.py
examples/icons.py
examples/imageview.py
examples/periodicTable.py
examples/plot3dContextMenu.py
+examples/plot3dSceneWindow.py
+examples/plotClearAction.py
examples/plotContextMenu.py
examples/plotItemsSelector.py
examples/plotLimits.py
@@ -271,6 +310,7 @@ package/debian9/source/options
package/desktop/org.silx.SilxView.desktop
package/desktop/silx.png
package/desktop/silx.svg
+package/desktop/silx.xml
qtdesigner_plugins/README.rst
qtdesigner_plugins/plot1dplugin.py
qtdesigner_plugins/plot2dplugin.py
@@ -329,6 +369,18 @@ silx/gui/data/test/test_arraywidget.py
silx/gui/data/test/test_dataviewer.py
silx/gui/data/test/test_numpyaxesselector.py
silx/gui/data/test/test_textformatter.py
+silx/gui/dialog/AbstractDataFileDialog.py
+silx/gui/dialog/DataFileDialog.py
+silx/gui/dialog/FileTypeComboBox.py
+silx/gui/dialog/ImageFileDialog.py
+silx/gui/dialog/SafeFileIconProvider.py
+silx/gui/dialog/SafeFileSystemModel.py
+silx/gui/dialog/__init__.py
+silx/gui/dialog/setup.py
+silx/gui/dialog/utils.py
+silx/gui/dialog/test/__init__.py
+silx/gui/dialog/test/test_datafiledialog.py
+silx/gui/dialog/test/test_imagefiledialog.py
silx/gui/fit/BackgroundWidget.py
silx/gui/fit/FitConfig.py
silx/gui/fit/FitWidget.py
@@ -409,6 +461,7 @@ silx/gui/plot/backends/glutils/PlotImageFile.py
silx/gui/plot/backends/glutils/__init__.py
silx/gui/plot/items/__init__.py
silx/gui/plot/items/axis.py
+silx/gui/plot/items/complex.py
silx/gui/plot/items/core.py
silx/gui/plot/items/curve.py
silx/gui/plot/items/histogram.py
@@ -439,23 +492,39 @@ silx/gui/plot/test/testPlotWidget.py
silx/gui/plot/test/testPlotWidgetNoBackend.py
silx/gui/plot/test/testPlotWindow.py
silx/gui/plot/test/testProfile.py
+silx/gui/plot/test/testSaveAction.py
silx/gui/plot/test/testScatterMaskToolsWidget.py
silx/gui/plot/test/testStackView.py
silx/gui/plot/test/testUtilsAxis.py
silx/gui/plot/test/utils.py
silx/gui/plot/utils/__init__.py
silx/gui/plot/utils/axis.py
+silx/gui/plot3d/ParamTreeView.py
silx/gui/plot3d/Plot3DWidget.py
silx/gui/plot3d/Plot3DWindow.py
silx/gui/plot3d/SFViewParamTree.py
silx/gui/plot3d/ScalarFieldView.py
+silx/gui/plot3d/SceneWidget.py
+silx/gui/plot3d/SceneWindow.py
silx/gui/plot3d/__init__.py
silx/gui/plot3d/setup.py
+silx/gui/plot3d/_model/__init__.py
+silx/gui/plot3d/_model/core.py
+silx/gui/plot3d/_model/items.py
+silx/gui/plot3d/_model/model.py
silx/gui/plot3d/actions/Plot3DAction.py
silx/gui/plot3d/actions/__init__.py
silx/gui/plot3d/actions/io.py
silx/gui/plot3d/actions/mode.py
silx/gui/plot3d/actions/viewpoint.py
+silx/gui/plot3d/items/__init__.py
+silx/gui/plot3d/items/clipplane.py
+silx/gui/plot3d/items/core.py
+silx/gui/plot3d/items/image.py
+silx/gui/plot3d/items/mesh.py
+silx/gui/plot3d/items/mixins.py
+silx/gui/plot3d/items/scatter.py
+silx/gui/plot3d/items/volume.py
silx/gui/plot3d/scene/__init__.py
silx/gui/plot3d/scene/axes.py
silx/gui/plot3d/scene/camera.py
@@ -477,6 +546,7 @@ silx/gui/plot3d/scene/test/test_utils.py
silx/gui/plot3d/test/__init__.py
silx/gui/plot3d/test/testGL.py
silx/gui/plot3d/test/testScalarFieldView.py
+silx/gui/plot3d/tools/GroupPropertiesWidget.py
silx/gui/plot3d/tools/ViewpointTools.py
silx/gui/plot3d/tools/__init__.py
silx/gui/plot3d/tools/toolbars.py
@@ -546,6 +616,7 @@ silx/io/specfile_wrapper.pxd
silx/io/specfilewrapper.py
silx/io/spech5.py
silx/io/spectoh5.py
+silx/io/url.py
silx/io/utils.py
silx/io/specfile/include/Lists.h
silx/io/specfile/include/SpecFile.h
@@ -573,6 +644,7 @@ silx/io/test/test_specfile.py
silx/io/test/test_specfilewrapper.py
silx/io/test/test_spech5.py
silx/io/test/test_spectoh5.py
+silx/io/test/test_url.py
silx/io/test/test_utils.py
silx/math/__init__.py
silx/math/calibration.py
@@ -650,6 +722,7 @@ silx/math/test/test_marchingcubes.py
silx/opencl/__init__.py
silx/opencl/backprojection.py
silx/opencl/common.py
+silx/opencl/image.py
silx/opencl/linalg.py
silx/opencl/medfilt.py
silx/opencl/processing.py
@@ -657,6 +730,11 @@ silx/opencl/projection.py
silx/opencl/reconstruction.py
silx/opencl/setup.py
silx/opencl/utils.py
+silx/opencl/codec/__init__.py
+silx/opencl/codec/byte_offset.py
+silx/opencl/codec/setup.py
+silx/opencl/codec/test/__init__.py
+silx/opencl/codec/test/test_byte_offset.py
silx/opencl/sift/__init__.py
silx/opencl/sift/alignment.py
silx/opencl/sift/match.py
@@ -682,6 +760,7 @@ silx/opencl/test/__init__.py
silx/opencl/test/test_addition.py
silx/opencl/test/test_array_utils.py
silx/opencl/test/test_backprojection.py
+silx/opencl/test/test_image.py
silx/opencl/test/test_linalg.py
silx/opencl/test/test_medfilt.py
silx/opencl/test/test_projection.py
@@ -712,6 +791,12 @@ silx/resources/gui/icons/close.png
silx/resources/gui/icons/close.svg
silx/resources/gui/icons/colorbar.png
silx/resources/gui/icons/colorbar.svg
+silx/resources/gui/icons/colormap-histogram.png
+silx/resources/gui/icons/colormap-histogram.svg
+silx/resources/gui/icons/colormap-none.png
+silx/resources/gui/icons/colormap-none.svg
+silx/resources/gui/icons/colormap-range.png
+silx/resources/gui/icons/colormap-range.svg
silx/resources/gui/icons/colormap.png
silx/resources/gui/icons/colormap.svg
silx/resources/gui/icons/crop.png
@@ -814,6 +899,8 @@ silx/resources/gui/icons/math-sigma.png
silx/resources/gui/icons/math-sigma.svg
silx/resources/gui/icons/math-smooth.png
silx/resources/gui/icons/math-smooth.svg
+silx/resources/gui/icons/math-square-amplitude.png
+silx/resources/gui/icons/math-square-amplitude.svg
silx/resources/gui/icons/math-substract.png
silx/resources/gui/icons/math-substract.svg
silx/resources/gui/icons/math-swap-sign.png
@@ -983,15 +1070,20 @@ silx/resources/opencl/linalg.cl
silx/resources/opencl/medfilt.cl
silx/resources/opencl/preprocess.cl
silx/resources/opencl/proj.cl
+silx/resources/opencl/codec/byte_offset.cl
+silx/resources/opencl/image/cast.cl
+silx/resources/opencl/image/histogram.cl
+silx/resources/opencl/image/map.cl
+silx/resources/opencl/image/max_min.cl
silx/resources/opencl/sift/addition.cl
silx/resources/opencl/sift/algebra.cl
silx/resources/opencl/sift/convolution.cl
+silx/resources/opencl/sift/descriptor_cpu.cl
+silx/resources/opencl/sift/descriptor_gpu1.cl
+silx/resources/opencl/sift/descriptor_gpu2.cl
silx/resources/opencl/sift/gaussian.cl
silx/resources/opencl/sift/image.cl
silx/resources/opencl/sift/interpolation.cl
-silx/resources/opencl/sift/keypoints_cpu.cl
-silx/resources/opencl/sift/keypoints_gpu1.cl
-silx/resources/opencl/sift/keypoints_gpu2.cl
silx/resources/opencl/sift/matching_cpu.cl
silx/resources/opencl/sift/matching_gpu.cl
silx/resources/opencl/sift/memset.cl
@@ -999,9 +1091,11 @@ silx/resources/opencl/sift/orientation_cpu.cl
silx/resources/opencl/sift/orientation_gpu.cl
silx/resources/opencl/sift/preprocess.cl
silx/resources/opencl/sift/reductions.cl
+silx/resources/opencl/sift/sift.cl
silx/resources/opencl/sift/transform.cl
silx/sx/__init__.py
silx/sx/_plot.py
+silx/sx/_plot3d.py
silx/test/__init__.py
silx/test/test_resources.py
silx/test/test_sx.py
@@ -1010,19 +1104,62 @@ silx/test/utils.py
silx/third_party/EdfFile.py
silx/third_party/TiffIO.py
silx/third_party/__init__.py
+silx/third_party/concurrent_futures.py
silx/third_party/enum.py
+silx/third_party/scipy_spatial.py
silx/third_party/setup.py
silx/third_party/six.py
silx/third_party/_local/__init__.py
silx/third_party/_local/enum.py
silx/third_party/_local/six.py
+silx/third_party/_local/concurrent_futures/__init__.py
+silx/third_party/_local/concurrent_futures/_base.py
+silx/third_party/_local/concurrent_futures/process.py
+silx/third_party/_local/concurrent_futures/thread.py
+silx/third_party/_local/scipy_spatial/__init__.py
+silx/third_party/_local/scipy_spatial/qhull.c
+silx/third_party/_local/scipy_spatial/qhull.pxd
+silx/third_party/_local/scipy_spatial/qhull.pyx
+silx/third_party/_local/scipy_spatial/setlist.pxd
+silx/third_party/_local/scipy_spatial/setup.py
+silx/third_party/_local/scipy_spatial/qhull/src/geom2_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/geom_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/geom_r.h
+silx/third_party/_local/scipy_spatial/qhull/src/global_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/io_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/io_r.h
+silx/third_party/_local/scipy_spatial/qhull/src/libqhull_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/libqhull_r.h
+silx/third_party/_local/scipy_spatial/qhull/src/mem_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/mem_r.h
+silx/third_party/_local/scipy_spatial/qhull/src/merge_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/merge_r.h
+silx/third_party/_local/scipy_spatial/qhull/src/poly2_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/poly_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/poly_r.h
+silx/third_party/_local/scipy_spatial/qhull/src/qhull_ra.h
+silx/third_party/_local/scipy_spatial/qhull/src/qset_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/qset_r.h
+silx/third_party/_local/scipy_spatial/qhull/src/random_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/random_r.h
+silx/third_party/_local/scipy_spatial/qhull/src/rboxlib_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/stat_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/stat_r.h
+silx/third_party/_local/scipy_spatial/qhull/src/user_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/user_r.h
+silx/third_party/_local/scipy_spatial/qhull/src/usermem_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/userprintf_r.c
+silx/third_party/_local/scipy_spatial/qhull/src/userprintf_rbox_r.c
silx/utils/__init__.py
silx/utils/array_like.py
silx/utils/deprecation.py
+silx/utils/exceptions.py
silx/utils/html.py
silx/utils/launcher.py
+silx/utils/property.py
silx/utils/proxy.py
silx/utils/setup.py
+silx/utils/testutils.py
silx/utils/weakref.py
silx/utils/test/__init__.py
silx/utils/test/test_array_like.py
diff --git a/silx/app/convert.py b/silx/app/convert.py
index a092ec1..cd48deb 100644
--- a/silx/app/convert.py
+++ b/silx/app/convert.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2017 European Synchrotron Radiation Facility
+# Copyright (C) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,13 +24,22 @@
"""Convert silx supported data files into HDF5 files"""
import ast
-import sys
import os
import argparse
from glob import glob
import logging
import numpy
-import silx
+import re
+import time
+
+import silx.io
+from silx.io.specfile import is_specfile
+from silx.third_party import six
+
+try:
+ from silx.io import fabioh5
+except ImportError:
+ fabioh5 = None
__authors__ = ["P. Knobel"]
@@ -42,6 +51,129 @@ _logger = logging.getLogger(__name__)
"""Module logger"""
+def c_format_string_to_re(pattern_string):
+ """
+
+ :param pattern_string: C style format string with integer patterns
+ (e.g. "%d", "%04d").
+ Not supported: fixed length padded with whitespaces (e.g "%4d", "%-4d")
+ :return: Equivalent regular expression (e.g. "\d+", "\d{4}")
+ """
+ # escape dots and backslashes
+ pattern_string = pattern_string.replace("\\", "\\\\")
+ pattern_string = pattern_string.replace(".", "\.")
+
+ # %d
+ pattern_string = pattern_string.replace("%d", "([-+]?\d+)")
+
+ # %0nd
+ for sub_pattern in re.findall("%0\d+d", pattern_string):
+ n = int(re.search("%0(\d+)d", sub_pattern).group(1))
+ if n == 1:
+ re_sub_pattern = "([+-]?\d)"
+ else:
+ re_sub_pattern = "([\d+-]\d{%d})" % (n - 1)
+ pattern_string = pattern_string.replace(sub_pattern, re_sub_pattern, 1)
+
+ return pattern_string
+
+
+def drop_indices_before_begin(filenames, regex, begin):
+ """
+
+ :param List[str] filenames: list of filenames
+ :param str regex: Regexp used to find indices in a filename
+ :param str begin: Comma separated list of begin indices
+ :return: List of filenames with only indices >= begin
+ """
+ begin_indices = list(map(int, begin.split(",")))
+ output_filenames = []
+ for fname in filenames:
+ m = re.match(regex, fname)
+ file_indices = list(map(int, m.groups()))
+ if len(file_indices) != len(begin_indices):
+ raise IOError("Number of indices found in filename "
+ "does not match number of parsed end indices.")
+ good_indices = True
+ for i, fidx in enumerate(file_indices):
+ if fidx < begin_indices[i]:
+ good_indices = False
+ if good_indices:
+ output_filenames.append(fname)
+ return output_filenames
+
+
+def drop_indices_after_end(filenames, regex, end):
+ """
+
+ :param List[str] filenames: list of filenames
+ :param str regex: Regexp used to find indices in a filename
+ :param str end: Comma separated list of end indices
+ :return: List of filenames with only indices <= end
+ """
+ end_indices = list(map(int, end.split(",")))
+ output_filenames = []
+ for fname in filenames:
+ m = re.match(regex, fname)
+ file_indices = list(map(int, m.groups()))
+ if len(file_indices) != len(end_indices):
+ raise IOError("Number of indices found in filename "
+ "does not match number of parsed end indices.")
+ good_indices = True
+ for i, fidx in enumerate(file_indices):
+ if fidx > end_indices[i]:
+ good_indices = False
+ if good_indices:
+ output_filenames.append(fname)
+ return output_filenames
+
+
+def are_files_missing_in_series(filenames, regex):
+ """Return True if any file is missing in a list of filenames
+ that are supposed to follow a pattern.
+
+ :param List[str] filenames: list of filenames
+ :param str regex: Regexp used to find indices in a filename
+ :return: boolean
+ :raises AssertionError: if a filename does not match the regexp
+ """
+ previous_indices = None
+ for fname in filenames:
+ m = re.match(regex, fname)
+ assert m is not None, \
+ "regex %s does not match filename %s" % (fname, regex)
+ new_indices = list(map(int, m.groups()))
+ if previous_indices is not None:
+ for old_idx, new_idx in zip(previous_indices, new_indices):
+ if (new_idx - old_idx) > 1:
+ _logger.error("Index increment > 1 in file series: "
+ "previous idx %d, next idx %d",
+ old_idx, new_idx)
+ return True
+ previous_indices = new_indices
+ return False
+
+
+def are_all_specfile(filenames):
+ """Return True if all files in a list are SPEC files.
+ :param List[str] filenames: list of filenames
+ """
+ for fname in filenames:
+ if not is_specfile(fname):
+ return False
+ return True
+
+
+def contains_specfile(filenames):
+ """Return True if any file in a list are SPEC files.
+ :param List[str] filenames: list of filenames
+ """
+ for fname in filenames:
+ if is_specfile(fname):
+ return True
+ return False
+
+
def main(argv):
"""
Main function to launch the converter as an application
@@ -52,15 +184,29 @@ def main(argv):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'input_files',
- nargs="+",
- help='Input files (EDF, SPEC)')
+ nargs="*",
+ help='Input files (EDF, TIFF, SPEC...). When specifying multiple '
+ 'files, you cannot specify both fabio images and SPEC files. '
+ 'Multiple SPEC files will simply be concatenated, with one '
+ 'entry per scan. Multiple image files will be merged into '
+ 'a single entry with a stack of images.')
+ # input_files and --filepattern are mutually exclusive
+ parser.add_argument(
+ '--file-pattern',
+ help='File name pattern for loading a series of indexed image files '
+ '(toto_%%04d.edf). This argument is incompatible with argument '
+ 'input_files. If an output URI with a HDF5 path is provided, '
+ 'only the content of the NXdetector group will be copied there. '
+ 'If no HDF5 path, or just "/", is given, a complete NXdata '
+ 'structure will be created.')
parser.add_argument(
'-o', '--output-uri',
- nargs="?",
- help='Output file (HDF5). If omitted, it will be the '
- 'concatenated input file names, with a ".h5" suffix added.'
- ' An URI can be provided to write the data into a specific '
- 'group in the output file: /path/to/file::/path/to/group')
+ default=time.strftime("%Y%m%d-%H%M%S") + '.h5',
+ help='Output file name (HDF5). An URI can be provided to write'
+ ' the data into a specific group in the output file: '
+ '/path/to/file::/path/to/group. '
+ 'If not provided, the filename defaults to a timestamp:'
+ ' YYYYmmdd-HHMMSS.h5')
parser.add_argument(
'-m', '--mode',
default="w-",
@@ -69,12 +215,26 @@ def main(argv):
'"w-" (write, fail if file exists) or '
'"a" (read/write if exists, create otherwise)')
parser.add_argument(
- '--no-root-group',
+ '--begin',
+ help='First file index, or first file indices to be considered. '
+ 'This argument only makes sense when used together with '
+ '--file-pattern. Provide as many start indices as there '
+ 'are indices in the file pattern, separated by commas. '
+ 'Examples: "--filepattern toto_%%d.edf --begin 100", '
+ ' "--filepattern toto_%%d_%%04d_%%02d.edf --begin 100,2000,5".')
+ parser.add_argument(
+ '--end',
+ help='Last file index, or last file indices to be considered. '
+ 'The same rules as with argument --begin apply. '
+ 'Example: "--filepattern toto_%%d_%%d.edf --end 199,1999"')
+ parser.add_argument(
+ '--add-root-group',
action="store_true",
- help='This option disables the default behavior of creating a '
- 'root group (entry) for each file to be converted. When '
- 'merging multiple input files, this can cause conflicts '
- 'when datasets have the same name (see --overwrite-data).')
+ help='This option causes each input file to be written to a '
+ 'specific root group with the same name as the file. When '
+ 'merging multiple input files, this can help preventing conflicts'
+ ' when datasets have the same name (see --overwrite-data). '
+ 'This option is ignored when using --file-pattern.')
parser.add_argument(
'--overwrite-data',
action="store_true",
@@ -121,7 +281,7 @@ def main(argv):
parser.add_argument(
'--shuffle',
action="store_true",
- help='Enables the byte shuffle filter, may improve the compression '
+ help='Enables the byte shuffle filter. This may improve the compression '
'ratio for block oriented compressors like GZIP or LZF.')
parser.add_argument(
'--fletcher32',
@@ -135,22 +295,10 @@ def main(argv):
options = parser.parse_args(argv[1:])
- # some shells (windows) don't interpret wildcard characters (*, ?, [])
- old_input_list = list(options.input_files)
- options.input_files = []
- for fname in old_input_list:
- globbed_files = glob(fname)
- if not globbed_files:
- # no files found, keep the name as it is, to raise an error later
- options.input_files += [fname]
- else:
- options.input_files += globbed_files
- old_input_list = None
-
if options.debug:
logging.root.setLevel(logging.DEBUG)
- # Import most of the things here to be sure to use the right logging level
+ # Import after parsing --debug
try:
# it should be loaded before h5py
import hdf5plugin # noqa
@@ -177,22 +325,78 @@ def main(argv):
+ " compressions. You can install it using \"pip install hdf5plugin\"."
_logger.debug(message)
+ # Process input arguments (mutually exclusive arguments)
+ if bool(options.input_files) == bool(options.file_pattern is not None):
+ if not options.input_files:
+ message = "You must specify either input files (at least one), "
+ message += "or a file pattern."
+ else:
+ message = "You cannot specify input files and a file pattern"
+ message += " at the same time."
+ _logger.error(message)
+ return -1
+ elif options.input_files:
+ # some shells (windows) don't interpret wildcard characters (*, ?, [])
+ old_input_list = list(options.input_files)
+ options.input_files = []
+ for fname in old_input_list:
+ globbed_files = glob(fname)
+ if not globbed_files:
+ # no files found, keep the name as it is, to raise an error later
+ options.input_files += [fname]
+ else:
+ # glob does not sort files, but the bash shell does
+ options.input_files += sorted(globbed_files)
+ else:
+ # File series
+ dirname = os.path.dirname(options.file_pattern)
+ file_pattern_re = c_format_string_to_re(options.file_pattern) + "$"
+ files_in_dir = glob(os.path.join(dirname, "*"))
+ _logger.debug("""
+ Processing file_pattern
+ dirname: %s
+ file_pattern_re: %s
+ files_in_dir: %s
+ """, dirname, file_pattern_re, files_in_dir)
+
+ options.input_files = sorted(list(filter(lambda name: re.match(file_pattern_re, name),
+ files_in_dir)))
+ _logger.debug("options.input_files: %s", options.input_files)
+
+ if options.begin is not None:
+ options.input_files = drop_indices_before_begin(options.input_files,
+ file_pattern_re,
+ options.begin)
+ _logger.debug("options.input_files after applying --begin: %s",
+ options.input_files)
+
+ if options.end is not None:
+ options.input_files = drop_indices_after_end(options.input_files,
+ file_pattern_re,
+ options.end)
+ _logger.debug("options.input_files after applying --end: %s",
+ options.input_files)
+
+ if are_files_missing_in_series(options.input_files,
+ file_pattern_re):
+ _logger.error("File missing in the file series. Aborting.")
+ return -1
+
+ if not options.input_files:
+ _logger.error("No file matching --file-pattern found.")
+ return -1
+
# Test that the output path is writeable
- if options.output_uri is None:
- input_basenames = [os.path.basename(name) for name in options.input_files]
- output_name = ''.join(input_basenames) + ".h5"
- _logger.info("No output file specified, using %s", output_name)
- hdf5_path = "/"
+ if "::" in options.output_uri:
+ output_name, hdf5_path = options.output_uri.split("::")
else:
- if "::" in options.output_uri:
- output_name, hdf5_path = options.output_uri.split("::")
- else:
- output_name, hdf5_path = options.output_uri, "/"
+ output_name, hdf5_path = options.output_uri, "/"
if os.path.isfile(output_name):
if options.mode == "w-":
- _logger.error("Output file %s exists and mode is 'w-'"
- " (write, file must not exist). Aborting.",
+ _logger.error("Output file %s exists and mode is 'w-' (default)."
+ " Aborting. To append data to an existing file, "
+ "use 'a' or 'r+'.",
output_name)
return -1
elif not os.access(output_name, os.W_OK):
@@ -262,22 +466,80 @@ def main(argv):
if options.fletcher32:
create_dataset_args["fletcher32"] = True
- with h5py.File(output_name, mode=options.mode) as h5f:
- for input_name in options.input_files:
- hdf5_path_for_file = hdf5_path
- if not options.no_root_group:
- hdf5_path_for_file = hdf5_path.rstrip("/") + "/" + os.path.basename(input_name)
- write_to_h5(input_name, h5f,
- h5path=hdf5_path_for_file,
+ if (len(options.input_files) > 1 and
+ not contains_specfile(options.input_files) and
+ not options.add_root_group) or options.file_pattern is not None:
+ # File series -> stack of images
+ if fabioh5 is None:
+ # return a helpful error message if fabio is missing
+ try:
+ import fabio
+ except ImportError:
+ _logger.error("The fabio library is required to convert"
+ " edf files. Please install it with 'pip "
+ "install fabio` and try again.")
+ else:
+ # unexpected problem in silx.io.fabioh5
+ raise
+ return -1
+ input_group = fabioh5.File(file_series=options.input_files)
+ if hdf5_path != "/":
+ # we want to append only data and headers to an existing file
+ input_group = input_group["/scan_0/instrument/detector_0"]
+ with h5py.File(output_name, mode=options.mode) as h5f:
+ write_to_h5(input_group, h5f,
+ h5path=hdf5_path,
overwrite_data=options.overwrite_data,
create_dataset_args=create_dataset_args,
min_size=options.min_size)
- # append the convert command to the creator attribute, for NeXus files
- creator = h5f[hdf5_path_for_file].attrs.get("creator", b"").decode()
- convert_command = " ".join(argv)
- if convert_command not in creator:
- h5f[hdf5_path_for_file].attrs["creator"] = \
- numpy.string_(creator + "; convert command: %s" % " ".join(argv))
+ elif len(options.input_files) == 1 or \
+ are_all_specfile(options.input_files) or\
+ options.add_root_group:
+ # single file, or spec files
+ h5paths_and_groups = []
+ for input_name in options.input_files:
+ hdf5_path_for_file = hdf5_path
+ if options.add_root_group:
+ hdf5_path_for_file = hdf5_path.rstrip("/") + "/" + os.path.basename(input_name)
+ try:
+ h5paths_and_groups.append((hdf5_path_for_file,
+ silx.io.open(input_name)))
+ except IOError:
+ _logger.error("Cannot read file %s. If this is a file format "
+ "supported by the fabio library, you can try to"
+ " install fabio (`pip install fabio`)."
+ " Aborting conversion.",
+ input_name)
+ return -1
+
+ with h5py.File(output_name, mode=options.mode) as h5f:
+ for hdf5_path_for_file, input_group in h5paths_and_groups:
+ write_to_h5(input_group, h5f,
+ h5path=hdf5_path_for_file,
+ overwrite_data=options.overwrite_data,
+ create_dataset_args=create_dataset_args,
+ min_size=options.min_size)
+
+ else:
+ # multiple file, SPEC and fabio images mixed
+ _logger.error("Multiple files with incompatible formats specified. "
+ "You can provide multiple SPEC files or multiple image "
+ "files, but not both.")
+ return -1
+
+ with h5py.File(output_name, mode="r+") as h5f:
+ # append "silx convert" to the creator attribute, for NeXus files
+ previous_creator = h5f.attrs.get("creator", u"")
+ creator = "silx convert (v%s)" % silx.version
+ # only if it not already there
+ if creator not in previous_creator:
+ if not previous_creator:
+ new_creator = creator
+ else:
+ new_creator = previous_creator + "; " + creator
+ h5f.attrs["creator"] = numpy.array(
+ new_creator,
+ dtype=h5py.special_dtype(vlen=six.text_type))
return 0
diff --git a/silx/app/test/test_convert.py b/silx/app/test/test_convert.py
index 3215460..97be3fd 100644
--- a/silx/app/test/test_convert.py
+++ b/silx/app/test/test_convert.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -26,7 +26,7 @@
__authors__ = ["P. Knobel"]
__license__ = "MIT"
-__date__ = "12/09/2017"
+__date__ = "17/01/2018"
import os
@@ -43,7 +43,7 @@ except ImportError:
import silx
from .. import convert
-from silx.test import utils
+from silx.utils import testutils
@@ -103,13 +103,12 @@ class TestConvertCommand(unittest.TestCase):
result = e.args[0]
self.assertEqual(result, 0)
- @unittest.skipUnless(h5py is None,
- "h5py is installed, this test is specific to h5py missing")
- @utils.test_logging(convert._logger.name, error=1)
+ @testutils.test_logging(convert._logger.name, error=1)
def testH5pyNotInstalled(self):
- result = convert.main(["convert", "foo.spec", "bar.edf"])
- # we explicitly return -1 if h5py is not imported
- self.assertNotEqual(result, 0)
+ with testutils.EnsureImportError("h5py"):
+ result = convert.main(["convert", "foo.spec", "bar.edf"])
+ # we explicitly return -1 if h5py is not imported
+ self.assertNotEqual(result, 0)
@unittest.skipIf(h5py is None, "h5py is required to test convert")
def testWrongOption(self):
@@ -122,7 +121,7 @@ class TestConvertCommand(unittest.TestCase):
self.assertNotEqual(result, 0)
@unittest.skipIf(h5py is None, "h5py is required to test convert")
- @utils.test_logging(convert._logger.name, error=3)
+ @testutils.test_logging(convert._logger.name, error=3)
# one error log per missing file + one "Aborted" error log
def testWrongFiles(self):
result = convert.main(["convert", "foo.spec", "bar.edf"])
@@ -136,15 +135,16 @@ class TestConvertCommand(unittest.TestCase):
# write a temporary SPEC file
specname = os.path.join(tempdir, "input.dat")
with io.open(specname, "wb") as fd:
- if sys.version < '3.0':
+ if sys.version_info < (3, ):
fd.write(sftext)
else:
fd.write(bytes(sftext, 'ascii'))
# convert it
h5name = os.path.join(tempdir, "output.h5")
+ assert not os.path.isfile(h5name)
command_list = ["convert", "-m", "w",
- "--no-root-group", specname, "-o", h5name]
+ specname, "-o", h5name]
result = convert.main(command_list)
self.assertEqual(result, 0)
@@ -152,17 +152,16 @@ class TestConvertCommand(unittest.TestCase):
with h5py.File(h5name, "r") as h5f:
title12 = h5f["/1.2/title"][()]
- if sys.version > '3.0':
- title12 = title12.decode()
+ if sys.version_info < (3, ):
+ title12 = title12.encode("utf-8")
self.assertEqual(title12,
- "1 aaaaaa")
+ "aaaaaa")
creator = h5f.attrs.get("creator")
self.assertIsNotNone(creator, "No creator attribute in NXroot group")
- creator = creator.decode() # make sure we can compare creator with native string
- self.assertTrue(creator.startswith("silx %s" % silx.version))
- command = " ".join(command_list)
- self.assertTrue(creator.endswith(command))
+ if sys.version_info < (3, ):
+ creator = creator.encode("utf-8")
+ self.assertIn("silx convert (v%s)" % silx.version, creator)
# delete input file
gc.collect() # necessary to free spec file on Windows
diff --git a/silx/app/test/test_view.py b/silx/app/test/test_view.py
index e55e4f3..aeba0cc 100644
--- a/silx/app/test/test_view.py
+++ b/silx/app/test/test_view.py
@@ -26,29 +26,20 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "29/09/2017"
+__date__ = "09/11/2017"
import unittest
import sys
-import os
+from silx.test.utils import test_options
-# TODO: factor this code with silx.gui.test
-with_qt = False
-if sys.platform.startswith('linux') and not os.environ.get('DISPLAY', ''):
- reason = 'test disabled (DISPLAY env. variable not set)'
- view = None
- TestCaseQt = unittest.TestCase
-elif os.environ.get('WITH_QT_TEST', 'True') == 'False':
- reason = "test disabled (env. variable WITH_QT_TEST=False)"
+if not test_options.WITH_QT_TEST:
view = None
TestCaseQt = unittest.TestCase
else:
from silx.gui.test.utils import TestCaseQt
from .. import view
- with_qt = True
- reason = ""
class QApplicationMock(object):
@@ -73,6 +64,9 @@ class ViewerMock(object):
def appendFile(self, filename):
self.appendFileCalls.append(filename)
+ def setAttribute(self, attr, value):
+ pass
+
def resize(self, size):
pass
@@ -80,7 +74,7 @@ class ViewerMock(object):
pass
-@unittest.skipUnless(with_qt, "Qt binding required for TestLauncher")
+@unittest.skipUnless(test_options.WITH_QT_TEST, test_options.WITH_QT_TEST_REASON)
class TestLauncher(unittest.TestCase):
"""Test command line parsing"""
@@ -133,7 +127,7 @@ class TestLauncher(unittest.TestCase):
class TestViewer(TestCaseQt):
"""Test for Viewer class"""
- @unittest.skipUnless(with_qt, reason)
+ @unittest.skipUnless(test_options.WITH_QT_TEST, test_options.WITH_QT_TEST_REASON)
def testConstruct(self):
if view is not None:
widget = view.Viewer()
diff --git a/silx/app/test_.py b/silx/app/test_.py
index 7f95085..2623c04 100644
--- a/silx/app/test_.py
+++ b/silx/app/test_.py
@@ -25,10 +25,9 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "04/08/2017"
+__date__ = "12/01/2018"
import sys
-import os
import argparse
import logging
import unittest
@@ -91,26 +90,17 @@ def main(argv):
:param argv: Command line arguments
:returns: exit status
"""
+ from silx.test import utils
+
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("-v", "--verbose", default=0,
action="count", dest="verbose",
help="Increase verbosity. Option -v prints additional " +
"INFO messages. Use -vv for full verbosity, " +
"including debug messages and test help strings.")
- parser.add_argument("-x", "--no-gui", dest="gui", default=True,
- action="store_false",
- help="Disable the test of the graphical use interface")
- parser.add_argument("-g", "--no-opengl", dest="opengl", default=True,
- action="store_false",
- help="Disable tests using OpenGL")
- parser.add_argument("-o", "--no-opencl", dest="opencl", default=True,
- action="store_false",
- help="Disable the test of the OpenCL part")
- parser.add_argument("-l", "--low-mem", dest="low_mem", default=False,
- action="store_true",
- help="Disable test with large memory consumption (>100Mbyte")
parser.add_argument("--qt-binding", dest="qt_binding", default=None,
help="Force using a Qt binding, from 'PyQt4', 'PyQt5', or 'PySide'")
+ utils.test_options.add_parser_argument(parser)
options = parser.parse_args(argv[1:])
@@ -127,18 +117,6 @@ def main(argv):
test_verbosity = 2
use_buffer = False
- if not options.gui:
- os.environ["WITH_QT_TEST"] = "False"
-
- if not options.opencl:
- os.environ["SILX_OPENCL"] = "False"
-
- if not options.opengl:
- os.environ["WITH_GL_TEST"] = "False"
-
- if options.low_mem:
- os.environ["SILX_TEST_LOW_MEM"] = "True"
-
if options.qt_binding:
binding = options.qt_binding.lower()
if binding == "pyqt4":
@@ -153,6 +131,9 @@ def main(argv):
else:
raise ValueError("Qt binding '%s' is unknown" % options.qt_binding)
+ # Configure test options
+ utils.test_options.configure(options)
+
# Run the tests
runnerArgs = {}
runnerArgs["verbosity"] = test_verbosity
diff --git a/silx/app/view.py b/silx/app/view.py
index e8507f4..bc4e30c 100644
--- a/silx/app/view.py
+++ b/silx/app/view.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +25,7 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "02/10/2017"
+__date__ = "28/02/2018"
import sys
import os
@@ -36,6 +36,17 @@ import collections
_logger = logging.getLogger(__name__)
"""Module logger"""
+if "silx.gui.qt" not in sys.modules:
+ # Try first PyQt5 and not the priority imposed by silx.gui.qt.
+ # To avoid problem with unittests we only do it if silx.gui.qt is not
+ # yet loaded.
+ # TODO: Can be removed for silx 0.8, as it should be the default binding
+ # of the silx library.
+ try:
+ import PyQt5.QtCore
+ except ImportError:
+ pass
+
from silx.gui import qt
@@ -142,22 +153,28 @@ class Viewer(qt.QMainWindow):
dialog.setWindowTitle("Open")
dialog.setModal(True)
+ # NOTE: hdf5plugin have to be loaded before
+ import silx.io
extensions = collections.OrderedDict()
- # expect h5py
- extensions["HDF5 files"] = "*.h5 *.hdf"
- extensions["NeXus files"] = "*.nx *.nxs *.h5 *.hdf"
- # no dependancy
- extensions["NeXus layout from spec files"] = "*.dat *.spec *.mca"
- extensions["Numpy binary files"] = "*.npz *.npy"
- # expect fabio
- extensions["NeXus layout from raster images"] = "*.edf *.tif *.tiff *.cbf *.mccd"
- extensions["NeXus layout from EDF files"] = "*.edf"
- extensions["NeXus layout from TIFF image files"] = "*.tif *.tiff"
- extensions["NeXus layout from CBF files"] = "*.cbf"
- extensions["NeXus layout from MarCCD image files"] = "*.mccd"
+ for description, ext in silx.io.supported_extensions().items():
+ extensions[description] = " ".join(sorted(list(ext)))
+
+ # NOTE: hdf5plugin have to be loaded before
+ import fabio
+ if fabio is not None:
+ extensions["NeXus layout from EDF files"] = "*.edf"
+ extensions["NeXus layout from TIFF image files"] = "*.tif *.tiff"
+ extensions["NeXus layout from CBF files"] = "*.cbf"
+ extensions["NeXus layout from MarCCD image files"] = "*.mccd"
+
+ all_supported_extensions = set()
+ for name, exts in extensions.items():
+ exts = exts.split(" ")
+ all_supported_extensions.update(exts)
+ all_supported_extensions = sorted(list(all_supported_extensions))
filters = []
- filters.append("All supported files (%s)" % " ".join(extensions.values()))
+ filters.append("All supported files (%s)" % " ".join(all_supported_extensions))
for name, extension in extensions.items():
filters.append("%s (%s)" % (name, extension))
filters.append("All files (*)")
@@ -194,7 +211,7 @@ class Viewer(qt.QMainWindow):
selectedObjects = event.source().selectedH5Nodes(ignoreBrokenLinks=False)
menu = event.menu()
- if len(menu.children()):
+ if not menu.isEmpty():
menu.addSeparator()
# Import it here to be sure to use the right logging level
@@ -280,6 +297,7 @@ def main(argv):
sys.excepthook = qt.exceptionHandler
window = Viewer()
+ window.setAttribute(qt.Qt.WA_DeleteOnClose, True)
window.resize(qt.QSize(640, 480))
for filename in options.files:
diff --git a/silx/gui/_glutils/OpenGLWidget.py b/silx/gui/_glutils/OpenGLWidget.py
index 6cbf8f0..7f600a0 100644
--- a/silx/gui/_glutils/OpenGLWidget.py
+++ b/silx/gui/_glutils/OpenGLWidget.py
@@ -116,6 +116,9 @@ else:
format_.setSwapBehavior(qt.QSurfaceFormat.DoubleBuffer)
self.setFormat(format_)
+ # Enable receiving mouse move events when no buttons are pressed
+ self.setMouseTracking(True)
+
def getDevicePixelRatio(self):
"""Returns the ratio device-independent / device pixel size
@@ -217,7 +220,7 @@ else:
_logger.error('_OpenGLWidget has no parent')
return
- if qt.BINDING == 'PyQt5':
+ if qt.BINDING in ('PyQt5', 'PySide2'):
devicePixelRatio = self.window().windowHandle().devicePixelRatio()
if devicePixelRatio != self.getDevicePixelRatio():
diff --git a/silx/gui/_glutils/Texture.py b/silx/gui/_glutils/Texture.py
index 9f09a86..0875ebe 100644
--- a/silx/gui/_glutils/Texture.py
+++ b/silx/gui/_glutils/Texture.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2014-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2014-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -49,7 +49,8 @@ class Texture(object):
:type data: numpy.ndarray or None
:param format_: Input data format if different from internalFormat
:param shape: If data is None, shape of the texture
- :type shape: 2 or 3-tuple of int (height, width) or (depth, height, width)
+ (height, width) or (depth, height, width)
+ :type shape: List[int]
:param int texUnit: The texture unit to use
:param minFilter: OpenGL texture minimization filter (default: GL_NEAREST)
:param magFilter: OpenGL texture magnification filter (default: GL_LINEAR)
@@ -258,7 +259,7 @@ class Texture(object):
:param format_: The OpenGL format of the data
:param data: The data to use to update the texture
:param offset: The offset in the texture where to copy the data
- :type offset: 2 or 3-tuple of int
+ :type offset: List[int]
:param int texUnit:
The texture unit to use (default: the one provided at init)
"""
diff --git a/silx/gui/_glutils/gl.py b/silx/gui/_glutils/gl.py
index 4b9a7bb..608d9ce 100644
--- a/silx/gui/_glutils/gl.py
+++ b/silx/gui/_glutils/gl.py
@@ -101,7 +101,10 @@ def enabled(capacity, enable=True):
:param bool enable:
True (default) to enable during context, False to disable
"""
- if enable:
+ if bool(enable) == glGetBoolean(capacity):
+ # Already in the right state: noop
+ yield
+ elif enable:
glEnable(capacity)
yield
glDisable(capacity)
diff --git a/silx/gui/_utils.py b/silx/gui/_utils.py
index e29141f..d91a572 100644
--- a/silx/gui/_utils.py
+++ b/silx/gui/_utils.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,7 +24,10 @@
# ###########################################################################*/
"""This module provides convenient functions to use with Qt objects.
-It provides conversion between numpy and QImage.
+It provides:
+- conversion between numpy and QImage:
+ :func:`convertArrayToQImage`, :func:`convertQImageToArray`
+- Execution of function in Qt main thread: :func:`submitToQtMainThread`
"""
from __future__ import division
@@ -38,6 +41,8 @@ __date__ = "16/01/2017"
import sys
import numpy
+from silx.third_party.concurrent_futures import Future
+
from . import qt
@@ -87,7 +92,7 @@ def convertQImageToArray(image):
image = image.convertToFormat(qt.QImage.Format_RGB888)
ptr = image.bits()
- if qt.BINDING != 'PySide':
+ if qt.BINDING not in ('PySide', 'PySide2'):
ptr.setsize(image.byteCount())
if qt.BINDING == 'PyQt4' and sys.version_info[0] == 2:
ptr = ptr.asstring()
@@ -100,3 +105,71 @@ def convertQImageToArray(image):
array = array.reshape(image.height(), -1)[:, :image.width() * 3]
array.shape = image.height(), image.width(), 3
return array
+
+
+class _QtExecutor(qt.QObject):
+ """Executor of tasks in Qt main thread"""
+
+ __sigSubmit = qt.Signal(Future, object, tuple, dict)
+ """Signal used to run tasks."""
+
+ def __init__(self):
+ super(_QtExecutor, self).__init__(parent=None)
+
+ # Makes sure the executor lives in the main thread
+ app = qt.QApplication.instance()
+ assert app is not None
+ mainThread = app.thread()
+ if self.thread() != mainThread:
+ self.moveToThread(mainThread)
+
+ self.__sigSubmit.connect(self.__run)
+
+ def submit(self, fn, *args, **kwargs):
+ """Submit fn(*args, **kwargs) to Qt main thread
+
+ :param callable fn: Function to call in main thread
+ :return: Future object to retrieve result
+ :rtype: concurrent.future.Future
+ """
+ future = Future()
+ self.__sigSubmit.emit(future, fn, args, kwargs)
+ return future
+
+ def __run(self, future, fn, args, kwargs):
+ """Run task in Qt main thread
+
+ :param concurrent.future.Future future:
+ :param callable fn: Function to run
+ :param tuple args: Arguments
+ :param dict kwargs: Keyword arguments
+ """
+ if not future.set_running_or_notify_cancel():
+ return
+
+ try:
+ result = fn(*args, **kwargs)
+ except BaseException as e:
+ future.set_exception(e)
+ else:
+ future.set_result(result)
+
+
+_executor = None
+"""QObject running the tasks in main thread"""
+
+
+def submitToQtMainThread(fn, *args, **kwargs):
+ """Run fn(*args, **kwargs) in Qt's main thread.
+
+ If not called from the main thread, this is run asynchronously.
+
+ :param callable fn: Function to call in main thread.
+ :return: A future object to retrieve the result
+ :rtype: concurrent.future.Future
+ """
+ global _executor
+ if _executor is None: # Lazy-loading
+ _executor = _QtExecutor()
+
+ return _executor.submit(fn, *args, **kwargs)
diff --git a/silx/gui/console.py b/silx/gui/console.py
index 7812e2d..3c69419 100644
--- a/silx/gui/console.py
+++ b/silx/gui/console.py
@@ -129,7 +129,10 @@ if qtconsole is None:
IPython.external.qt_loaders.has_binding = has_binding
- from IPython.qt.console.rich_ipython_widget import RichIPythonWidget
+ try:
+ from IPython.qtconsole.rich_ipython_widget import RichIPythonWidget
+ except ImportError:
+ from IPython.qt.console.rich_ipython_widget import RichIPythonWidget
from IPython.qt.inprocess import QtInProcessKernelManager
diff --git a/silx/gui/data/DataViewer.py b/silx/gui/data/DataViewer.py
index 750c654..5e0b25e 100644
--- a/silx/gui/data/DataViewer.py
+++ b/silx/gui/data/DataViewer.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -32,10 +32,12 @@ from silx.gui.data.DataViews import _normalizeData
import logging
from silx.gui import qt
from silx.gui.data.NumpyAxesSelector import NumpyAxesSelector
+from silx.utils import deprecation
+from silx.utils.property import classproperty
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "03/10/2017"
+__date__ = "26/02/2018"
_logger = logging.getLogger(__name__)
@@ -68,16 +70,65 @@ class DataViewer(qt.QFrame):
viewer.setVisible(True)
"""
- EMPTY_MODE = 0
- PLOT1D_MODE = 10
- PLOT2D_MODE = 20
- PLOT3D_MODE = 30
- RAW_MODE = 40
- RAW_ARRAY_MODE = 41
- RAW_RECORD_MODE = 42
- RAW_SCALAR_MODE = 43
- STACK_MODE = 50
- HDF5_MODE = 60
+ # TODO: Can be removed for silx 0.8
+ @classproperty
+ @deprecation.deprecated(replacement="DataViews.EMPTY_MODE", since_version="0.7", skip_backtrace_count=2)
+ def EMPTY_MODE(self):
+ return DataViews.EMPTY_MODE
+
+ # TODO: Can be removed for silx 0.8
+ @classproperty
+ @deprecation.deprecated(replacement="DataViews.PLOT1D_MODE", since_version="0.7", skip_backtrace_count=2)
+ def PLOT1D_MODE(self):
+ return DataViews.PLOT1D_MODE
+
+ # TODO: Can be removed for silx 0.8
+ @classproperty
+ @deprecation.deprecated(replacement="DataViews.PLOT2D_MODE", since_version="0.7", skip_backtrace_count=2)
+ def PLOT2D_MODE(self):
+ return DataViews.PLOT2D_MODE
+
+ # TODO: Can be removed for silx 0.8
+ @classproperty
+ @deprecation.deprecated(replacement="DataViews.PLOT3D_MODE", since_version="0.7", skip_backtrace_count=2)
+ def PLOT3D_MODE(self):
+ return DataViews.PLOT3D_MODE
+
+ # TODO: Can be removed for silx 0.8
+ @classproperty
+ @deprecation.deprecated(replacement="DataViews.RAW_MODE", since_version="0.7", skip_backtrace_count=2)
+ def RAW_MODE(self):
+ return DataViews.RAW_MODE
+
+ # TODO: Can be removed for silx 0.8
+ @classproperty
+ @deprecation.deprecated(replacement="DataViews.RAW_ARRAY_MODE", since_version="0.7", skip_backtrace_count=2)
+ def RAW_ARRAY_MODE(self):
+ return DataViews.RAW_ARRAY_MODE
+
+ # TODO: Can be removed for silx 0.8
+ @classproperty
+ @deprecation.deprecated(replacement="DataViews.RAW_RECORD_MODE", since_version="0.7", skip_backtrace_count=2)
+ def RAW_RECORD_MODE(self):
+ return DataViews.RAW_RECORD_MODE
+
+ # TODO: Can be removed for silx 0.8
+ @classproperty
+ @deprecation.deprecated(replacement="DataViews.RAW_SCALAR_MODE", since_version="0.7", skip_backtrace_count=2)
+ def RAW_SCALAR_MODE(self):
+ return DataViews.RAW_SCALAR_MODE
+
+ # TODO: Can be removed for silx 0.8
+ @classproperty
+ @deprecation.deprecated(replacement="DataViews.STACK_MODE", since_version="0.7", skip_backtrace_count=2)
+ def STACK_MODE(self):
+ return DataViews.STACK_MODE
+
+ # TODO: Can be removed for silx 0.8
+ @classproperty
+ @deprecation.deprecated(replacement="DataViews.HDF5_MODE", since_version="0.7", skip_backtrace_count=2)
+ def HDF5_MODE(self):
+ return DataViews.HDF5_MODE
displayedViewChanged = qt.Signal(object)
"""Emitted when the displayed view changes"""
@@ -129,7 +180,7 @@ class DataViewer(qt.QFrame):
"""Inisialize the available views"""
views = self.createDefaultViews(self.__stack)
self.__views = list(views)
- self.setDisplayMode(self.EMPTY_MODE)
+ self.setDisplayMode(DataViews.EMPTY_MODE)
def createDefaultViews(self, parent=None):
"""Create and returns available views which can be displayed by default
@@ -137,7 +188,7 @@ class DataViewer(qt.QFrame):
overwriten to provide a different set of viewers.
:param QWidget parent: QWidget parent of the views
- :rtype: list[silx.gui.data.DataViews.DataView]
+ :rtype: List[silx.gui.data.DataViews.DataView]
"""
viewClasses = [
DataViews._EmptyView,
@@ -262,6 +313,7 @@ class DataViewer(qt.QFrame):
def getViewFromModeId(self, modeId):
"""Returns the first available view which have the requested modeId.
+ Return None if modeId does not correspond to an existing view.
:param int modeId: Requested mode id
:rtype: silx.gui.data.DataViews.DataView
@@ -269,7 +321,7 @@ class DataViewer(qt.QFrame):
for view in self.__views:
if view.modeId() == modeId:
return view
- return view
+ return None
def setDisplayMode(self, modeId):
"""Set the displayed view using display mode.
@@ -278,13 +330,14 @@ class DataViewer(qt.QFrame):
:param int modeId: Display mode, one of
- - `EMPTY_MODE`: display nothing
- - `PLOT1D_MODE`: display the data as a curve
- - `PLOT2D_MODE`: display the data as an image
- - `PLOT3D_MODE`: display the data as an isosurface
- - `RAW_MODE`: display the data as a table
- - `STACK_MODE`: display the data as a stack of images
- - `HDF5_MODE`: display the data as a table
+ - `DataViews.EMPTY_MODE`: display nothing
+ - `DataViews.PLOT1D_MODE`: display the data as a curve
+ - `DataViews.IMAGE_MODE`: display the data as an image
+ - `DataViews.PLOT3D_MODE`: display the data as an isosurface
+ - `DataViews.RAW_MODE`: display the data as a table
+ - `DataViews.STACK_MODE`: display the data as a stack of images
+ - `DataViews.HDF5_MODE`: display the data as a table of HDF5 info
+ - `DataViews.NXDATA_MODE`: display the data as NXdata
"""
try:
view = self.getViewFromModeId(modeId)
@@ -377,21 +430,21 @@ class DataViewer(qt.QFrame):
on rendering.
:param object data: data which will be displayed
- :param list[view] available: List of available views, from highest
+ :param List[view] available: List of available views, from highest
priority to lowest.
:rtype: DataView
"""
hdf5View = self.getViewFromModeId(DataViewer.HDF5_MODE)
if hdf5View in available:
return hdf5View
- return self.getViewFromModeId(DataViewer.EMPTY_MODE)
+ return self.getViewFromModeId(DataViews.EMPTY_MODE)
def getDefaultViewFromAvailableViews(self, data, available):
"""Returns the default view which will be used according to available
views.
:param object data: data which will be displayed
- :param list[view] available: List of available views, from highest
+ :param List[view] available: List of available views, from highest
priority to lowest.
:rtype: DataView
"""
@@ -403,7 +456,7 @@ class DataViewer(qt.QFrame):
view = available[0]
else:
# else returns the empty view
- view = self.getViewFromModeId(DataViewer.EMPTY_MODE)
+ view = self.getViewFromModeId(DataViews.EMPTY_MODE)
return view
def __setCurrentAvailableViews(self, availableViews):
@@ -462,3 +515,51 @@ class DataViewer(qt.QFrame):
def displayMode(self):
"""Returns the current display mode"""
return self.__currentView.modeId()
+
+ def replaceView(self, modeId, newView):
+ """Replace one of the builtin data views with a custom view.
+ Return True in case of success, False in case of failure.
+
+ .. note::
+
+ This method must be called just after instantiation, before
+ the viewer is used.
+
+ :param int modeId: Unique mode ID identifying the DataView to
+ be replaced. One of:
+
+ - `DataViews.EMPTY_MODE`
+ - `DataViews.PLOT1D_MODE`
+ - `DataViews.IMAGE_MODE`
+ - `DataViews.PLOT2D_MODE`
+ - `DataViews.COMPLEX_IMAGE_MODE`
+ - `DataViews.PLOT3D_MODE`
+ - `DataViews.RAW_MODE`
+ - `DataViews.STACK_MODE`
+ - `DataViews.HDF5_MODE`
+ - `DataViews.NXDATA_MODE`
+ - `DataViews.NXDATA_INVALID_MODE`
+ - `DataViews.NXDATA_SCALAR_MODE`
+ - `DataViews.NXDATA_CURVE_MODE`
+ - `DataViews.NXDATA_XYVSCATTER_MODE`
+ - `DataViews.NXDATA_IMAGE_MODE`
+ - `DataViews.NXDATA_STACK_MODE`
+
+ :param DataViews.DataView newView: New data view
+ :return: True if replacement was successful, else False
+ """
+ assert isinstance(newView, DataViews.DataView)
+ isReplaced = False
+ for idx, view in enumerate(self.__views):
+ if view.modeId() == modeId:
+ self.__views[idx] = newView
+ isReplaced = True
+ break
+ elif isinstance(view, DataViews.CompositeDataView):
+ isReplaced = view.replaceView(modeId, newView)
+ if isReplaced:
+ break
+
+ if isReplaced:
+ self.__updateAvailableViews()
+ return isReplaced
diff --git a/silx/gui/data/DataViewerFrame.py b/silx/gui/data/DataViewerFrame.py
index e050d4a..89a9992 100644
--- a/silx/gui/data/DataViewerFrame.py
+++ b/silx/gui/data/DataViewerFrame.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -133,7 +133,7 @@ class DataViewerFrame(qt.QWidget):
overwriten to provide a different set of viewers.
:param QWidget parent: QWidget parent of the views
- :rtype: list[silx.gui.data.DataViews.DataView]
+ :rtype: List[silx.gui.data.DataViews.DataView]
"""
return self.__dataViewer._createDefaultViews(parent)
@@ -192,3 +192,16 @@ class DataViewerFrame(qt.QWidget):
- `ARRAY_MODE`: display the data as a table
"""
return self.__dataViewer.setDisplayMode(modeId)
+
+ def getViewFromModeId(self, modeId):
+ """See :meth:`DataViewer.getViewFromModeId`"""
+ return self.__dataViewer.getViewFromModeId(modeId)
+
+ def replaceView(self, modeId, newView):
+ """Replace one of the builtin data views with a custom view.
+ See :meth:`DataViewer.replaceView` for more documentation.
+
+ :param DataViews.DataView newView: New data view
+ :return: True if replacement was successful, else False
+ """
+ return self.__dataViewer.replaceView(modeId, newView)
diff --git a/silx/gui/data/DataViewerSelector.py b/silx/gui/data/DataViewerSelector.py
index 32cc636..35bbe99 100644
--- a/silx/gui/data/DataViewerSelector.py
+++ b/silx/gui/data/DataViewerSelector.py
@@ -29,12 +29,11 @@ from __future__ import division
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "26/01/2017"
+__date__ = "23/01/2018"
import weakref
import functools
from silx.gui import qt
-from silx.gui.data.DataViewer import DataViewer
import silx.utils.weakref
@@ -51,21 +50,36 @@ class DataViewerSelector(qt.QWidget):
self.__group = None
self.__buttons = {}
+ self.__buttonLayout = None
self.__buttonDummy = None
self.__dataViewer = None
+ # Create the fixed layout
+ self.setLayout(qt.QHBoxLayout())
+ layout = self.layout()
+ layout.setContentsMargins(0, 0, 0, 0)
+ self.__buttonLayout = qt.QHBoxLayout()
+ self.__buttonLayout.setContentsMargins(0, 0, 0, 0)
+ layout.addLayout(self.__buttonLayout)
+ layout.addStretch(1)
+
if dataViewer is not None:
self.setDataViewer(dataViewer)
def __updateButtons(self):
if self.__group is not None:
self.__group.deleteLater()
+
+ # Clean up
+ for _, b in self.__buttons.items():
+ b.deleteLater()
+ if self.__buttonDummy is not None:
+ self.__buttonDummy.deleteLater()
+ self.__buttonDummy = None
self.__buttons = {}
self.__buttonDummy = None
self.__group = qt.QButtonGroup(self)
- self.setLayout(qt.QHBoxLayout())
- self.layout().setContentsMargins(0, 0, 0, 0)
if self.__dataViewer is None:
return
@@ -83,19 +97,17 @@ class DataViewerSelector(qt.QWidget):
weakMethod = silx.utils.weakref.WeakMethodProxy(self.__setDisplayedView)
callback = functools.partial(weakMethod, weakView)
button.clicked.connect(callback)
- self.layout().addWidget(button)
+ self.__buttonLayout.addWidget(button)
self.__group.addButton(button)
self.__buttons[view] = button
button = qt.QPushButton("Dummy")
button.setCheckable(True)
button.setVisible(False)
- self.layout().addWidget(button)
+ self.__buttonLayout.addWidget(button)
self.__group.addButton(button)
self.__buttonDummy = button
- self.layout().addStretch(1)
-
self.__updateButtonsVisibility()
self.__displayedViewChanged(self.__dataViewer.displayedView())
@@ -125,7 +137,7 @@ class DataViewerSelector(qt.QWidget):
self.__buttonDummy.setFlat(isFlat)
def __displayedViewChanged(self, view):
- """Called on displayed view changeS"""
+ """Called on displayed view changes"""
selectedButton = self.__buttons.get(view, self.__buttonDummy)
selectedButton.setChecked(True)
@@ -142,12 +154,22 @@ class DataViewerSelector(qt.QWidget):
return
self.__dataViewer.setDisplayedView(view)
+ def __checkAvailableButtons(self):
+ views = set(self.__dataViewer.availableViews())
+ if views == set(self.__buttons.keys()):
+ return
+ # Recreate all the buttons
+ # TODO: We dont have to create everything again
+ # We expect the views stay quite stable
+ self.__updateButtons()
+
def __updateButtonsVisibility(self):
"""Called on data changed"""
if self.__dataViewer is None:
for b in self.__buttons.values():
b.setVisible(False)
else:
+ self.__checkAvailableButtons()
availableViews = set(self.__dataViewer.currentAvailableViews())
for view, button in self.__buttons.items():
button.setVisible(view in availableViews)
diff --git a/silx/gui/data/DataViews.py b/silx/gui/data/DataViews.py
index 1ad997b..ef69441 100644
--- a/silx/gui/data/DataViews.py
+++ b/silx/gui/data/DataViews.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -35,11 +35,13 @@ from silx.gui import qt, icons
from silx.gui.data.TextFormatter import TextFormatter
from silx.io import nxdata
from silx.gui.hdf5 import H5Node
-from silx.io.nxdata import NXdata, get_attr_as_string
+from silx.io.nxdata import get_attr_as_string
+from silx.gui.plot.Colormap import Colormap
+from silx.gui.plot.actions.control import ColormapAction
__authors__ = ["V. Valls", "P. Knobel"]
__license__ = "MIT"
-__date__ = "03/10/2017"
+__date__ = "23/01/2018"
_logger = logging.getLogger(__name__)
@@ -47,7 +49,9 @@ _logger = logging.getLogger(__name__)
# DataViewer modes
EMPTY_MODE = 0
PLOT1D_MODE = 10
-PLOT2D_MODE = 20
+IMAGE_MODE = 20
+PLOT2D_MODE = 21
+COMPLEX_IMAGE_MODE = 22
PLOT3D_MODE = 30
RAW_MODE = 40
RAW_ARRAY_MODE = 41
@@ -56,6 +60,13 @@ RAW_SCALAR_MODE = 43
RAW_HEXA_MODE = 44
STACK_MODE = 50
HDF5_MODE = 60
+NXDATA_MODE = 70
+NXDATA_INVALID_MODE = 71
+NXDATA_SCALAR_MODE = 72
+NXDATA_CURVE_MODE = 73
+NXDATA_XYVSCATTER_MODE = 74
+NXDATA_IMAGE_MODE = 75
+NXDATA_STACK_MODE = 76
def _normalizeData(data):
@@ -77,7 +88,7 @@ def _normalizeComplex(data):
absolute value.
Else returns the input data."""
if hasattr(data, "dtype"):
- isComplex = numpy.issubdtype(data.dtype, numpy.complex)
+ isComplex = numpy.issubdtype(data.dtype, numpy.complexfloating)
else:
isComplex = isinstance(data, numbers.Complex)
if isComplex:
@@ -97,7 +108,7 @@ class DataInfo(object):
self.isComplex = False
self.isBoolean = False
self.isRecord = False
- self.isNXdata = False
+ self.hasNXdata = False
self.shape = tuple()
self.dim = 0
self.size = 0
@@ -105,9 +116,10 @@ class DataInfo(object):
if data is None:
return
- if silx.io.is_group(data) and nxdata.is_valid_nxdata(data):
- self.isNXdata = True
- nxd = nxdata.NXdata(data)
+ if silx.io.is_group(data):
+ nxd = nxdata.get_default(data)
+ if nxd is not None:
+ self.hasNXdata = True
if isinstance(data, numpy.ndarray):
self.isArray = True
@@ -121,7 +133,7 @@ class DataInfo(object):
self.interpretation = get_attr_as_string(data, "interpretation")
else:
self.interpretation = None
- elif self.isNXdata:
+ elif self.hasNXdata:
self.interpretation = nxd.interpretation
else:
self.interpretation = None
@@ -132,12 +144,12 @@ class DataInfo(object):
self.isVoid = data.dtype.fields is None
self.isNumeric = numpy.issubdtype(data.dtype, numpy.number)
self.isRecord = data.dtype.fields is not None
- self.isComplex = numpy.issubdtype(data.dtype, numpy.complex)
+ self.isComplex = numpy.issubdtype(data.dtype, numpy.complexfloating)
self.isBoolean = numpy.issubdtype(data.dtype, numpy.bool_)
- elif self.isNXdata:
+ elif self.hasNXdata:
self.isNumeric = numpy.issubdtype(nxd.signal.dtype,
numpy.number)
- self.isComplex = numpy.issubdtype(nxd.signal.dtype, numpy.complex)
+ self.isComplex = numpy.issubdtype(nxd.signal.dtype, numpy.complexfloating)
self.isBoolean = numpy.issubdtype(nxd.signal.dtype, numpy.bool_)
else:
self.isNumeric = isinstance(data, numbers.Number)
@@ -147,7 +159,7 @@ class DataInfo(object):
if hasattr(data, "shape"):
self.shape = data.shape
- elif self.isNXdata:
+ elif self.hasNXdata:
self.shape = nxd.signal.shape
else:
self.shape = tuple()
@@ -172,6 +184,12 @@ class DataView(object):
"""Priority returned when the requested data can't be displayed by the
view."""
+ _defaultColormap = None
+ """Store a default colormap shared with all the views"""
+
+ _defaultColorDialog = None
+ """Store a default color dialog shared with all the views"""
+
def __init__(self, parent, modeId=None, icon=None, label=None):
"""Constructor
@@ -187,6 +205,32 @@ class DataView(object):
icon = qt.QIcon()
self.__icon = icon
+ @staticmethod
+ def defaultColormap():
+ """Returns a shared colormap as default for all the views.
+
+ :rtype: Colormap
+ """
+ if DataView._defaultColormap is None:
+ DataView._defaultColormap = Colormap(name="viridis")
+ return DataView._defaultColormap
+
+ @staticmethod
+ def defaultColorDialog():
+ """Returns a shared color dialog as default for all the views.
+
+ :rtype: ColorDialog
+ """
+ if DataView._defaultColorDialog is None:
+ DataView._defaultColorDialog = ColormapAction._createDialog(qt.QApplication.instance().activeWindow())
+ return DataView._defaultColorDialog
+
+ @staticmethod
+ def _cleanUpCache():
+ """Clean up the cache. Needed for tests"""
+ DataView._defaultColormap = None
+ DataView._defaultColorDialog = None
+
def icon(self):
"""Returns the default icon"""
return self.__icon
@@ -305,6 +349,13 @@ class CompositeDataView(DataView):
"""Add a new dataview to the available list."""
self.__views[dataView] = None
+ def availableViews(self):
+ """Returns the list of registered views
+
+ :rtype: List[DataView]
+ """
+ return list(self.__views.keys())
+
def getBestView(self, data, info):
"""Returns the best view according to priorities."""
views = [(v.getDataPriority(data, info), v) for v in self.__views.keys()]
@@ -374,6 +425,38 @@ class CompositeDataView(DataView):
else:
return view.getDataPriority(data, info)
+ def replaceView(self, modeId, newView):
+ """Replace a data view with a custom view.
+ Return True in case of success, False in case of failure.
+
+ .. note::
+
+ This method must be called just after instantiation, before
+ the viewer is used.
+
+ :param int modeId: Unique mode ID identifying the DataView to
+ be replaced.
+ :param DataViews.DataView newView: New data view
+ :return: True if replacement was successful, else False
+ """
+ oldView = None
+ for view in self.__views:
+ if view.modeId() == modeId:
+ oldView = view
+ break
+ elif isinstance(view, CompositeDataView):
+ # recurse
+ if view.replaceView(modeId, newView):
+ return True
+ if oldView is None:
+ return False
+
+ # replace oldView with new view in dict
+ self.__views = OrderedDict(
+ (newView, None) if view is oldView else (view, idx) for
+ view, idx in self.__views.items())
+ return True
+
class _EmptyView(DataView):
"""Dummy view to display nothing"""
@@ -457,6 +540,8 @@ class _Plot2dView(DataView):
def createWidget(self, parent):
from silx.gui import plot
widget = plot.Plot2D(parent=parent)
+ widget.setDefaultColormap(self.defaultColormap())
+ widget.getColormapAction().setColorDialog(self.defaultColorDialog())
widget.getIntensityHistogramAction().setVisible(True)
widget.setKeepDataAspectRatio(True)
widget.getXAxis().setLabel('X')
@@ -582,13 +667,18 @@ class _ComplexImageView(DataView):
def __init__(self, parent):
super(_ComplexImageView, self).__init__(
parent=parent,
- modeId=PLOT2D_MODE,
+ modeId=COMPLEX_IMAGE_MODE,
label="Complex Image",
icon=icons.getQIcon("view-2d"))
def createWidget(self, parent):
from silx.gui.plot.ComplexImageView import ComplexImageView
widget = ComplexImageView(parent=parent)
+ widget.setColormap(self.defaultColormap(), mode=ComplexImageView.Mode.ABSOLUTE)
+ widget.setColormap(self.defaultColormap(), mode=ComplexImageView.Mode.SQUARE_AMPLITUDE)
+ widget.setColormap(self.defaultColormap(), mode=ComplexImageView.Mode.REAL)
+ widget.setColormap(self.defaultColormap(), mode=ComplexImageView.Mode.IMAGINARY)
+ widget.getPlot().getColormapAction().setColorDialog(self.defaultColorDialog())
widget.getPlot().getIntensityHistogramAction().setVisible(True)
widget.getPlot().setKeepDataAspectRatio(True)
widget.getXAxis().setLabel('X')
@@ -681,6 +771,8 @@ class _StackView(DataView):
def createWidget(self, parent):
from silx.gui import plot
widget = plot.StackView(parent=parent)
+ widget.setColormap(self.defaultColormap())
+ widget.getPlot().getColormapAction().setColorDialog(self.defaultColorDialog())
widget.setKeepDataAspectRatio(True)
widget.setLabels(self.axesNames(None, None))
# hide default option panel
@@ -699,6 +791,8 @@ class _StackView(DataView):
def setData(self, data):
data = self.normalizeData(data)
self.getWidget().setStack(stack=data, reset=self.__resetZoomNextTime)
+ # Override the colormap, while setStack overwrite it
+ self.getWidget().setColormap(self.defaultColormap())
self.__resetZoomNextTime = False
def axesNames(self, data, info):
@@ -736,7 +830,11 @@ class _ScalarView(DataView):
d = self.normalizeData(data)
if silx.io.is_dataset(d):
d = d[()]
- text = self.__formatter.toString(d, data.dtype)
+ dtype = None
+ if data is not None:
+ if hasattr(data, "dtype"):
+ dtype = data.dtype
+ text = self.__formatter.toString(d, dtype)
self.getWidget().setText(text)
def axesNames(self, data, info):
@@ -891,18 +989,111 @@ class _ImageView(CompositeDataView):
def __init__(self, parent):
super(_ImageView, self).__init__(
parent=parent,
- modeId=PLOT2D_MODE,
+ modeId=IMAGE_MODE,
label="Image",
icon=icons.getQIcon("view-2d"))
self.addView(_ComplexImageView(parent))
self.addView(_Plot2dView(parent))
+class _InvalidNXdataView(DataView):
+ """DataView showing a simple label with an error message
+ to inform that a group with @NX_class=NXdata cannot be
+ interpreted by any NXDataview."""
+ def __init__(self, parent):
+ DataView.__init__(self, parent,
+ modeId=NXDATA_INVALID_MODE)
+ self._msg = ""
+
+ def createWidget(self, parent):
+ widget = qt.QLabel(parent)
+ widget.setWordWrap(True)
+ widget.setStyleSheet("QLabel { color : red; }")
+ return widget
+
+ def axesNames(self, data, info):
+ return []
+
+ def clear(self):
+ self.getWidget().setText("")
+
+ def setData(self, data):
+ self.getWidget().setText(self._msg)
+
+ def getDataPriority(self, data, info):
+ data = self.normalizeData(data)
+ if silx.io.is_group(data):
+ nxd = nxdata.get_default(data)
+ nx_class = get_attr_as_string(data, "NX_class")
+
+ if nxd is None:
+ if nx_class == "NXdata":
+ # invalid: could not even be parsed by NXdata
+ self._msg = "Group has @NX_class = NXdata, but could not be interpreted"
+ self._msg += " as valid NXdata."
+ return 100
+ elif nx_class == "NXentry":
+ if "default" not in data.attrs:
+ # no link to NXdata, no problem
+ return DataView.UNSUPPORTED
+ self._msg = "NXentry group provides a @default attribute,"
+ default_nxdata_name = data.attrs["default"]
+ if default_nxdata_name not in data:
+ self._msg += " but no corresponding NXdata group exists."
+ elif get_attr_as_string(data[default_nxdata_name], "NX_class") != "NXdata":
+ self._msg += " but the corresponding item is not a "
+ self._msg += "NXdata group."
+ else:
+ self._msg += " but the corresponding NXdata seems to be"
+ self._msg += " malformed."
+ return 100
+ elif nx_class == "NXroot" or silx.io.is_file(data):
+ if "default" not in data.attrs:
+ # no link to NXentry, no problem
+ return DataView.UNSUPPORTED
+ default_entry_name = data.attrs["default"]
+ if default_entry_name not in data:
+ # this is a problem, but not NXdata related
+ return DataView.UNSUPPORTED
+ default_entry = data[default_entry_name]
+ if "default" not in default_entry.attrs:
+ # no NXdata specified, no problemo
+ return DataView.UNSUPPORTED
+ default_nxdata_name = default_entry.attrs["default"]
+ self._msg = "NXroot group provides a @default attribute "
+ self._msg += "pointing to a NXentry which defines its own "
+ self._msg += "@default attribute, "
+ if default_nxdata_name not in default_entry:
+ self._msg += " but no corresponding NXdata group exists."
+ elif get_attr_as_string(default_entry[default_nxdata_name],
+ "NX_class") != "NXdata":
+ self._msg += " but the corresponding item is not a "
+ self._msg += "NXdata group."
+ else:
+ self._msg += " but the corresponding NXdata seems to be"
+ self._msg += " malformed."
+ return 100
+ else:
+ # Not pretending to be NXdata, no problem
+ return DataView.UNSUPPORTED
+
+ is_scalar = nxd.signal_is_0d or nxd.interpretation in ["scalar", "scaler"]
+ if not (is_scalar or nxd.is_curve or nxd.is_x_y_value_scatter or
+ nxd.is_image or nxd.is_stack):
+ # invalid: cannot be plotted by any widget (I cannot imagine a case)
+ self._msg = "NXdata seems valid, but cannot be displayed "
+ self._msg += "by any existing plot widget."
+ return 100
+
+ return DataView.UNSUPPORTED
+
+
class _NXdataScalarView(DataView):
"""DataView using a table view for displaying NXdata scalars:
0-D signal or n-D signal with *@interpretation=scalar*"""
def __init__(self, parent):
- DataView.__init__(self, parent)
+ DataView.__init__(self, parent,
+ modeId=NXDATA_SCALAR_MODE)
def createWidget(self, parent):
from silx.gui.data.ArrayTableWidget import ArrayTableWidget
@@ -919,14 +1110,17 @@ class _NXdataScalarView(DataView):
def setData(self, data):
data = self.normalizeData(data)
- signal = NXdata(data).signal
+ # data could be a NXdata or an NXentry
+ nxd = nxdata.get_default(data)
+ signal = nxd.signal
self.getWidget().setArrayData(signal,
labels=True)
def getDataPriority(self, data, info):
data = self.normalizeData(data)
- if info.isNXdata:
- nxd = NXdata(data)
+
+ if info.hasNXdata:
+ nxd = nxdata.get_default(data)
if nxd.signal_is_0d or nxd.interpretation in ["scalar", "scaler"]:
return 100
return DataView.UNSUPPORTED
@@ -940,7 +1134,8 @@ class _NXdataCurveView(DataView):
a 1-D signal with one axis whose values are not monotonically increasing.
"""
def __init__(self, parent):
- DataView.__init__(self, parent)
+ DataView.__init__(self, parent,
+ modeId=NXDATA_CURVE_MODE)
def createWidget(self, parent):
from silx.gui.data.NXdataWidgets import ArrayCurvePlot
@@ -956,29 +1151,34 @@ class _NXdataCurveView(DataView):
def setData(self, data):
data = self.normalizeData(data)
- nxd = NXdata(data)
- signal_name = get_attr_as_string(data, "signal")
- group_name = data.name
+ nxd = nxdata.get_default(data)
+ signals_names = [nxd.signal_name] + nxd.auxiliary_signals_names
if nxd.axes_dataset_names[-1] is not None:
x_errors = nxd.get_axis_errors(nxd.axes_dataset_names[-1])
else:
x_errors = None
- self.getWidget().setCurveData(nxd.signal, nxd.axes[-1],
- yerror=nxd.errors, xerror=x_errors,
- ylabel=signal_name, xlabel=nxd.axes_names[-1],
- title="NXdata group " + group_name)
+ # this fix is necessary until the next release of PyMca (5.2.3 or 5.3.0)
+ # see https://github.com/vasole/pymca/issues/144 and https://github.com/vasole/pymca/pull/145
+ if not hasattr(self.getWidget(), "setCurvesData") and \
+ hasattr(self.getWidget(), "setCurveData"):
+ _logger.warning("Using deprecated ArrayCurvePlot API, "
+ "without support of auxiliary signals")
+ self.getWidget().setCurveData(nxd.signal, nxd.axes[-1],
+ yerror=nxd.errors, xerror=x_errors,
+ ylabel=nxd.signal_name, xlabel=nxd.axes_names[-1],
+ title=nxd.title or nxd.signal_name)
+ return
+
+ self.getWidget().setCurvesData([nxd.signal] + nxd.auxiliary_signals, nxd.axes[-1],
+ yerror=nxd.errors, xerror=x_errors,
+ ylabels=signals_names, xlabel=nxd.axes_names[-1],
+ title=nxd.title or signals_names[0])
def getDataPriority(self, data, info):
data = self.normalizeData(data)
- if info.isNXdata:
- nxd = NXdata(data)
- if nxd.is_x_y_value_scatter or nxd.is_unsupported_scatter:
- return DataView.UNSUPPORTED
- if nxd.signal_is_1d and \
- not nxd.interpretation in ["scalar", "scaler"]:
- return 100
- if nxd.interpretation == "spectrum":
+ if info.hasNXdata:
+ if nxdata.get_default(data).is_curve:
return 100
return DataView.UNSUPPORTED
@@ -987,11 +1187,12 @@ class _NXdataXYVScatterView(DataView):
"""DataView using a Plot1D for displaying NXdata 3D scatters as
a scatter of coloured points (1-D signal with 2 axes)"""
def __init__(self, parent):
- DataView.__init__(self, parent)
+ DataView.__init__(self, parent,
+ modeId=NXDATA_XYVSCATTER_MODE)
def createWidget(self, parent):
- from silx.gui.data.NXdataWidgets import ArrayCurvePlot
- widget = ArrayCurvePlot(parent)
+ from silx.gui.data.NXdataWidgets import XYVScatterPlot
+ widget = XYVScatterPlot(parent)
return widget
def axesNames(self, data, info):
@@ -1003,10 +1204,7 @@ class _NXdataXYVScatterView(DataView):
def setData(self, data):
data = self.normalizeData(data)
- nxd = NXdata(data)
- signal_name = get_attr_as_string(data, "signal")
- # signal_errors = nx.errors # not supported
- group_name = data.name
+ nxd = nxdata.get_default(data)
x_axis, y_axis = nxd.axes[-2:]
x_label, y_label = nxd.axes_names[-2:]
@@ -1020,16 +1218,18 @@ class _NXdataXYVScatterView(DataView):
else:
y_errors = None
- self.getWidget().setCurveData(y_axis, x_axis, values=nxd.signal,
- yerror=y_errors, xerror=x_errors,
- ylabel=signal_name, xlabel=x_label,
- title="NXdata group " + group_name)
+ self.getWidget().setScattersData(y_axis, x_axis, values=[nxd.signal] + nxd.auxiliary_signals,
+ yerror=y_errors, xerror=x_errors,
+ ylabel=y_label, xlabel=x_label,
+ title=nxd.title,
+ scatter_titles=[nxd.signal_name] + nxd.auxiliary_signals_names)
def getDataPriority(self, data, info):
data = self.normalizeData(data)
- if info.isNXdata:
- if NXdata(data).is_x_y_value_scatter:
+ if info.hasNXdata:
+ if nxdata.get_default(data).is_x_y_value_scatter:
return 100
+
return DataView.UNSUPPORTED
@@ -1037,11 +1237,14 @@ class _NXdataImageView(DataView):
"""DataView using a Plot2D for displaying NXdata images:
2-D signal or n-D signals with *@interpretation=spectrum*."""
def __init__(self, parent):
- DataView.__init__(self, parent)
+ DataView.__init__(self, parent,
+ modeId=NXDATA_IMAGE_MODE)
def createWidget(self, parent):
from silx.gui.data.NXdataWidgets import ArrayImagePlot
widget = ArrayImagePlot(parent)
+ widget.getPlot().setDefaultColormap(self.defaultColormap())
+ widget.getPlot().getColormapAction().setColorDialog(self.defaultColorDialog())
return widget
def axesNames(self, data, info):
@@ -1053,36 +1256,41 @@ class _NXdataImageView(DataView):
def setData(self, data):
data = self.normalizeData(data)
- nxd = NXdata(data)
- signal_name = get_attr_as_string(data, "signal")
- group_name = data.name
- y_axis, x_axis = nxd.axes[-2:]
- y_label, x_label = nxd.axes_names[-2:]
+ nxd = nxdata.get_default(data)
+ isRgba = nxd.interpretation == "rgba-image"
+
+ # last two axes are Y & X
+ img_slicing = slice(-2, None) if not isRgba else slice(-3, -1)
+ y_axis, x_axis = nxd.axes[img_slicing]
+ y_label, x_label = nxd.axes_names[img_slicing]
self.getWidget().setImageData(
- nxd.signal, x_axis=x_axis, y_axis=y_axis,
- signal_name=signal_name, xlabel=x_label, ylabel=y_label,
- title="NXdata group %s: %s" % (group_name, signal_name))
+ [nxd.signal] + nxd.auxiliary_signals,
+ x_axis=x_axis, y_axis=y_axis,
+ signals_names=[nxd.signal_name] + nxd.auxiliary_signals_names,
+ xlabel=x_label, ylabel=y_label,
+ title=nxd.title, isRgba=isRgba)
def getDataPriority(self, data, info):
data = self.normalizeData(data)
- if info.isNXdata:
- nxd = NXdata(data)
- if nxd.signal_is_2d:
- if nxd.interpretation not in ["scalar", "spectrum", "scaler"]:
- return 100
- if nxd.interpretation == "image":
+
+ if info.hasNXdata:
+ if nxdata.get_default(data).is_image:
return 100
+
return DataView.UNSUPPORTED
class _NXdataStackView(DataView):
def __init__(self, parent):
- DataView.__init__(self, parent)
+ DataView.__init__(self, parent,
+ modeId=NXDATA_STACK_MODE)
def createWidget(self, parent):
from silx.gui.data.NXdataWidgets import ArrayStackPlot
widget = ArrayStackPlot(parent)
+ widget.getStackView().setColormap(self.defaultColormap())
+ widget.getStackView().getPlot().getColormapAction().setColorDialog(self.defaultColorDialog())
return widget
def axesNames(self, data, info):
@@ -1094,26 +1302,27 @@ class _NXdataStackView(DataView):
def setData(self, data):
data = self.normalizeData(data)
- nxd = NXdata(data)
- signal_name = get_attr_as_string(data, "signal")
- group_name = data.name
+ nxd = nxdata.get_default(data)
+ signal_name = nxd.signal_name
z_axis, y_axis, x_axis = nxd.axes[-3:]
z_label, y_label, x_label = nxd.axes_names[-3:]
+ title = nxd.title or signal_name
- self.getWidget().setStackData(
+ widget = self.getWidget()
+ widget.setStackData(
nxd.signal, x_axis=x_axis, y_axis=y_axis, z_axis=z_axis,
signal_name=signal_name,
xlabel=x_label, ylabel=y_label, zlabel=z_label,
- title="NXdata group %s: %s" % (group_name, signal_name))
+ title=title)
+ # Override the colormap, while setStack overwrite it
+ widget.getStackView().setColormap(self.defaultColormap())
def getDataPriority(self, data, info):
data = self.normalizeData(data)
- if info.isNXdata:
- nxd = NXdata(data)
- if nxd.signal_ndim >= 3:
- if nxd.interpretation not in ["scalar", "scaler",
- "spectrum", "image"]:
- return 100
+ if info.hasNXdata:
+ if nxdata.get_default(data).is_stack:
+ return 100
+
return DataView.UNSUPPORTED
@@ -1124,8 +1333,10 @@ class _NXdataView(CompositeDataView):
super(_NXdataView, self).__init__(
parent=parent,
label="NXdata",
+ modeId=NXDATA_MODE,
icon=icons.getQIcon("view-nexus"))
+ self.addView(_InvalidNXdataView(parent))
self.addView(_NXdataScalarView(parent))
self.addView(_NXdataCurveView(parent))
self.addView(_NXdataXYVScatterView(parent))
diff --git a/silx/gui/data/Hdf5TableView.py b/silx/gui/data/Hdf5TableView.py
index ba737e3..e4a0747 100644
--- a/silx/gui/data/Hdf5TableView.py
+++ b/silx/gui/data/Hdf5TableView.py
@@ -30,7 +30,7 @@ from __future__ import division
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "29/09/2017"
+__date__ = "10/10/2017"
import functools
import os.path
@@ -330,7 +330,7 @@ class Hdf5TableModel(HierarchicalTableView.HierarchicalTableModel):
self.__data.addHeaderRow(headerLabel="Data info")
- if h5py is not None and hasattr(obj, "id"):
+ if h5py is not None and hasattr(obj, "id") and hasattr(obj.id, "get_type"):
# display the HDF5 type
self.__data.addHeaderValueRow("HDF5 type", self.__formatHdf5Type)
self.__data.addHeaderValueRow("dtype", self.__formatDType)
@@ -345,21 +345,22 @@ class Hdf5TableModel(HierarchicalTableView.HierarchicalTableModel):
# h5py also expose fletcher32 and shuffle attributes, but it is also
# part of the filters
if hasattr(obj, "shape") and hasattr(obj, "id"):
- dcpl = obj.id.get_create_plist()
- if dcpl.get_nfilters() > 0:
- self.__data.addHeaderRow(headerLabel="Compression info")
- pos = _CellData(value="Position", isHeader=True)
- hdf5id = _CellData(value="HDF5 ID", isHeader=True)
- name = _CellData(value="Name", isHeader=True)
- options = _CellData(value="Options", isHeader=True)
- self.__data.addRow(pos, hdf5id, name, options)
- for index in range(dcpl.get_nfilters()):
- callback = lambda index, dataIndex, x: self.__get_filter_info(x, index)[dataIndex]
- pos = _CellData(value=functools.partial(callback, index, 0))
- hdf5id = _CellData(value=functools.partial(callback, index, 1))
- name = _CellData(value=functools.partial(callback, index, 2))
- options = _CellData(value=functools.partial(callback, index, 3))
- self.__data.addRow(pos, hdf5id, name, options)
+ if hasattr(obj.id, "get_create_plist"):
+ dcpl = obj.id.get_create_plist()
+ if dcpl.get_nfilters() > 0:
+ self.__data.addHeaderRow(headerLabel="Compression info")
+ pos = _CellData(value="Position", isHeader=True)
+ hdf5id = _CellData(value="HDF5 ID", isHeader=True)
+ name = _CellData(value="Name", isHeader=True)
+ options = _CellData(value="Options", isHeader=True)
+ self.__data.addRow(pos, hdf5id, name, options)
+ for index in range(dcpl.get_nfilters()):
+ callback = lambda index, dataIndex, x: self.__get_filter_info(x, index)[dataIndex]
+ pos = _CellData(value=functools.partial(callback, index, 0))
+ hdf5id = _CellData(value=functools.partial(callback, index, 1))
+ name = _CellData(value=functools.partial(callback, index, 2))
+ options = _CellData(value=functools.partial(callback, index, 3))
+ self.__data.addRow(pos, hdf5id, name, options)
if hasattr(obj, "attrs"):
if len(obj.attrs) > 0:
diff --git a/silx/gui/data/NXdataWidgets.py b/silx/gui/data/NXdataWidgets.py
index 7aaf3ad..ae2911d 100644
--- a/silx/gui/data/NXdataWidgets.py
+++ b/silx/gui/data/NXdataWidgets.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -26,13 +26,15 @@
"""
__authors__ = ["P. Knobel"]
__license__ = "MIT"
-__date__ = "27/06/2017"
+__date__ = "20/12/2017"
import numpy
from silx.gui import qt
from silx.gui.data.NumpyAxesSelector import NumpyAxesSelector
from silx.gui.plot import Plot1D, Plot2D, StackView
+from silx.gui.plot.Colormap import Colormap
+from silx.gui.widgets.FrameBrowser import HorizontalSliderWithBrowser
from silx.math.calibration import ArrayCalibration, NoCalibration, LinearCalibration
@@ -60,83 +62,79 @@ class ArrayCurvePlot(qt.QWidget):
"""
super(ArrayCurvePlot, self).__init__(parent)
- self.__signal = None
- self.__signal_name = None
+ self.__signals = None
+ self.__signals_names = None
self.__signal_errors = None
self.__axis = None
self.__axis_name = None
- self.__axis_errors = None
+ self.__x_axis_errors = None
self.__values = None
- self.__first_curve_added = False
-
self._plot = Plot1D(self)
- self._plot.setDefaultColormap( # for scatters
- {"name": "viridis",
- "vmin": 0., "vmax": 1., # ignored (autoscale) but mandatory
- "normalization": "linear",
- "autoscale": True})
self.selectorDock = qt.QDockWidget("Data selector", self._plot)
# not closable
self.selectorDock.setFeatures(qt.QDockWidget.DockWidgetMovable |
- qt.QDockWidget.DockWidgetFloatable)
+ qt.QDockWidget.DockWidgetFloatable)
self._selector = NumpyAxesSelector(self.selectorDock)
self._selector.setNamedAxesSelectorVisibility(False)
self.__selector_is_connected = False
self.selectorDock.setWidget(self._selector)
self._plot.addTabbedDockWidget(self.selectorDock)
+ self._plot.sigActiveCurveChanged.connect(self._setYLabelFromActiveLegend)
+
layout = qt.QGridLayout()
layout.setContentsMargins(0, 0, 0, 0)
- layout.addWidget(self._plot, 0, 0)
+ layout.addWidget(self._plot, 0, 0)
self.setLayout(layout)
- def setCurveData(self, y, x=None, values=None,
- yerror=None, xerror=None,
- ylabel=None, xlabel=None, title=None):
+ def getPlot(self):
+ """Returns the plot used for the display
+
+ :rtype: Plot1D
+ """
+ return self._plot
+
+ def setCurvesData(self, ys, x=None,
+ yerror=None, xerror=None,
+ ylabels=None, xlabel=None, title=None):
"""
- :param y: dataset to be represented by the y (vertical) axis.
- For a scatter, this must be a 1D array and x and values must be
- 1-D arrays of the same size.
- In other cases, it can be a n-D array whose last dimension must
+ :param List[ndarray] ys: List of arrays to be represented by the y (vertical) axis.
+ It can be multiple n-D array whose last dimension must
have the same length as x (and values must be None)
- :param x: 1-D dataset used as the curve's x values. If provided,
+ :param ndarray x: 1-D dataset used as the curve's x values. If provided,
its lengths must be equal to the length of the last dimension of
``y`` (and equal to the length of ``value``, for a scatter plot).
- :param values: Values, to be provided for a x-y-value scatter plot.
- This will be used to compute the color map and assign colors
- to the points.
- :param yerror: 1-D dataset of errors for y, or None
- :param xerror: 1-D dataset of errors for x, or None
- :param ylabel: Label for Y axis
- :param xlabel: Label for X axis
- :param title: Graph title
+ :param ndarray yerror: Single array of errors for y (same shape), or None.
+ There can only be one array, and it applies to the first/main y
+ (no y errors for auxiliary_signals curves).
+ :param ndarray xerror: 1-D dataset of errors for x, or None
+ :param str ylabels: Labels for each curve's Y axis
+ :param str xlabel: Label for X axis
+ :param str title: Graph title
"""
- self.__signal = y
- self.__signal_name = ylabel or "Y"
+ self.__signals = ys
+ self.__signals_names = ylabels or (["Y"] * len(ys))
self.__signal_errors = yerror
self.__axis = x
self.__axis_name = xlabel
- self.__axis_errors = xerror
- self.__values = values
+ self.__x_axis_errors = xerror
if self.__selector_is_connected:
self._selector.selectionChanged.disconnect(self._updateCurve)
self.__selector_is_connected = False
- self._selector.setData(y)
- self._selector.setAxisNames([ylabel or "Y"])
+ self._selector.setData(ys[0])
+ self._selector.setAxisNames(["Y"])
- if len(y.shape) < 2:
+ if len(ys[0].shape) < 2:
self.selectorDock.hide()
else:
self.selectorDock.show()
self._plot.setGraphTitle(title or "")
- self._plot.getXAxis().setLabel(self.__axis_name or "X")
- self._plot.getYAxis().setLabel(self.__signal_name)
self._updateCurve()
if not self.__selector_is_connected:
@@ -144,52 +142,165 @@ class ArrayCurvePlot(qt.QWidget):
self.__selector_is_connected = True
def _updateCurve(self):
- y = self._selector.selectedData()
+ selection = self._selector.selection()
+ ys = [sig[selection] for sig in self.__signals]
+ y0 = ys[0]
+ len_y = len(y0)
x = self.__axis
if x is None:
- x = numpy.arange(len(y))
+ x = numpy.arange(len_y)
elif numpy.isscalar(x) or len(x) == 1:
# constant axis
- x = x * numpy.ones_like(y)
- elif len(x) == 2 and len(y) != 2:
+ x = x * numpy.ones_like(y0)
+ elif len(x) == 2 and len_y != 2:
# linear calibration a + b * x
- x = x[0] + x[1] * numpy.arange(len(y))
- legend = self.__signal_name + "["
- for sl in self._selector.selection():
- if sl == slice(None):
- legend += ":, "
- else:
- legend += str(sl) + ", "
- legend = legend[:-2] + "]"
- if self.__signal_errors is not None:
- y_errors = self.__signal_errors[self._selector.selection()]
- else:
- y_errors = None
+ x = x[0] + x[1] * numpy.arange(len_y)
- self._plot.remove(kind=("curve", "scatter"))
+ self._plot.remove(kind=("curve",))
- # values: x-y-v scatter
- if self.__values is not None:
- self._plot.addScatter(x, y, self.__values,
- legend=legend,
- xerror=self.__axis_errors,
- yerror=y_errors)
+ for i in range(len(self.__signals)):
+ legend = self.__signals_names[i]
- # x monotonically increasing or decreasiing: curve
- elif numpy.all(numpy.diff(x) > 0) or numpy.all(numpy.diff(x) < 0):
- self._plot.addCurve(x, y, legend=legend,
- xerror=self.__axis_errors,
+ # errors only supported for primary signal in NXdata
+ y_errors = None
+ if i == 0 and self.__signal_errors is not None:
+ y_errors = self.__signal_errors[self._selector.selection()]
+ self._plot.addCurve(x, ys[i], legend=legend,
+ xerror=self.__x_axis_errors,
yerror=y_errors)
+ if i == 0:
+ self._plot.setActiveCurve(legend)
- # scatter
- else:
- self._plot.addScatter(x, y, value=numpy.ones_like(y),
- legend=legend,
- xerror=self.__axis_errors,
- yerror=y_errors)
self._plot.resetZoom()
self._plot.getXAxis().setLabel(self.__axis_name)
- self._plot.getYAxis().setLabel(self.__signal_name)
+ self._plot.getYAxis().setLabel(self.__signals_names[0])
+
+ def _setYLabelFromActiveLegend(self, previous_legend, new_legend):
+ for ylabel in self.__signals_names:
+ if new_legend is not None and new_legend == ylabel:
+ self._plot.getYAxis().setLabel(ylabel)
+ break
+
+ def clear(self):
+ self._plot.clear()
+
+
+class XYVScatterPlot(qt.QWidget):
+ """
+ Widget for plotting one or more scatters
+ (with identical x, y coordinates).
+ """
+ def __init__(self, parent=None):
+ """
+
+ :param parent: Parent QWidget
+ """
+ super(XYVScatterPlot, self).__init__(parent)
+
+ self.__y_axis = None
+ """1D array"""
+ self.__y_axis_name = None
+ self.__values = None
+ """List of 1D arrays (for multiple scatters with identical
+ x, y coordinates)"""
+
+ self.__x_axis = None
+ self.__x_axis_name = None
+ self.__x_axis_errors = None
+ self.__y_axis = None
+ self.__y_axis_name = None
+ self.__y_axis_errors = None
+
+ self._plot = Plot1D(self)
+ self._plot.setDefaultColormap(Colormap(name="viridis",
+ vmin=None, vmax=None,
+ normalization=Colormap.LINEAR))
+
+ self._slider = HorizontalSliderWithBrowser(parent=self)
+ self._slider.setMinimum(0)
+ self._slider.setValue(0)
+ self._slider.valueChanged[int].connect(self._sliderIdxChanged)
+ self._slider.setToolTip("Select auxiliary signals")
+
+ layout = qt.QGridLayout()
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.addWidget(self._plot, 0, 0)
+ layout.addWidget(self._slider, 1, 0)
+
+ self.setLayout(layout)
+
+ def _sliderIdxChanged(self, value):
+ self._updateScatter()
+
+ def getPlot(self):
+ """Returns the plot used for the display
+
+ :rtype: Plot1D
+ """
+ return self._plot
+
+ def setScattersData(self, y, x, values,
+ yerror=None, xerror=None,
+ ylabel=None, xlabel=None,
+ title="", scatter_titles=None):
+ """
+
+ :param ndarray y: 1D array for y (vertical) coordinates.
+ :param ndarray x: 1D array for x coordinates.
+ :param List[ndarray] values: List of 1D arrays of values.
+ This will be used to compute the color map and assign colors
+ to the points. There should be as many arrays in the list as
+ scatters to be represented.
+ :param ndarray yerror: 1D array of errors for y (same shape), or None.
+ :param ndarray xerror: 1D array of errors for x, or None
+ :param str ylabel: Label for Y axis
+ :param str xlabel: Label for X axis
+ :param str title: Main graph title
+ :param List[str] scatter_titles: Subtitles (one per scatter)
+ """
+ self.__y_axis = y
+ self.__x_axis = x
+ self.__x_axis_name = xlabel or "X"
+ self.__y_axis_name = ylabel or "Y"
+ self.__x_axis_errors = xerror
+ self.__y_axis_errors = yerror
+ self.__values = values
+
+ self.__graph_title = title or ""
+ self.__scatter_titles = scatter_titles
+
+ self._slider.valueChanged[int].disconnect(self._sliderIdxChanged)
+ self._slider.setMaximum(len(values) - 1)
+ if len(values) > 1:
+ self._slider.show()
+ else:
+ self._slider.hide()
+ self._slider.setValue(0)
+ self._slider.valueChanged[int].connect(self._sliderIdxChanged)
+
+ self._updateScatter()
+
+ def _updateScatter(self):
+ x = self.__x_axis
+ y = self.__y_axis
+
+ self._plot.remove(kind=("scatter", ))
+
+ idx = self._slider.value()
+
+ title = ""
+ if self.__graph_title:
+ title += self.__graph_title + "\n" # main NXdata @title
+ title += self.__scatter_titles[idx] # scatter dataset name
+
+ self._plot.setGraphTitle(title)
+ self._plot.addScatter(x, y, self.__values[idx],
+ legend="scatter%d" % idx,
+ xerror=self.__x_axis_errors,
+ yerror=self.__y_axis_errors)
+ self._plot.resetZoom()
+ self._plot.getXAxis().setLabel(self.__x_axis_name)
+ self._plot.getYAxis().setLabel(self.__y_axis_name)
def clear(self):
self._plot.clear()
@@ -218,97 +329,117 @@ class ArrayImagePlot(qt.QWidget):
"""
super(ArrayImagePlot, self).__init__(parent)
- self.__signal = None
- self.__signal_name = None
+ self.__signals = None
+ self.__signals_names = None
self.__x_axis = None
self.__x_axis_name = None
self.__y_axis = None
self.__y_axis_name = None
self._plot = Plot2D(self)
- self._plot.setDefaultColormap(
- {"name": "viridis",
- "vmin": 0., "vmax": 1., # ignored (autoscale) but mandatory
- "normalization": "linear",
- "autoscale": True})
+ self._plot.setDefaultColormap(Colormap(name="viridis",
+ vmin=None, vmax=None,
+ normalization=Colormap.LINEAR))
self.selectorDock = qt.QDockWidget("Data selector", self._plot)
# not closable
self.selectorDock.setFeatures(qt.QDockWidget.DockWidgetMovable |
qt.QDockWidget.DockWidgetFloatable)
- self._legend = qt.QLabel(self)
self._selector = NumpyAxesSelector(self.selectorDock)
self._selector.setNamedAxesSelectorVisibility(False)
- self.__selector_is_connected = False
+ self._selector.selectionChanged.connect(self._updateImage)
+
+ self._auxSigSlider = HorizontalSliderWithBrowser(parent=self)
+ self._auxSigSlider.setMinimum(0)
+ self._auxSigSlider.setValue(0)
+ self._auxSigSlider.valueChanged[int].connect(self._sliderIdxChanged)
+ self._auxSigSlider.setToolTip("Select auxiliary signals")
layout = qt.QVBoxLayout()
layout.addWidget(self._plot)
- layout.addWidget(self._legend)
+ layout.addWidget(self._auxSigSlider)
self.selectorDock.setWidget(self._selector)
self._plot.addTabbedDockWidget(self.selectorDock)
self.setLayout(layout)
- def setImageData(self, signal,
+ def _sliderIdxChanged(self, value):
+ self._updateImage()
+
+ def getPlot(self):
+ """Returns the plot used for the display
+
+ :rtype: Plot2D
+ """
+ return self._plot
+
+ def setImageData(self, signals,
x_axis=None, y_axis=None,
- signal_name=None,
+ signals_names=None,
xlabel=None, ylabel=None,
- title=None):
+ title=None, isRgba=False):
"""
- :param signal: n-D dataset, whose last 2 dimensions are used as the
- image's values.
+ :param signals: list of n-D datasets, whose last 2 dimensions are used as the
+ image's values, or list of 3D datasets interpreted as RGBA image.
:param x_axis: 1-D dataset used as the image's x coordinates. If
provided, its lengths must be equal to the length of the last
dimension of ``signal``.
:param y_axis: 1-D dataset used as the image's y. If provided,
its lengths must be equal to the length of the 2nd to last
dimension of ``signal``.
- :param signal_name: Label used in the legend
+ :param signals_names: Names for each image, used as subtitle and legend.
:param xlabel: Label for X axis
:param ylabel: Label for Y axis
:param title: Graph title
+ :param isRgba: True if data is a 3D RGBA image
"""
- if self.__selector_is_connected:
- self._selector.selectionChanged.disconnect(self._updateImage)
- self.__selector_is_connected = False
+ self._selector.selectionChanged.disconnect(self._updateImage)
+ self._auxSigSlider.valueChanged.disconnect(self._sliderIdxChanged)
- self.__signal = signal
- self.__signal_name = signal_name or ""
+ self.__signals = signals
+ self.__signals_names = signals_names
self.__x_axis = x_axis
self.__x_axis_name = xlabel
self.__y_axis = y_axis
self.__y_axis_name = ylabel
+ self.__title = title
- self._selector.setData(signal)
- self._selector.setAxisNames([ylabel or "Y", xlabel or "X"])
+ self._selector.clear()
+ if not isRgba:
+ self._selector.setAxisNames(["Y", "X"])
+ img_ndim = 2
+ else:
+ self._selector.setAxisNames(["Y", "X", "RGB(A) channel"])
+ img_ndim = 3
+ self._selector.setData(signals[0])
- if len(signal.shape) < 3:
+ if len(signals[0].shape) <= img_ndim:
self.selectorDock.hide()
else:
self.selectorDock.show()
- self._plot.setGraphTitle(title or "")
- self._plot.getXAxis().setLabel(self.__x_axis_name or "X")
- self._plot.getYAxis().setLabel(self.__y_axis_name or "Y")
+ self._auxSigSlider.setMaximum(len(signals) - 1)
+ if len(signals) > 1:
+ self._auxSigSlider.show()
+ else:
+ self._auxSigSlider.hide()
+ self._auxSigSlider.setValue(0)
self._updateImage()
- if not self.__selector_is_connected:
- self._selector.selectionChanged.connect(self._updateImage)
- self.__selector_is_connected = True
+ self._selector.selectionChanged.connect(self._updateImage)
+ self._auxSigSlider.valueChanged.connect(self._sliderIdxChanged)
def _updateImage(self):
- legend = self.__signal_name + "["
- for sl in self._selector.selection():
- if sl == slice(None):
- legend += ":, "
- else:
- legend += str(sl) + ", "
- legend = legend[:-2] + "]"
- self._legend.setText("Displayed data: " + legend)
+ selection = self._selector.selection()
+ auxSigIdx = self._auxSigSlider.value()
+
+ legend = self.__signals_names[auxSigIdx]
+
+ images = [img[selection] for img in self.__signals]
+ image = images[auxSigIdx]
- img = self._selector.selectedData()
x_axis = self.__x_axis
y_axis = self.__y_axis
@@ -318,25 +449,25 @@ class ArrayImagePlot(qt.QWidget):
else:
if x_axis is None:
# no calibration
- x_axis = numpy.arange(img.shape[-1])
+ x_axis = numpy.arange(image.shape[1])
elif numpy.isscalar(x_axis) or len(x_axis) == 1:
# constant axis
- x_axis = x_axis * numpy.ones((img.shape[-1], ))
+ x_axis = x_axis * numpy.ones((image.shape[1], ))
elif len(x_axis) == 2:
# linear calibration
- x_axis = x_axis[0] * numpy.arange(img.shape[-1]) + x_axis[1]
+ x_axis = x_axis[0] * numpy.arange(image.shape[1]) + x_axis[1]
if y_axis is None:
- y_axis = numpy.arange(img.shape[-2])
+ y_axis = numpy.arange(image.shape[0])
elif numpy.isscalar(y_axis) or len(y_axis) == 1:
- y_axis = y_axis * numpy.ones((img.shape[-2], ))
+ y_axis = y_axis * numpy.ones((image.shape[0], ))
elif len(y_axis) == 2:
- y_axis = y_axis[0] * numpy.arange(img.shape[-2]) + y_axis[1]
+ y_axis = y_axis[0] * numpy.arange(image.shape[0]) + y_axis[1]
xcalib = ArrayCalibration(x_axis)
ycalib = ArrayCalibration(y_axis)
- self._plot.remove(kind=("scatter", "image"))
+ self._plot.remove(kind=("scatter", "image",))
if xcalib.is_affine() and ycalib.is_affine():
# regular image
xorigin, xscale = xcalib(0), xcalib.get_slope()
@@ -344,14 +475,22 @@ class ArrayImagePlot(qt.QWidget):
origin = (xorigin, yorigin)
scale = (xscale, yscale)
- self._plot.addImage(img, legend=legend,
+ self._plot.addImage(image, legend=legend,
origin=origin, scale=scale)
else:
scatterx, scattery = numpy.meshgrid(x_axis, y_axis)
+ # fixme: i don't think this can handle "irregular" RGBA images
self._plot.addScatter(numpy.ravel(scatterx),
numpy.ravel(scattery),
- numpy.ravel(img),
+ numpy.ravel(image),
legend=legend)
+
+ title = ""
+ if self.__title:
+ title += self.__title
+ if not title.strip().endswith(self.__signals_names[auxSigIdx]):
+ title += "\n" + self.__signals_names[auxSigIdx]
+ self._plot.setGraphTitle(title)
self._plot.getXAxis().setLabel(self.__x_axis_name)
self._plot.getYAxis().setLabel(self.__y_axis_name)
self._plot.resetZoom()
@@ -408,6 +547,13 @@ class ArrayStackPlot(qt.QWidget):
self.setLayout(layout)
+ def getStackView(self):
+ """Returns the plot used for the display
+
+ :rtype: StackView
+ """
+ return self._stack_view
+
def setStackData(self, signal,
x_axis=None, y_axis=None, z_axis=None,
signal_name=None,
@@ -446,7 +592,7 @@ class ArrayStackPlot(qt.QWidget):
self.__z_axis_name = zlabel
self._selector.setData(signal)
- self._selector.setAxisNames([ylabel or "Y", xlabel or "X", zlabel or "Z"])
+ self._selector.setAxisNames(["Y", "X", "Z"])
self._stack_view.setGraphTitle(title or "")
# by default, the z axis is the image position (dimension not plotted)
diff --git a/silx/gui/data/NumpyAxesSelector.py b/silx/gui/data/NumpyAxesSelector.py
index f4641da..4530aa9 100644
--- a/silx/gui/data/NumpyAxesSelector.py
+++ b/silx/gui/data/NumpyAxesSelector.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -29,7 +29,7 @@ from __future__ import division
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "16/01/2017"
+__date__ = "29/01/2018"
import numpy
import functools
@@ -133,7 +133,7 @@ class _Axis(qt.QWidget):
def setAxisNames(self, axesNames):
"""Set the available list of names for the axis.
- :param list[str] axesNames: List of available names
+ :param List[str] axesNames: List of available names
"""
self.__axes.clear()
previous = self.__axes.blockSignals(True)
@@ -146,7 +146,7 @@ class _Axis(qt.QWidget):
def setCustomAxis(self, axesNames):
"""Set the available list of named axis which can be set to a value.
- :param list[str] axesNames: List of customable axis names
+ :param List[str] axesNames: List of customable axis names
"""
self.__customAxisNames = set(axesNames)
self.__updateSliderVisibility()
@@ -258,9 +258,12 @@ class NumpyAxesSelector(qt.QWidget):
The size of the list will constrain the dimension of the resulting
array.
- :param list[str] axesNames: List of string identifying axis names
+ :param List[str] axesNames: List of distinct strings identifying axis names
"""
self.__axisNames = list(axesNames)
+ assert len(set(self.__axisNames)) == len(self.__axisNames),\
+ "Non-unique axes names: %s" % self.__axisNames
+
delta = len(self.__axis) - len(self.__axisNames)
if delta < 0:
delta = 0
@@ -277,7 +280,7 @@ class NumpyAxesSelector(qt.QWidget):
def setCustomAxis(self, axesNames):
"""Set the available list of named axis which can be set to a value.
- :param list[str] axesNames: List of customable axis names
+ :param List[str] axesNames: List of customable axis names
"""
self.__customAxisNames = set(axesNames)
for axis in self.__axis:
@@ -415,13 +418,20 @@ class NumpyAxesSelector(qt.QWidget):
else:
selection.append(slice(None))
axisNames.append(name)
-
self.__selection = tuple(selection)
# get a view with few fixed dimensions
# with a h5py dataset, it create a copy
# TODO we can reuse the same memory in case of a copy
view = self.__data[self.__selection]
+ if set(self.__axisNames) - set(axisNames) != set([]):
+ # Not all the expected axis are there
+ if self.__selectedData is not None:
+ self.__selectedData = None
+ self.__selection = tuple()
+ self.selectionChanged.emit()
+ return
+
# order axis as expected
source = []
destination = []
diff --git a/silx/gui/data/TextFormatter.py b/silx/gui/data/TextFormatter.py
index 37e1f48..332625c 100644
--- a/silx/gui/data/TextFormatter.py
+++ b/silx/gui/data/TextFormatter.py
@@ -27,12 +27,13 @@ data module to format data as text in the same way."""
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "27/09/2017"
+__date__ = "13/12/2017"
import numpy
import numbers
from silx.third_party import six
from silx.gui import qt
+import logging
try:
import h5py
@@ -40,6 +41,9 @@ except ImportError:
h5py = None
+_logger = logging.getLogger(__name__)
+
+
class TextFormatter(qt.QObject):
"""Formatter to convert data to string.
@@ -203,8 +207,9 @@ class TextFormatter(qt.QObject):
data = [ord(d) for d in data.item()]
else:
data = data.item().astype(numpy.uint8)
- else:
+ elif six.PY2:
data = [ord(d) for d in data]
+ # In python3 data is already a bytes array
data = ["\\x%02X" % d for d in data]
if self.__useQuoteForText:
return "b\"%s\"" % "".join(data)
@@ -221,6 +226,30 @@ class TextFormatter(qt.QObject):
else:
return "".join(data)
+ def __formatCharString(self, data):
+ """Format text of char.
+
+ From the specifications we expect to have ASCII, but we also allow
+ CP1252 in some ceases as fallback.
+
+ If no encoding fits, it will display a readable ASCII chars, with
+ escaped chars (using the python syntax) for non decoded characters.
+
+ :param data: A binary string of char expected in ASCII
+ :rtype: str
+ """
+ try:
+ text = "%s" % data.decode("ascii")
+ return self.__formatText(text)
+ except UnicodeDecodeError:
+ # Here we can spam errors, this is definitly a badly
+ # generated file
+ _logger.error("Invalid ASCII string %s.", data)
+ if data == b"\xB0":
+ _logger.error("Fallback using cp1252 encoding")
+ return self.__formatText(u"\u00B0")
+ return self.__formatSafeAscii(data)
+
def __formatH5pyObject(self, data, dtype):
# That's an HDF5 object
ref = h5py.check_dtype(ref=dtype)
@@ -236,11 +265,7 @@ class TextFormatter(qt.QObject):
return self.__formatText(data)
elif vlen == six.binary_type:
# HDF5 ASCII
- try:
- text = "%s" % data.decode("ascii")
- return self.__formatText(text)
- except UnicodeDecodeError:
- return self.__formatSafeAscii(data)
+ return self.__formatCharString(data)
return None
def toString(self, data, dtype=None):
@@ -276,14 +301,12 @@ class TextFormatter(qt.QObject):
elif isinstance(data, (numpy.unicode_, six.text_type)):
return self.__formatText(data)
elif isinstance(data, (numpy.string_, six.binary_type)):
+ if dtype is None and hasattr(data, "dtype"):
+ dtype = data.dtype
if dtype is not None:
# Maybe a sub item from HDF5
if dtype.kind == 'S':
- try:
- text = "%s" % data.decode("ascii")
- return self.__formatText(text)
- except UnicodeDecodeError:
- return self.__formatSafeAscii(data)
+ return self.__formatCharString(data)
elif dtype.kind == 'O':
if h5py is not None:
text = self.__formatH5pyObject(data, dtype)
diff --git a/silx/gui/data/test/test_dataviewer.py b/silx/gui/data/test/test_dataviewer.py
index dd3114a..274df92 100644
--- a/silx/gui/data/test/test_dataviewer.py
+++ b/silx/gui/data/test/test_dataviewer.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,7 +24,7 @@
# ###########################################################################*/
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "22/08/2017"
+__date__ = "22/02/2018"
import os
import tempfile
@@ -67,7 +67,8 @@ class _DataViewMock(DataView):
class AbstractDataViewerTests(TestCaseQt):
def create_widget(self):
- raise NotImplementedError()
+ # Avoid to raise an error when testing the full module
+ self.skipTest("Not implemented")
@contextmanager
def h5_temporary_file(self):
@@ -89,7 +90,7 @@ class AbstractDataViewerTests(TestCaseQt):
widget = self.create_widget()
for data in data_list:
widget.setData(data)
- self.assertEqual(DataViewer.RAW_MODE, widget.displayMode())
+ self.assertEqual(DataViews.RAW_MODE, widget.displayMode())
def test_plot_1d_data(self):
data = numpy.arange(3 ** 1)
@@ -97,35 +98,35 @@ class AbstractDataViewerTests(TestCaseQt):
widget = self.create_widget()
widget.setData(data)
availableModes = set([v.modeId() for v in widget.currentAvailableViews()])
- self.assertEqual(DataViewer.RAW_MODE, widget.displayMode())
- self.assertIn(DataViewer.PLOT1D_MODE, availableModes)
+ self.assertEqual(DataViews.RAW_MODE, widget.displayMode())
+ self.assertIn(DataViews.PLOT1D_MODE, availableModes)
- def test_plot_2d_data(self):
+ def test_image_data(self):
data = numpy.arange(3 ** 2)
data.shape = [3] * 2
widget = self.create_widget()
widget.setData(data)
availableModes = set([v.modeId() for v in widget.currentAvailableViews()])
- self.assertEqual(DataViewer.RAW_MODE, widget.displayMode())
- self.assertIn(DataViewer.PLOT2D_MODE, availableModes)
+ self.assertEqual(DataViews.RAW_MODE, widget.displayMode())
+ self.assertIn(DataViews.IMAGE_MODE, availableModes)
- def test_plot_2d_bool(self):
+ def test_image_bool(self):
data = numpy.zeros((10, 10), dtype=numpy.bool)
data[::2, ::2] = True
widget = self.create_widget()
widget.setData(data)
availableModes = set([v.modeId() for v in widget.currentAvailableViews()])
- self.assertEqual(DataViewer.RAW_MODE, widget.displayMode())
- self.assertIn(DataViewer.PLOT2D_MODE, availableModes)
+ self.assertEqual(DataViews.RAW_MODE, widget.displayMode())
+ self.assertIn(DataViews.IMAGE_MODE, availableModes)
- def test_plot_2d_complex_data(self):
+ def test_image_complex_data(self):
data = numpy.arange(3 ** 2, dtype=numpy.complex)
data.shape = [3] * 2
widget = self.create_widget()
widget.setData(data)
availableModes = set([v.modeId() for v in widget.currentAvailableViews()])
- self.assertEqual(DataViewer.RAW_MODE, widget.displayMode())
- self.assertIn(DataViewer.PLOT2D_MODE, availableModes)
+ self.assertEqual(DataViews.RAW_MODE, widget.displayMode())
+ self.assertIn(DataViews.IMAGE_MODE, availableModes)
def test_plot_3d_data(self):
data = numpy.arange(3 ** 3)
@@ -135,38 +136,38 @@ class AbstractDataViewerTests(TestCaseQt):
availableModes = set([v.modeId() for v in widget.currentAvailableViews()])
try:
import silx.gui.plot3d # noqa
- self.assertIn(DataViewer.PLOT3D_MODE, availableModes)
+ self.assertIn(DataViews.PLOT3D_MODE, availableModes)
except ImportError:
- self.assertIn(DataViewer.STACK_MODE, availableModes)
- self.assertEqual(DataViewer.RAW_MODE, widget.displayMode())
+ self.assertIn(DataViews.STACK_MODE, availableModes)
+ self.assertEqual(DataViews.RAW_MODE, widget.displayMode())
def test_array_1d_data(self):
data = numpy.array(["aaa"] * (3 ** 1))
data.shape = [3] * 1
widget = self.create_widget()
widget.setData(data)
- self.assertEqual(DataViewer.RAW_MODE, widget.displayedView().modeId())
+ self.assertEqual(DataViews.RAW_MODE, widget.displayedView().modeId())
def test_array_2d_data(self):
data = numpy.array(["aaa"] * (3 ** 2))
data.shape = [3] * 2
widget = self.create_widget()
widget.setData(data)
- self.assertEqual(DataViewer.RAW_MODE, widget.displayedView().modeId())
+ self.assertEqual(DataViews.RAW_MODE, widget.displayedView().modeId())
def test_array_4d_data(self):
data = numpy.array(["aaa"] * (3 ** 4))
data.shape = [3] * 4
widget = self.create_widget()
widget.setData(data)
- self.assertEqual(DataViewer.RAW_MODE, widget.displayedView().modeId())
+ self.assertEqual(DataViews.RAW_MODE, widget.displayedView().modeId())
def test_record_4d_data(self):
data = numpy.zeros(3 ** 4, dtype='3int8, float32, (2,3)float64')
data.shape = [3] * 4
widget = self.create_widget()
widget.setData(data)
- self.assertEqual(DataViewer.RAW_MODE, widget.displayedView().modeId())
+ self.assertEqual(DataViews.RAW_MODE, widget.displayedView().modeId())
def test_3d_h5_dataset(self):
if h5py is None:
@@ -191,7 +192,7 @@ class AbstractDataViewerTests(TestCaseQt):
widget.setData(10)
widget.setData(None)
modes = [v.modeId() for v in listener.arguments(argumentIndex=0)]
- self.assertEquals(modes, [DataViewer.RAW_MODE, DataViewer.EMPTY_MODE])
+ self.assertEquals(modes, [DataViews.RAW_MODE, DataViews.EMPTY_MODE])
listener.clear()
def test_change_display_mode(self):
@@ -199,14 +200,15 @@ class AbstractDataViewerTests(TestCaseQt):
data.shape = [10] * 4
widget = self.create_widget()
widget.setData(data)
- widget.setDisplayMode(DataViewer.PLOT1D_MODE)
- self.assertEquals(widget.displayedView().modeId(), DataViewer.PLOT1D_MODE)
- widget.setDisplayMode(DataViewer.PLOT2D_MODE)
- self.assertEquals(widget.displayedView().modeId(), DataViewer.PLOT2D_MODE)
- widget.setDisplayMode(DataViewer.RAW_MODE)
- self.assertEquals(widget.displayedView().modeId(), DataViewer.RAW_MODE)
- widget.setDisplayMode(DataViewer.EMPTY_MODE)
- self.assertEquals(widget.displayedView().modeId(), DataViewer.EMPTY_MODE)
+ widget.setDisplayMode(DataViews.PLOT1D_MODE)
+ self.assertEquals(widget.displayedView().modeId(), DataViews.PLOT1D_MODE)
+ widget.setDisplayMode(DataViews.IMAGE_MODE)
+ self.assertEquals(widget.displayedView().modeId(), DataViews.IMAGE_MODE)
+ widget.setDisplayMode(DataViews.RAW_MODE)
+ self.assertEquals(widget.displayedView().modeId(), DataViews.RAW_MODE)
+ widget.setDisplayMode(DataViews.EMPTY_MODE)
+ self.assertEquals(widget.displayedView().modeId(), DataViews.EMPTY_MODE)
+ DataView._cleanUpCache()
def test_create_default_views(self):
widget = self.create_widget()
@@ -228,6 +230,26 @@ class AbstractDataViewerTests(TestCaseQt):
self.assertTrue(view not in widget.availableViews())
self.assertTrue(view not in widget.currentAvailableViews())
+ def test_replace_view(self):
+ widget = self.create_widget()
+ view = _DataViewMock(widget)
+ widget.replaceView(DataViews.RAW_MODE,
+ view)
+ self.assertIsNone(widget.getViewFromModeId(DataViews.RAW_MODE))
+ self.assertTrue(view in widget.availableViews())
+ self.assertTrue(view in widget.currentAvailableViews())
+
+ def test_replace_view_in_composite(self):
+ # replace a view that is a child of a composite view
+ widget = self.create_widget()
+ view = _DataViewMock(widget)
+ widget.replaceView(DataViews.NXDATA_INVALID_MODE,
+ view)
+ nxdata_view = widget.getViewFromModeId(DataViews.NXDATA_MODE)
+ self.assertNotIn(DataViews.NXDATA_INVALID_MODE,
+ [v.modeId() for v in nxdata_view.availableViews()])
+ self.assertTrue(view in nxdata_view.availableViews())
+
class TestDataViewer(AbstractDataViewerTests):
def create_widget(self):
@@ -265,6 +287,7 @@ class TestDataView(TestCaseQt):
dataViewClass = DataViews._Plot2dView
widget = self.createDataViewWithData(dataViewClass, data[0])
self.qWaitForWindowExposed(widget)
+ DataView._cleanUpCache()
def testCubeWithComplex(self):
self.skipTest("OpenGL widget not yet tested")
@@ -276,12 +299,14 @@ class TestDataView(TestCaseQt):
dataViewClass = DataViews._Plot3dView
widget = self.createDataViewWithData(dataViewClass, data)
self.qWaitForWindowExposed(widget)
+ DataView._cleanUpCache()
def testImageStackWithComplex(self):
data = self.createComplexData()
dataViewClass = DataViews._StackView
widget = self.createDataViewWithData(dataViewClass, data)
self.qWaitForWindowExposed(widget)
+ DataView._cleanUpCache()
def suite():
diff --git a/silx/gui/data/test/test_numpyaxesselector.py b/silx/gui/data/test/test_numpyaxesselector.py
index cc15f83..6ce5119 100644
--- a/silx/gui/data/test/test_numpyaxesselector.py
+++ b/silx/gui/data/test/test_numpyaxesselector.py
@@ -24,7 +24,7 @@
# ###########################################################################*/
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "15/12/2016"
+__date__ = "29/01/2018"
import os
import tempfile
@@ -70,6 +70,20 @@ class TestNumpyAxesSelector(TestCaseQt):
result = widget.selectedData()
self.assertTrue(numpy.array_equal(result, expectedResult))
+ def test_output_moredim(self):
+ data = numpy.arange(3 * 3 * 3 * 3)
+ data.shape = 3, 3, 3, 3
+ expectedResult = data
+
+ widget = NumpyAxesSelector()
+ widget.setAxisNames(["x", "y", "z", "boum"])
+ widget.setData(data[0])
+ result = widget.selectedData()
+ self.assertEqual(result, None)
+ widget.setData(data)
+ result = widget.selectedData()
+ self.assertTrue(numpy.array_equal(result, expectedResult))
+
def test_output_lessdim(self):
data = numpy.arange(3 * 3 * 3)
data.shape = 3, 3, 3
diff --git a/silx/gui/data/test/test_textformatter.py b/silx/gui/data/test/test_textformatter.py
index 2a7a66b..06a29ba 100644
--- a/silx/gui/data/test/test_textformatter.py
+++ b/silx/gui/data/test/test_textformatter.py
@@ -24,7 +24,7 @@
# ###########################################################################*/
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "27/09/2017"
+__date__ = "12/12/2017"
import unittest
import shutil
@@ -91,6 +91,17 @@ class TestTextFormatter(TestCaseQt):
result = formatter.toString("toto")
self.assertEquals(result, '"toto"')
+ def test_numpy_void(self):
+ formatter = TextFormatter()
+ result = formatter.toString(numpy.void(b"\xFF"))
+ self.assertEquals(result, 'b"\\xFF"')
+
+ def test_char_cp1252(self):
+ # degree character in cp1252
+ formatter = TextFormatter()
+ result = formatter.toString(numpy.bytes_(b"\xB0"))
+ self.assertEquals(result, u'"\u00B0"')
+
class TestTextFormatterWithH5py(TestCaseQt):
diff --git a/silx/gui/dialog/AbstractDataFileDialog.py b/silx/gui/dialog/AbstractDataFileDialog.py
new file mode 100644
index 0000000..1bd52bb
--- /dev/null
+++ b/silx/gui/dialog/AbstractDataFileDialog.py
@@ -0,0 +1,1718 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This module contains an :class:`AbstractDataFileDialog`.
+"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "12/02/2018"
+
+
+import sys
+import os
+import logging
+import numpy
+import functools
+import silx.io.url
+from silx.gui import qt
+from silx.gui.hdf5.Hdf5TreeModel import Hdf5TreeModel
+from . import utils
+from silx.third_party import six
+from .FileTypeComboBox import FileTypeComboBox
+try:
+ import fabio
+except ImportError:
+ fabio = None
+
+
+_logger = logging.getLogger(__name__)
+
+
+class _IconProvider(object):
+
+ FileDialogToParentDir = qt.QStyle.SP_CustomBase + 1
+
+ FileDialogToParentFile = qt.QStyle.SP_CustomBase + 2
+
+ def __init__(self):
+ self.__iconFileDialogToParentDir = None
+ self.__iconFileDialogToParentFile = None
+
+ def _createIconToParent(self, standardPixmap):
+ """
+
+ FIXME: It have to be tested for some OS (arrow icon do not have always
+ the same direction)
+ """
+ style = qt.QApplication.style()
+ baseIcon = style.standardIcon(qt.QStyle.SP_FileDialogToParent)
+ backgroundIcon = style.standardIcon(standardPixmap)
+ icon = qt.QIcon()
+
+ sizes = baseIcon.availableSizes()
+ sizes = sorted(sizes, key=lambda s: s.height())
+ sizes = filter(lambda s: s.height() < 100, sizes)
+ sizes = list(sizes)
+ if len(sizes) > 0:
+ baseSize = sizes[-1]
+ else:
+ baseSize = baseIcon.availableSizes()[0]
+ size = qt.QSize(baseSize.width(), baseSize.height() * 3 // 2)
+
+ modes = [qt.QIcon.Normal, qt.QIcon.Disabled]
+ for mode in modes:
+ pixmap = qt.QPixmap(size)
+ pixmap.fill(qt.Qt.transparent)
+ painter = qt.QPainter(pixmap)
+ painter.drawPixmap(0, 0, backgroundIcon.pixmap(baseSize, mode=mode))
+ painter.drawPixmap(0, size.height() // 3, baseIcon.pixmap(baseSize, mode=mode))
+ painter.end()
+ icon.addPixmap(pixmap, mode=mode)
+
+ return icon
+
+ def getFileDialogToParentDir(self):
+ if self.__iconFileDialogToParentDir is None:
+ self.__iconFileDialogToParentDir = self._createIconToParent(qt.QStyle.SP_DirIcon)
+ return self.__iconFileDialogToParentDir
+
+ def getFileDialogToParentFile(self):
+ if self.__iconFileDialogToParentFile is None:
+ self.__iconFileDialogToParentFile = self._createIconToParent(qt.QStyle.SP_FileIcon)
+ return self.__iconFileDialogToParentFile
+
+ def icon(self, kind):
+ if kind == self.FileDialogToParentDir:
+ return self.getFileDialogToParentDir()
+ elif kind == self.FileDialogToParentFile:
+ return self.getFileDialogToParentFile()
+ else:
+ style = qt.QApplication.style()
+ icon = style.standardIcon(kind)
+ return icon
+
+
+class _SideBar(qt.QListView):
+ """Sidebar containing shortcuts for common directories"""
+
+ def __init__(self, parent=None):
+ super(_SideBar, self).__init__(parent)
+ self.__iconProvider = qt.QFileIconProvider()
+ self.setUniformItemSizes(True)
+ model = qt.QStandardItemModel(self)
+ self.setModel(model)
+ self._initModel()
+ self.setEditTriggers(qt.QAbstractItemView.NoEditTriggers)
+
+ def iconProvider(self):
+ return self.__iconProvider
+
+ def _initModel(self):
+ urls = self._getDefaultUrls()
+ self.setUrls(urls)
+
+ def _getDefaultUrls(self):
+ """Returns the default shortcuts.
+
+ It uses the default QFileDialog shortcuts if it is possible, else
+ provides a link to the computer's root and the user's home.
+
+ :rtype: List[str]
+ """
+ urls = []
+ if qt.qVersion().startswith("5.") and sys.platform in ["linux", "linux2"]:
+ # Avoid segfault on PyQt5 + gtk
+ _logger.debug("Skip default sidebar URLs (avoid PyQt5 segfault)")
+ pass
+ elif qt.qVersion().startswith("4.") and sys.platform in ["win32"]:
+ # Avoid 5min of locked GUI relative to network driver
+ _logger.debug("Skip default sidebar URLs (avoid lock when using network drivers)")
+ else:
+ # Get default shortcut
+ # There is no other way
+ d = qt.QFileDialog(self)
+ # Needed to be able to reach the sidebar urls
+ d.setOption(qt.QFileDialog.DontUseNativeDialog, True)
+ urls = d.sidebarUrls()
+ d.deleteLater()
+ d = None
+
+ if len(urls) == 0:
+ urls.append(qt.QUrl("file://"))
+ urls.append(qt.QUrl.fromLocalFile(qt.QDir.homePath()))
+
+ return urls
+
+ def setSelectedPath(self, path):
+ selected = None
+ model = self.model()
+ for i in range(model.rowCount()):
+ index = model.index(i, 0)
+ url = model.data(index, qt.Qt.UserRole)
+ urlPath = url.toLocalFile()
+ if path == urlPath:
+ selected = index
+
+ selectionModel = self.selectionModel()
+ if selected is not None:
+ selectionModel.setCurrentIndex(selected, qt.QItemSelectionModel.ClearAndSelect)
+ else:
+ selectionModel.clear()
+
+ def setUrls(self, urls):
+ model = self.model()
+ model.clear()
+
+ names = {}
+ names[qt.QDir.rootPath()] = "Computer"
+ names[qt.QDir.homePath()] = "Home"
+
+ style = qt.QApplication.style()
+ iconProvider = self.iconProvider()
+ for url in urls:
+ path = url.toLocalFile()
+ if path == "":
+ if sys.platform != "win32":
+ url = qt.QUrl(qt.QDir.rootPath())
+ name = "Computer"
+ icon = style.standardIcon(qt.QStyle.SP_ComputerIcon)
+ else:
+ fileInfo = qt.QFileInfo(path)
+ name = names.get(path, fileInfo.fileName())
+ icon = iconProvider.icon(fileInfo)
+
+ if icon.isNull():
+ icon = style.standardIcon(qt.QStyle.SP_MessageBoxCritical)
+
+ item = qt.QStandardItem()
+ item.setText(name)
+ item.setIcon(icon)
+ item.setData(url, role=qt.Qt.UserRole)
+ model.appendRow(item)
+
+ def urls(self):
+ result = []
+ model = self.model()
+ for i in range(model.rowCount()):
+ index = model.index(i, 0)
+ url = model.data(index, qt.Qt.UserRole)
+ result.append(url)
+ return result
+
+ def sizeHint(self):
+ index = self.model().index(0, 0)
+ return self.sizeHintForIndex(index) + qt.QSize(2 * self.frameWidth(), 2 * self.frameWidth())
+
+
+class _Browser(qt.QStackedWidget):
+
+ activated = qt.Signal(qt.QModelIndex)
+ selected = qt.Signal(qt.QModelIndex)
+ rootIndexChanged = qt.Signal(qt.QModelIndex)
+
+ def __init__(self, parent, listView, detailView):
+ qt.QStackedWidget.__init__(self, parent)
+ self.__listView = listView
+ self.__detailView = detailView
+ self.insertWidget(0, self.__listView)
+ self.insertWidget(1, self.__detailView)
+
+ self.__listView.activated.connect(self.__emitActivated)
+ self.__detailView.activated.connect(self.__emitActivated)
+
+ def __emitActivated(self, index):
+ self.activated.emit(index)
+
+ def __emitSelected(self, selected, deselected):
+ index = self.selectedIndex()
+ if index is not None:
+ self.selected.emit(index)
+
+ def selectedIndex(self):
+ if self.currentIndex() == 0:
+ selectionModel = self.__listView.selectionModel()
+ else:
+ selectionModel = self.__detailView.selectionModel()
+
+ if selectionModel is None:
+ return None
+
+ indexes = selectionModel.selectedIndexes()
+ # Filter non-main columns
+ indexes = [i for i in indexes if i.column() == 0]
+ if len(indexes) == 1:
+ index = indexes[0]
+ return index
+ return None
+
+ def model(self):
+ """Returns the current model."""
+ if self.currentIndex() == 0:
+ return self.__listView.model()
+ else:
+ return self.__detailView.model()
+
+ def selectIndex(self, index):
+ if self.currentIndex() == 0:
+ selectionModel = self.__listView.selectionModel()
+ else:
+ selectionModel = self.__detailView.selectionModel()
+ if selectionModel is None:
+ return
+ selectionModel.setCurrentIndex(index, qt.QItemSelectionModel.ClearAndSelect)
+
+ def viewMode(self):
+ """Returns the current view mode.
+
+ :rtype: qt.QFileDialog.ViewMode
+ """
+ if self.currentIndex() == 0:
+ return qt.QFileDialog.List
+ elif self.currentIndex() == 1:
+ return qt.QFileDialog.Detail
+ else:
+ assert(False)
+
+ def setViewMode(self, mode):
+ """Set the current view mode.
+
+ :param qt.QFileDialog.ViewMode mode: The new view mode
+ """
+ if mode == qt.QFileDialog.Detail:
+ self.showDetails()
+ elif mode == qt.QFileDialog.List:
+ self.showList()
+ else:
+ assert(False)
+
+ def showList(self):
+ self.__listView.show()
+ self.__detailView.hide()
+ self.setCurrentIndex(0)
+
+ def showDetails(self):
+ self.__listView.hide()
+ self.__detailView.show()
+ self.setCurrentIndex(1)
+ self.__detailView.updateGeometry()
+
+ def clear(self):
+ self.__listView.setRootIndex(qt.QModelIndex())
+ self.__detailView.setRootIndex(qt.QModelIndex())
+ selectionModel = self.__listView.selectionModel()
+ if selectionModel is not None:
+ selectionModel.selectionChanged.disconnect()
+ selectionModel.clear()
+ selectionModel = self.__detailView.selectionModel()
+ if selectionModel is not None:
+ selectionModel.selectionChanged.disconnect()
+ selectionModel.clear()
+ self.__listView.setModel(None)
+ self.__detailView.setModel(None)
+
+ def setRootIndex(self, index, model=None):
+ """Sets the root item to the item at the given index.
+ """
+ rootIndex = self.__listView.rootIndex()
+ newModel = model or index.model()
+ assert(newModel is not None)
+
+ if rootIndex is None or rootIndex.model() is not newModel:
+ # update the model
+ selectionModel = self.__listView.selectionModel()
+ if selectionModel is not None:
+ selectionModel.selectionChanged.disconnect()
+ selectionModel.clear()
+ selectionModel = self.__detailView.selectionModel()
+ if selectionModel is not None:
+ selectionModel.selectionChanged.disconnect()
+ selectionModel.clear()
+ pIndex = qt.QPersistentModelIndex(index)
+ self.__listView.setModel(newModel)
+ # changing the model of the tree view change the index mapping
+ # that is why we are using a persistance model index
+ self.__detailView.setModel(newModel)
+ index = newModel.index(pIndex.row(), pIndex.column(), pIndex.parent())
+ selectionModel = self.__listView.selectionModel()
+ selectionModel.selectionChanged.connect(self.__emitSelected)
+ selectionModel = self.__detailView.selectionModel()
+ selectionModel.selectionChanged.connect(self.__emitSelected)
+
+ self.__listView.setRootIndex(index)
+ self.__detailView.setRootIndex(index)
+ self.rootIndexChanged.emit(index)
+
+ def rootIndex(self):
+ """Returns the model index of the model's root item. The root item is
+ the parent item to the view's toplevel items. The root can be invalid.
+ """
+ return self.__listView.rootIndex()
+
+ __serialVersion = 1
+ """Store the current version of the serialized data"""
+
+ def visualRect(self, index):
+ """Returns the rectangle on the viewport occupied by the item at index.
+
+ :param qt.QModelIndex index: An index
+ :rtype: QRect
+ """
+ if self.currentIndex() == 0:
+ return self.__listView.visualRect(index)
+ else:
+ return self.__detailView.visualRect(index)
+
+ def viewport(self):
+ """Returns the viewport widget.
+
+ :param qt.QModelIndex index: An index
+ :rtype: QRect
+ """
+ if self.currentIndex() == 0:
+ return self.__listView.viewport()
+ else:
+ return self.__detailView.viewport()
+
+ def restoreState(self, state):
+ """Restores the dialogs's layout, history and current directory to the
+ state specified.
+
+ :param qt.QByeArray state: Stream containing the new state
+ :rtype: bool
+ """
+ stream = qt.QDataStream(state, qt.QIODevice.ReadOnly)
+
+ nameId = stream.readQString()
+ if nameId != "Browser":
+ _logger.warning("Stored state contains an invalid name id. Browser restoration cancelled.")
+ return False
+
+ version = stream.readInt32()
+ if version != self.__serialVersion:
+ _logger.warning("Stored state contains an invalid version. Browser restoration cancelled.")
+ return False
+
+ headerData = stream.readQVariant()
+ self.__detailView.header().restoreState(headerData)
+
+ viewMode = stream.readInt32()
+ self.setViewMode(viewMode)
+ return True
+
+ def saveState(self):
+ """Saves the state of the dialog's layout.
+
+ :rtype: qt.QByteArray
+ """
+ data = qt.QByteArray()
+ stream = qt.QDataStream(data, qt.QIODevice.WriteOnly)
+
+ nameId = u"Browser"
+ stream.writeQString(nameId)
+ stream.writeInt32(self.__serialVersion)
+ stream.writeQVariant(self.__detailView.header().saveState())
+ stream.writeInt32(self.viewMode())
+
+ return data
+
+
+class _FabioData(object):
+
+ def __init__(self, fabioFile):
+ self.__fabioFile = fabioFile
+
+ @property
+ def dtype(self):
+ # Let say it is a valid type
+ return numpy.dtype("float")
+
+ @property
+ def shape(self):
+ if self.__fabioFile.nframes == 0:
+ return None
+ return [self.__fabioFile.nframes, slice(None), slice(None)]
+
+ def __getitem__(self, selector):
+ if isinstance(selector, tuple) and len(selector) == 1:
+ selector = selector[0]
+
+ if isinstance(selector, six.integer_types):
+ if 0 <= selector < self.__fabioFile.nframes:
+ if self.__fabioFile.nframes == 1:
+ return self.__fabioFile.data
+ else:
+ frame = self.__fabioFile.getframe(selector)
+ return frame.data
+ else:
+ raise ValueError("Invalid selector %s" % selector)
+ else:
+ raise TypeError("Unsupported selector type %s" % type(selector))
+
+
+class _PathEdit(qt.QLineEdit):
+ pass
+
+
+class _CatchResizeEvent(qt.QObject):
+
+ resized = qt.Signal(qt.QResizeEvent)
+
+ def __init__(self, parent, target):
+ super(_CatchResizeEvent, self).__init__(parent)
+ self.__target = target
+ self.__target_oldResizeEvent = self.__target.resizeEvent
+ self.__target.resizeEvent = self.__resizeEvent
+
+ def __resizeEvent(self, event):
+ result = self.__target_oldResizeEvent(event)
+ self.resized.emit(event)
+ return result
+
+
+class AbstractDataFileDialog(qt.QDialog):
+ """The `AbstractFileDialog` provides a generic GUI to create a custom dialog
+ allowing to access to file resources like HDF5 files or HDF5 datasets
+
+ The dialog contains:
+
+ - Shortcuts: It provides few links to have a fast access of browsing
+ locations.
+ - Browser: It provides a display to browse throw the file system and inside
+ HDF5 files or fabio files. A file format selector is provided.
+ - URL: Display the URL available to reach the data using
+ :meth:`silx.io.get_data`, :meth:`silx.io.open`.
+ - Data selector: A widget to apply a sub selection of the browsed dataset.
+ This widget can be provided, else nothing will be used.
+ - Data preview: A widget to preview the selected data, which is the result
+ of the filter from the data selector.
+ This widget can be provided, else nothing will be used.
+ - Preview's toolbar: Provides tools used to custom data preview or data
+ selector.
+ This widget can be provided, else nothing will be used.
+ - Buttons to validate the dialog
+ """
+
+ _defaultIconProvider = None
+ """Lazy loaded default icon provider"""
+
+ def __init__(self, parent=None):
+ super(AbstractDataFileDialog, self).__init__(parent)
+ self._init()
+
+ def _init(self):
+ self.setWindowTitle("Open")
+
+ self.__directory = None
+ self.__directoryLoadedFilter = None
+ self.__errorWhileLoadingFile = None
+ self.__selectedFile = None
+ self.__selectedData = None
+ self.__currentHistory = []
+ """Store history of URLs, last index one is the latest one"""
+ self.__currentHistoryLocation = -1
+ """Store the location in the history. Bigger is older"""
+
+ self.__processing = 0
+ """Number of asynchronous processing tasks"""
+ self.__h5 = None
+ self.__fabio = None
+
+ if qt.qVersion() < "5.0":
+ # On Qt4 it is needed to provide a safe file system model
+ _logger.debug("Uses SafeFileSystemModel")
+ from .SafeFileSystemModel import SafeFileSystemModel
+ self.__fileModel = SafeFileSystemModel(self)
+ else:
+ # On Qt5 a safe icon provider is still needed to avoid freeze
+ _logger.debug("Uses default QFileSystemModel with a SafeFileIconProvider")
+ self.__fileModel = qt.QFileSystemModel(self)
+ from .SafeFileIconProvider import SafeFileIconProvider
+ iconProvider = SafeFileIconProvider()
+ self.__fileModel.setIconProvider(iconProvider)
+
+ # The common file dialog filter only on Mac OS X
+ self.__fileModel.setNameFilterDisables(sys.platform == "darwin")
+ self.__fileModel.setReadOnly(True)
+ self.__fileModel.directoryLoaded.connect(self.__directoryLoaded)
+
+ self.__dataModel = Hdf5TreeModel(self)
+
+ self.__createWidgets()
+ self.__initLayout()
+ self.__showAsListView()
+
+ path = os.getcwd()
+ self.__fileModel_setRootPath(path)
+
+ self.__clearData()
+ self.__updatePath()
+
+ # Update the file model filter
+ self.__fileTypeCombo.setCurrentIndex(0)
+ self.__filterSelected(0)
+
+ self.__openedFiles = []
+ """Store the list of files opened by the model itself."""
+ # FIXME: It should be managed one by one by Hdf5Item itself
+
+ # It is not possible to override the QObject destructor nor
+ # to access to the content of the Python object with the `destroyed`
+ # signal cause the Python method was already removed with the QWidget,
+ # while the QObject still exists.
+ # We use a static method plus explicit references to objects to
+ # release. The callback do not use any ref to self.
+ onDestroy = functools.partial(self._closeFileList, self.__openedFiles)
+ self.destroyed.connect(onDestroy)
+
+ @staticmethod
+ def _closeFileList(fileList):
+ """Static method to close explicit references to internal objects."""
+ _logger.debug("Clear AbstractDataFileDialog")
+ for obj in fileList:
+ _logger.debug("Close file %s", obj.filename)
+ obj.close()
+ fileList[:] = []
+
+ def done(self, result):
+ self._clear()
+ super(AbstractDataFileDialog, self).done(result)
+
+ def _clear(self):
+ """Explicit method to clear data stored in the dialog.
+ After this call it is not anymore possible to use the widget.
+
+ This method is triggered by the destruction of the object and the
+ QDialog :meth:`done`. Then it can be triggered more than once.
+ """
+ _logger.debug("Clear dialog")
+ self.__errorWhileLoadingFile = None
+ self.__clearData()
+ if self.__fileModel is not None:
+ # Cache the directory before cleaning the model
+ self.__directory = self.directory()
+ self.__browser.clear()
+ self.__closeFile()
+ self.__fileModel = None
+ self.__dataModel = None
+
+ def hasPendingEvents(self):
+ """Returns true if the dialog have asynchronous tasks working on the
+ background."""
+ return self.__processing > 0
+
+ # User interface
+
+ def __createWidgets(self):
+ self.__sidebar = self._createSideBar()
+ if self.__sidebar is not None:
+ sideBarModel = self.__sidebar.selectionModel()
+ sideBarModel.selectionChanged.connect(self.__shortcutSelected)
+ self.__sidebar.setSelectionMode(qt.QAbstractItemView.SingleSelection)
+
+ listView = qt.QListView(self)
+ listView.setSelectionBehavior(qt.QAbstractItemView.SelectRows)
+ listView.setSelectionMode(qt.QAbstractItemView.SingleSelection)
+ listView.setResizeMode(qt.QListView.Adjust)
+ listView.setWrapping(True)
+ listView.setEditTriggers(qt.QAbstractItemView.NoEditTriggers)
+ listView.setContextMenuPolicy(qt.Qt.CustomContextMenu)
+ utils.patchToConsumeReturnKey(listView)
+
+ treeView = qt.QTreeView(self)
+ treeView.setSelectionBehavior(qt.QAbstractItemView.SelectRows)
+ treeView.setSelectionMode(qt.QAbstractItemView.SingleSelection)
+ treeView.setRootIsDecorated(False)
+ treeView.setItemsExpandable(False)
+ treeView.setSortingEnabled(True)
+ treeView.header().setSortIndicator(0, qt.Qt.AscendingOrder)
+ treeView.header().setStretchLastSection(False)
+ treeView.setTextElideMode(qt.Qt.ElideMiddle)
+ treeView.setEditTriggers(qt.QAbstractItemView.NoEditTriggers)
+ treeView.setContextMenuPolicy(qt.Qt.CustomContextMenu)
+ treeView.setDragDropMode(qt.QAbstractItemView.InternalMove)
+ utils.patchToConsumeReturnKey(treeView)
+
+ self.__browser = _Browser(self, listView, treeView)
+ self.__browser.activated.connect(self.__browsedItemActivated)
+ self.__browser.selected.connect(self.__browsedItemSelected)
+ self.__browser.rootIndexChanged.connect(self.__rootIndexChanged)
+ self.__browser.setObjectName("browser")
+
+ self.__previewWidget = self._createPreviewWidget(self)
+
+ self.__fileTypeCombo = FileTypeComboBox(self)
+ self.__fileTypeCombo.setObjectName("fileTypeCombo")
+ self.__fileTypeCombo.setDuplicatesEnabled(False)
+ self.__fileTypeCombo.setSizeAdjustPolicy(qt.QComboBox.AdjustToMinimumContentsLength)
+ self.__fileTypeCombo.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Fixed)
+ self.__fileTypeCombo.activated[int].connect(self.__filterSelected)
+ self.__fileTypeCombo.setFabioUrlSupproted(self._isFabioFilesSupported())
+
+ self.__pathEdit = _PathEdit(self)
+ self.__pathEdit.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Fixed)
+ self.__pathEdit.textChanged.connect(self.__textChanged)
+ self.__pathEdit.setObjectName("url")
+ utils.patchToConsumeReturnKey(self.__pathEdit)
+
+ self.__buttons = qt.QDialogButtonBox(self)
+ self.__buttons.setSizePolicy(qt.QSizePolicy.Fixed, qt.QSizePolicy.Fixed)
+ types = qt.QDialogButtonBox.Open | qt.QDialogButtonBox.Cancel
+ self.__buttons.setStandardButtons(types)
+ self.__buttons.button(qt.QDialogButtonBox.Cancel).setObjectName("cancel")
+ self.__buttons.button(qt.QDialogButtonBox.Open).setObjectName("open")
+
+ self.__buttons.accepted.connect(self.accept)
+ self.__buttons.rejected.connect(self.reject)
+
+ self.__browseToolBar = self._createBrowseToolBar()
+ self.__backwardAction.setEnabled(False)
+ self.__forwardAction.setEnabled(False)
+ self.__fileDirectoryAction.setEnabled(False)
+ self.__parentFileDirectoryAction.setEnabled(False)
+
+ self.__selectorWidget = self._createSelectorWidget(self)
+ if self.__selectorWidget is not None:
+ self.__selectorWidget.selectionChanged.connect(self.__selectorWidgetChanged)
+
+ self.__previewToolBar = self._createPreviewToolbar(self, self.__previewWidget, self.__selectorWidget)
+
+ self.__dataIcon = qt.QLabel(self)
+ self.__dataIcon.setSizePolicy(qt.QSizePolicy.Fixed, qt.QSizePolicy.Fixed)
+ self.__dataIcon.setScaledContents(True)
+ self.__dataIcon.setMargin(2)
+ self.__dataIcon.setAlignment(qt.Qt.AlignCenter)
+
+ self.__dataInfo = qt.QLabel(self)
+ self.__dataInfo.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Fixed)
+
+ def _createSideBar(self):
+ sidebar = _SideBar(self)
+ sidebar.setObjectName("sidebar")
+ return sidebar
+
+ def iconProvider(self):
+ iconProvider = self.__class__._defaultIconProvider
+ if iconProvider is None:
+ iconProvider = _IconProvider()
+ self.__class__._defaultIconProvider = iconProvider
+ return iconProvider
+
+ def _createBrowseToolBar(self):
+ toolbar = qt.QToolBar(self)
+ toolbar.setIconSize(qt.QSize(16, 16))
+ iconProvider = self.iconProvider()
+
+ backward = qt.QAction(toolbar)
+ backward.setText("Back")
+ backward.setObjectName("backwardAction")
+ backward.setIcon(iconProvider.icon(qt.QStyle.SP_ArrowBack))
+ backward.triggered.connect(self.__navigateBackward)
+ self.__backwardAction = backward
+
+ forward = qt.QAction(toolbar)
+ forward.setText("Forward")
+ forward.setObjectName("forwardAction")
+ forward.setIcon(iconProvider.icon(qt.QStyle.SP_ArrowForward))
+ forward.triggered.connect(self.__navigateForward)
+ self.__forwardAction = forward
+
+ parentDirectory = qt.QAction(toolbar)
+ parentDirectory.setText("Go to parent")
+ parentDirectory.setObjectName("toParentAction")
+ parentDirectory.setIcon(iconProvider.icon(qt.QStyle.SP_FileDialogToParent))
+ parentDirectory.triggered.connect(self.__navigateToParent)
+ self.__toParentAction = parentDirectory
+
+ fileDirectory = qt.QAction(toolbar)
+ fileDirectory.setText("Root of the file")
+ fileDirectory.setObjectName("toRootFileAction")
+ fileDirectory.setIcon(iconProvider.icon(iconProvider.FileDialogToParentFile))
+ fileDirectory.triggered.connect(self.__navigateToParentFile)
+ self.__fileDirectoryAction = fileDirectory
+
+ parentFileDirectory = qt.QAction(toolbar)
+ parentFileDirectory.setText("Parent directory of the file")
+ parentFileDirectory.setObjectName("toDirectoryAction")
+ parentFileDirectory.setIcon(iconProvider.icon(iconProvider.FileDialogToParentDir))
+ parentFileDirectory.triggered.connect(self.__navigateToParentDir)
+ self.__parentFileDirectoryAction = parentFileDirectory
+
+ listView = qt.QAction(toolbar)
+ listView.setText("List view")
+ listView.setObjectName("listModeAction")
+ listView.setIcon(iconProvider.icon(qt.QStyle.SP_FileDialogListView))
+ listView.triggered.connect(self.__showAsListView)
+ listView.setCheckable(True)
+
+ detailView = qt.QAction(toolbar)
+ detailView.setText("Detail view")
+ detailView.setObjectName("detailModeAction")
+ detailView.setIcon(iconProvider.icon(qt.QStyle.SP_FileDialogDetailedView))
+ detailView.triggered.connect(self.__showAsDetailedView)
+ detailView.setCheckable(True)
+
+ self.__listViewAction = listView
+ self.__detailViewAction = detailView
+
+ toolbar.addAction(backward)
+ toolbar.addAction(forward)
+ toolbar.addSeparator()
+ toolbar.addAction(parentDirectory)
+ toolbar.addAction(fileDirectory)
+ toolbar.addAction(parentFileDirectory)
+ toolbar.addSeparator()
+ toolbar.addAction(listView)
+ toolbar.addAction(detailView)
+
+ toolbar.setStyleSheet("QToolBar { border: 0px }")
+
+ return toolbar
+
+ def __initLayout(self):
+ sideBarLayout = qt.QVBoxLayout()
+ sideBarLayout.setContentsMargins(0, 0, 0, 0)
+ dummyToolBar = qt.QWidget(self)
+ dummyToolBar.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Fixed)
+ dummyCombo = qt.QWidget(self)
+ dummyCombo.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Fixed)
+ sideBarLayout.addWidget(dummyToolBar)
+ if self.__sidebar is not None:
+ sideBarLayout.addWidget(self.__sidebar)
+ sideBarLayout.addWidget(dummyCombo)
+ sideBarWidget = qt.QWidget(self)
+ sideBarWidget.setLayout(sideBarLayout)
+
+ dummyCombo.setFixedHeight(self.__fileTypeCombo.height())
+ self.__resizeCombo = _CatchResizeEvent(self, self.__fileTypeCombo)
+ self.__resizeCombo.resized.connect(lambda e: dummyCombo.setFixedHeight(e.size().height()))
+
+ dummyToolBar.setFixedHeight(self.__browseToolBar.height())
+ self.__resizeToolbar = _CatchResizeEvent(self, self.__browseToolBar)
+ self.__resizeToolbar.resized.connect(lambda e: dummyToolBar.setFixedHeight(e.size().height()))
+
+ datasetSelection = qt.QWidget(self)
+ layoutLeft = qt.QVBoxLayout()
+ layoutLeft.setContentsMargins(0, 0, 0, 0)
+ layoutLeft.addWidget(self.__browseToolBar)
+ layoutLeft.addWidget(self.__browser)
+ layoutLeft.addWidget(self.__fileTypeCombo)
+ datasetSelection.setLayout(layoutLeft)
+ datasetSelection.setSizePolicy(qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Expanding)
+
+ infoLayout = qt.QHBoxLayout()
+ infoLayout.setContentsMargins(0, 0, 0, 0)
+ infoLayout.addWidget(self.__dataIcon)
+ infoLayout.addWidget(self.__dataInfo)
+
+ dataFrame = qt.QFrame(self)
+ dataFrame.setFrameShape(qt.QFrame.StyledPanel)
+ layout = qt.QVBoxLayout()
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.setSpacing(0)
+ layout.addWidget(self.__previewWidget)
+ layout.addLayout(infoLayout)
+ dataFrame.setLayout(layout)
+
+ dataSelection = qt.QWidget(self)
+ dataLayout = qt.QVBoxLayout()
+ dataLayout.setContentsMargins(0, 0, 0, 0)
+ if self.__previewToolBar is not None:
+ dataLayout.addWidget(self.__previewToolBar)
+ else:
+ # Add dummy space
+ dummyToolbar2 = qt.QWidget(self)
+ dummyToolbar2.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Fixed)
+ dummyToolbar2.setFixedHeight(self.__browseToolBar.height())
+ self.__resizeToolbar = _CatchResizeEvent(self, self.__browseToolBar)
+ self.__resizeToolbar.resized.connect(lambda e: dummyToolbar2.setFixedHeight(e.size().height()))
+ dataLayout.addWidget(dummyToolbar2)
+
+ dataLayout.addWidget(dataFrame)
+ if self.__selectorWidget is not None:
+ dataLayout.addWidget(self.__selectorWidget)
+ else:
+ # Add dummy space
+ dummyCombo2 = qt.QWidget(self)
+ dummyCombo2.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Fixed)
+ dummyCombo2.setFixedHeight(self.__fileTypeCombo.height())
+ self.__resizeToolbar = _CatchResizeEvent(self, self.__fileTypeCombo)
+ self.__resizeToolbar.resized.connect(lambda e: dummyCombo2.setFixedHeight(e.size().height()))
+ dataLayout.addWidget(dummyCombo2)
+ dataSelection.setLayout(dataLayout)
+
+ self.__splitter = qt.QSplitter(self)
+ self.__splitter.setContentsMargins(0, 0, 0, 0)
+ self.__splitter.addWidget(sideBarWidget)
+ self.__splitter.addWidget(datasetSelection)
+ self.__splitter.addWidget(dataSelection)
+ self.__splitter.setStretchFactor(1, 10)
+
+ bottomLayout = qt.QHBoxLayout()
+ bottomLayout.setContentsMargins(0, 0, 0, 0)
+ bottomLayout.addWidget(self.__pathEdit)
+ bottomLayout.addWidget(self.__buttons)
+
+ layout = qt.QVBoxLayout(self)
+ layout.addWidget(self.__splitter)
+ layout.addLayout(bottomLayout)
+
+ self.setLayout(layout)
+ self.updateGeometry()
+
+ # Logic
+
+ def __navigateBackward(self):
+ """Navigate through the history one step backward."""
+ if len(self.__currentHistory) > 0 and self.__currentHistoryLocation > 0:
+ self.__currentHistoryLocation -= 1
+ url = self.__currentHistory[self.__currentHistoryLocation]
+ self.selectUrl(url)
+
+ def __navigateForward(self):
+ """Navigate through the history one step forward."""
+ if len(self.__currentHistory) > 0 and self.__currentHistoryLocation < len(self.__currentHistory) - 1:
+ self.__currentHistoryLocation += 1
+ url = self.__currentHistory[self.__currentHistoryLocation]
+ self.selectUrl(url)
+
+ def __navigateToParent(self):
+ index = self.__browser.rootIndex()
+ if index.model() is self.__fileModel:
+ # browse throw the file system
+ index = index.parent()
+ path = self.__fileModel.filePath(index)
+ self.__fileModel_setRootPath(path)
+ self.__browser.selectIndex(qt.QModelIndex())
+ self.__updatePath()
+ elif index.model() is self.__dataModel:
+ index = index.parent()
+ if index.isValid():
+ # browse throw the hdf5
+ self.__browser.setRootIndex(index)
+ self.__browser.selectIndex(qt.QModelIndex())
+ self.__updatePath()
+ else:
+ # go back to the file system
+ self.__navigateToParentDir()
+ else:
+ # Root of the file system (my computer)
+ pass
+
+ def __navigateToParentFile(self):
+ index = self.__browser.rootIndex()
+ if index.model() is self.__dataModel:
+ index = self.__dataModel.indexFromH5Object(self.__h5)
+ self.__browser.setRootIndex(index)
+ self.__browser.selectIndex(qt.QModelIndex())
+ self.__updatePath()
+
+ def __navigateToParentDir(self):
+ index = self.__browser.rootIndex()
+ if index.model() is self.__dataModel:
+ path = os.path.dirname(self.__h5.file.filename)
+ index = self.__fileModel.index(path)
+ self.__browser.setRootIndex(index)
+ self.__browser.selectIndex(qt.QModelIndex())
+ self.__closeFile()
+ self.__updatePath()
+
+ def viewMode(self):
+ """Returns the current view mode.
+
+ :rtype: qt.QFileDialog.ViewMode
+ """
+ return self.__browser.viewMode()
+
+ def setViewMode(self, mode):
+ """Set the current view mode.
+
+ :param qt.QFileDialog.ViewMode mode: The new view mode
+ """
+ if mode == qt.QFileDialog.Detail:
+ self.__browser.showDetails()
+ self.__listViewAction.setChecked(False)
+ self.__detailViewAction.setChecked(True)
+ elif mode == qt.QFileDialog.List:
+ self.__browser.showList()
+ self.__listViewAction.setChecked(True)
+ self.__detailViewAction.setChecked(False)
+ else:
+ assert(False)
+
+ def __showAsListView(self):
+ self.setViewMode(qt.QFileDialog.List)
+
+ def __showAsDetailedView(self):
+ self.setViewMode(qt.QFileDialog.Detail)
+
+ def __shortcutSelected(self):
+ self.__browser.selectIndex(qt.QModelIndex())
+ self.__clearData()
+ self.__updatePath()
+ selectionModel = self.__sidebar.selectionModel()
+ indexes = selectionModel.selectedIndexes()
+ if len(indexes) == 1:
+ index = indexes[0]
+ url = self.__sidebar.model().data(index, role=qt.Qt.UserRole)
+ path = url.toLocalFile()
+ self.__fileModel_setRootPath(path)
+
+ def __browsedItemActivated(self, index):
+ if not index.isValid():
+ return
+ if index.model() is self.__fileModel:
+ path = self.__fileModel.filePath(index)
+ if self.__fileModel.isDir(index):
+ self.__fileModel_setRootPath(path)
+ if os.path.isfile(path):
+ self.__fileActivated(index)
+ elif index.model() is self.__dataModel:
+ obj = self.__dataModel.data(index, role=Hdf5TreeModel.H5PY_OBJECT_ROLE)
+ if silx.io.is_group(obj):
+ self.__browser.setRootIndex(index)
+ else:
+ assert(False)
+
+ def __browsedItemSelected(self, index):
+ self.__dataSelected(index)
+ self.__updatePath()
+
+ def __fileModel_setRootPath(self, path):
+ """Set the root path of the fileModel with a filter on the
+ directoryLoaded event.
+
+ Without this filter an extra event is received (at least with PyQt4)
+ when we use for the first time the sidebar.
+
+ :param str path: Path to load
+ """
+ assert(path is not None)
+ if path != "" and not os.path.exists(path):
+ return
+ if self.hasPendingEvents():
+ # Make sure the asynchronous fileModel setRootPath is finished
+ qt.QApplication.instance().processEvents()
+
+ if self.__directoryLoadedFilter is not None:
+ if utils.samefile(self.__directoryLoadedFilter, path):
+ return
+ self.__directoryLoadedFilter = path
+ self.__processing += 1
+ index = self.__fileModel.setRootPath(path)
+ if not index.isValid():
+ self.__processing -= 1
+ self.__browser.setRootIndex(index, model=self.__fileModel)
+ self.__clearData()
+ self.__updatePath()
+ else:
+ # asynchronous process
+ pass
+
+ def __directoryLoaded(self, path):
+ if self.__directoryLoadedFilter is not None:
+ if not utils.samefile(self.__directoryLoadedFilter, path):
+ # Filter event which should not arrive in PyQt4
+ # The first click on the sidebar sent 2 events
+ self.__processing -= 1
+ return
+ index = self.__fileModel.index(path)
+ self.__browser.setRootIndex(index, model=self.__fileModel)
+ self.__updatePath()
+ self.__processing -= 1
+
+ def __closeFile(self):
+ self.__openedFiles[:] = []
+ self.__fileDirectoryAction.setEnabled(False)
+ self.__parentFileDirectoryAction.setEnabled(False)
+ if self.__h5 is not None:
+ self.__dataModel.removeH5pyObject(self.__h5)
+ self.__h5.close()
+ self.__h5 = None
+ if self.__fabio is not None:
+ if hasattr(self.__fabio, "close"):
+ self.__fabio.close()
+ self.__fabio = None
+
+ def __openFabioFile(self, filename):
+ self.__closeFile()
+ try:
+ if fabio is None:
+ raise ImportError("Fabio module is not available")
+ self.__fabio = fabio.open(filename)
+ self.__openedFiles.append(self.__fabio)
+ self.__selectedFile = filename
+ except Exception as e:
+ _logger.error("Error while loading file %s: %s", filename, e.args[0])
+ _logger.debug("Backtrace", exc_info=True)
+ self.__errorWhileLoadingFile = filename, e.args[0]
+ return False
+ else:
+ return True
+
+ def __openSilxFile(self, filename):
+ self.__closeFile()
+ try:
+ self.__h5 = silx.io.open(filename)
+ self.__openedFiles.append(self.__h5)
+ self.__selectedFile = filename
+ except IOError as e:
+ _logger.error("Error while loading file %s: %s", filename, e.args[0])
+ _logger.debug("Backtrace", exc_info=True)
+ self.__errorWhileLoadingFile = filename, e.args[0]
+ return False
+ else:
+ self.__fileDirectoryAction.setEnabled(True)
+ self.__parentFileDirectoryAction.setEnabled(True)
+ self.__dataModel.insertH5pyObject(self.__h5)
+ return True
+
+ def __isSilxHavePriority(self, filename):
+ """Silx have priority when there is a specific decoder
+ """
+ _, ext = os.path.splitext(filename)
+ ext = "*%s" % ext
+ formats = silx.io.supported_extensions(flat_formats=False)
+ for extensions in formats.values():
+ if ext in extensions:
+ return True
+ return False
+
+ def __openFile(self, filename):
+ codec = self.__fileTypeCombo.currentCodec()
+ openners = []
+ if codec.is_autodetect():
+ if self.__isSilxHavePriority(filename):
+ openners.append(self.__openSilxFile)
+ if fabio is not None and self._isFabioFilesSupported():
+ openners.append(self.__openFabioFile)
+ else:
+ if fabio is not None and self._isFabioFilesSupported():
+ openners.append(self.__openFabioFile)
+ openners.append(self.__openSilxFile)
+ elif codec.is_silx_codec():
+ openners.append(self.__openSilxFile)
+ elif self._isFabioFilesSupported() and codec.is_fabio_codec():
+ # It is requested to use fabio, anyway fabio is here or not
+ openners.append(self.__openFabioFile)
+
+ for openner in openners:
+ ref = openner(filename)
+ if ref is not None:
+ return True
+ return False
+
+ def __fileActivated(self, index):
+ self.__selectedFile = None
+ path = self.__fileModel.filePath(index)
+ if os.path.isfile(path):
+ loaded = self.__openFile(path)
+ if loaded:
+ if self.__h5 is not None:
+ index = self.__dataModel.indexFromH5Object(self.__h5)
+ self.__browser.setRootIndex(index)
+ elif self.__fabio is not None:
+ data = _FabioData(self.__fabio)
+ self.__setData(data)
+ self.__updatePath()
+ else:
+ self.__clearData()
+
+ def __dataSelected(self, index):
+ selectedData = None
+ if index is not None:
+ if index.model() is self.__dataModel:
+ obj = self.__dataModel.data(index, self.__dataModel.H5PY_OBJECT_ROLE)
+ if self._isDataSupportable(obj):
+ selectedData = obj
+ elif index.model() is self.__fileModel:
+ self.__closeFile()
+ if self._isFabioFilesSupported():
+ path = self.__fileModel.filePath(index)
+ if os.path.isfile(path):
+ codec = self.__fileTypeCombo.currentCodec()
+ is_fabio_decoder = codec.is_fabio_codec()
+ is_fabio_have_priority = not codec.is_silx_codec() and not self.__isSilxHavePriority(path)
+ if is_fabio_decoder or is_fabio_have_priority:
+ # Then it's flat frame container
+ if fabio is not None:
+ self.__openFabioFile(path)
+ if self.__fabio is not None:
+ selectedData = _FabioData(self.__fabio)
+ else:
+ assert(False)
+
+ self.__setData(selectedData)
+
+ def __filterSelected(self, index):
+ filters = self.__fileTypeCombo.itemExtensions(index)
+ self.__fileModel.setNameFilters(filters)
+
+ def __setData(self, data):
+ self.__data = data
+
+ if data is not None and self._isDataSupportable(data):
+ if self.__selectorWidget is not None:
+ self.__selectorWidget.setData(data)
+ if not self.__selectorWidget.isUsed():
+ # Needed to fake the fact we have to reset the zoom in preview
+ self.__selectedData = None
+ self.__setSelectedData(data)
+ self.__selectorWidget.hide()
+ else:
+ self.__selectorWidget.setVisible(self.__selectorWidget.hasVisibleSelectors())
+ # Needed to fake the fact we have to reset the zoom in preview
+ self.__selectedData = None
+ self.__selectorWidget.selectionChanged.emit()
+ else:
+ # Needed to fake the fact we have to reset the zoom in preview
+ self.__selectedData = None
+ self.__setSelectedData(data)
+ else:
+ self.__clearData()
+ self.__updatePath()
+
+ def _isDataSupported(self, data):
+ """Check if the data can be returned by the dialog.
+
+ If true, this data can be returned by the dialog and the open button
+ while be enabled. If false the button will be disabled.
+
+ :rtype: bool
+ """
+ raise NotImplementedError()
+
+ def _isDataSupportable(self, data):
+ """Check if the selected data can be supported at one point.
+
+ If true, the data selector will be checked and it will update the data
+ preview. Else the selecting is disabled.
+
+ :rtype: bool
+ """
+ raise NotImplementedError()
+
+ def __clearData(self):
+ """Clear the data part of the GUI"""
+ if self.__previewWidget is not None:
+ self.__previewWidget.setData(None)
+ if self.__selectorWidget is not None:
+ self.__selectorWidget.hide()
+ self.__selectedData = None
+ self.__data = None
+ self.__updateDataInfo()
+ button = self.__buttons.button(qt.QDialogButtonBox.Open)
+ button.setEnabled(False)
+
+ def __selectorWidgetChanged(self):
+ data = self.__selectorWidget.getSelectedData(self.__data)
+ self.__setSelectedData(data)
+
+ def __setSelectedData(self, data):
+ """Set the data selected by the dialog.
+
+ If :meth:`_isDataSupported` returns false, this function will be
+ inhibited and no data will be selected.
+ """
+ if self.__previewWidget is not None:
+ fromDataSelector = self.__selectedData is not None
+ self.__previewWidget.setData(data, fromDataSelector=fromDataSelector)
+ if self._isDataSupported(data):
+ self.__selectedData = data
+ else:
+ self.__clearData()
+ return
+ self.__updateDataInfo()
+ self.__updatePath()
+ button = self.__buttons.button(qt.QDialogButtonBox.Open)
+ button.setEnabled(True)
+
+ def __updateDataInfo(self):
+ if self.__errorWhileLoadingFile is not None:
+ filename, message = self.__errorWhileLoadingFile
+ message = "<b>Error while loading file '%s'</b><hr/>%s" % (filename, message)
+ size = self.__dataInfo.height()
+ icon = self.style().standardIcon(qt.QStyle.SP_MessageBoxCritical)
+ pixmap = icon.pixmap(size, size)
+
+ self.__dataInfo.setText("Error while loading file")
+ self.__dataInfo.setToolTip(message)
+ self.__dataIcon.setToolTip(message)
+ self.__dataIcon.setVisible(True)
+ self.__dataIcon.setPixmap(pixmap)
+
+ self.__errorWhileLoadingFile = None
+ return
+
+ self.__dataIcon.setVisible(False)
+ self.__dataInfo.setToolTip("")
+ if self.__selectedData is None:
+ self.__dataInfo.setText("No data selected")
+ else:
+ text = self._displayedDataInfo(self.__data, self.__selectedData)
+ self.__dataInfo.setVisible(text is not None)
+ if text is not None:
+ self.__dataInfo.setText(text)
+
+ def _displayedDataInfo(self, dataBeforeSelection, dataAfterSelection):
+ """Returns the text displayed under the data preview.
+
+ This zone is used to display error in case or problem of data selection
+ or problems with IO.
+
+ :param numpy.ndarray dataAfterSelection: Data as it is after the
+ selection widget (basically the data from the preview widget)
+ :param numpy.ndarray dataAfterSelection: Data as it is before the
+ selection widget (basically the data from the browsing widget)
+ :rtype: bool
+ """
+ return None
+
+ def __createUrlFromIndex(self, index, useSelectorWidget=True):
+ if index.model() is self.__fileModel:
+ filename = self.__fileModel.filePath(index)
+ dataPath = None
+ elif index.model() is self.__dataModel:
+ obj = self.__dataModel.data(index, role=Hdf5TreeModel.H5PY_OBJECT_ROLE)
+ filename = obj.file.filename
+ dataPath = obj.name
+ else:
+ # root of the computer
+ filename = ""
+ dataPath = None
+
+ if useSelectorWidget and self.__selectorWidget is not None and self.__selectorWidget.isVisible():
+ slicing = self.__selectorWidget.slicing()
+ else:
+ slicing = None
+
+ if self.__fabio is not None:
+ scheme = "fabio"
+ elif self.__h5 is not None:
+ scheme = "silx"
+ else:
+ if os.path.isfile(filename):
+ codec = self.__fileTypeCombo.currentCodec()
+ if codec.is_fabio_codec():
+ scheme = "fabio"
+ elif codec.is_silx_codec():
+ scheme = "silx"
+ else:
+ scheme = None
+ else:
+ scheme = None
+
+ url = silx.io.url.DataUrl(file_path=filename, data_path=dataPath, data_slice=slicing, scheme=scheme)
+ return url
+
+ def __updatePath(self):
+ index = self.__browser.selectedIndex()
+ if index is None:
+ index = self.__browser.rootIndex()
+ url = self.__createUrlFromIndex(index)
+ if url.path() != self.__pathEdit.text():
+ old = self.__pathEdit.blockSignals(True)
+ self.__pathEdit.setText(url.path())
+ self.__pathEdit.blockSignals(old)
+
+ def __rootIndexChanged(self, index):
+ url = self.__createUrlFromIndex(index, useSelectorWidget=False)
+
+ currentUrl = None
+ if 0 <= self.__currentHistoryLocation < len(self.__currentHistory):
+ currentUrl = self.__currentHistory[self.__currentHistoryLocation]
+
+ if currentUrl is None or currentUrl != url.path():
+ # clean up the forward history
+ self.__currentHistory = self.__currentHistory[0:self.__currentHistoryLocation + 1]
+ self.__currentHistory.append(url.path())
+ self.__currentHistoryLocation += 1
+
+ if index.model() != self.__dataModel:
+ if sys.platform == "win32":
+ # path == ""
+ isRoot = not index.isValid()
+ else:
+ # path in ["", "/"]
+ isRoot = not index.isValid() or not index.parent().isValid()
+ else:
+ isRoot = False
+
+ if index.isValid():
+ self.__dataSelected(index)
+ self.__toParentAction.setEnabled(not isRoot)
+ self.__updateActionHistory()
+ self.__updateSidebar()
+
+ def __updateSidebar(self):
+ """Called when the current directory location change"""
+ if self.__sidebar is None:
+ return
+ selectionModel = self.__sidebar.selectionModel()
+ selectionModel.selectionChanged.disconnect(self.__shortcutSelected)
+ index = self.__browser.rootIndex()
+ if index.model() == self.__fileModel:
+ path = self.__fileModel.filePath(index)
+ self.__sidebar.setSelectedPath(path)
+ elif index.model() is None:
+ path = ""
+ self.__sidebar.setSelectedPath(path)
+ else:
+ selectionModel.clear()
+ selectionModel.selectionChanged.connect(self.__shortcutSelected)
+
+ def __updateActionHistory(self):
+ self.__forwardAction.setEnabled(len(self.__currentHistory) - 1 > self.__currentHistoryLocation)
+ self.__backwardAction.setEnabled(self.__currentHistoryLocation > 0)
+
+ def __textChanged(self, text):
+ self.__pathChanged()
+
+ def _isFabioFilesSupported(self):
+ """Returns true fabio files can be loaded.
+ """
+ return True
+
+ def _isLoadableUrl(self, url):
+ """Returns true if the URL is loadable by this dialog.
+
+ :param DataUrl url: The requested URL
+ """
+ return True
+
+ def __pathChanged(self):
+ url = silx.io.url.DataUrl(path=self.__pathEdit.text())
+ if url.is_valid() or url.path() == "":
+ if url.path() in ["", "/"] or url.file_path() in ["", "/"]:
+ self.__fileModel_setRootPath(qt.QDir.rootPath())
+ elif os.path.exists(url.file_path()):
+ rootIndex = None
+ if os.path.isdir(url.file_path()):
+ self.__fileModel_setRootPath(url.file_path())
+ index = self.__fileModel.index(url.file_path())
+ elif os.path.isfile(url.file_path()):
+ if self._isLoadableUrl(url):
+ if url.scheme() == "silx":
+ loaded = self.__openSilxFile(url.file_path())
+ elif url.scheme() == "fabio" and self._isFabioFilesSupported():
+ loaded = self.__openFabioFile(url.file_path())
+ else:
+ loaded = self.__openFile(url.file_path())
+ else:
+ loaded = False
+ if loaded:
+ if self.__h5 is not None:
+ rootIndex = self.__dataModel.indexFromH5Object(self.__h5)
+ elif self.__fabio is not None:
+ index = self.__fileModel.index(url.file_path())
+ rootIndex = index
+ if rootIndex is None:
+ index = self.__fileModel.index(url.file_path())
+ index = index.parent()
+
+ if rootIndex is not None:
+ if rootIndex.model() == self.__dataModel:
+ if url.data_path() is not None:
+ dataPath = url.data_path()
+ if dataPath in self.__h5:
+ obj = self.__h5[dataPath]
+ else:
+ path = utils.findClosestSubPath(self.__h5, dataPath)
+ if path is None:
+ path = "/"
+ obj = self.__h5[path]
+
+ if silx.io.is_file(obj):
+ self.__browser.setRootIndex(rootIndex)
+ elif silx.io.is_group(obj):
+ index = self.__dataModel.indexFromH5Object(obj)
+ self.__browser.setRootIndex(index)
+ else:
+ index = self.__dataModel.indexFromH5Object(obj)
+ self.__browser.setRootIndex(index.parent())
+ self.__browser.selectIndex(index)
+ else:
+ self.__browser.setRootIndex(rootIndex)
+ self.__clearData()
+ elif rootIndex.model() == self.__fileModel:
+ # that's a fabio file
+ self.__browser.setRootIndex(rootIndex.parent())
+ self.__browser.selectIndex(rootIndex)
+ # data = _FabioData(self.__fabio)
+ # self.__setData(data)
+ else:
+ assert(False)
+ else:
+ self.__browser.setRootIndex(index, model=self.__fileModel)
+ self.__clearData()
+
+ if self.__selectorWidget is not None:
+ self.__selectorWidget.setVisible(url.data_slice() is not None)
+ if url.data_slice() is not None:
+ self.__selectorWidget.setSlicing(url.data_slice())
+ else:
+ self.__errorWhileLoadingFile = (url.file_path(), "File not found")
+ self.__clearData()
+ else:
+ self.__errorWhileLoadingFile = (url.file_path(), "Path invalid")
+ self.__clearData()
+
+ def previewToolbar(self):
+ return self.__previewToolbar
+
+ def previewWidget(self):
+ return self.__previewWidget
+
+ def selectorWidget(self):
+ return self.__selectorWidget
+
+ def _createPreviewToolbar(self, parent, dataPreviewWidget, dataSelectorWidget):
+ return None
+
+ def _createPreviewWidget(self, parent):
+ return None
+
+ def _createSelectorWidget(self, parent):
+ return None
+
+ # Selected file
+
+ def setDirectory(self, path):
+ """Sets the data dialog's current directory."""
+ self.__fileModel_setRootPath(path)
+
+ def selectedFile(self):
+ """Returns the file path containing the selected data.
+
+ :rtype: str
+ """
+ return self.__selectedFile
+
+ def selectFile(self, filename):
+ """Sets the data dialog's current file."""
+ self.__directoryLoadedFilter = ""
+ old = self.__pathEdit.blockSignals(True)
+ try:
+ self.__pathEdit.setText(filename)
+ finally:
+ self.__pathEdit.blockSignals(old)
+ self.__pathChanged()
+
+ # Selected data
+
+ def selectUrl(self, url):
+ """Sets the data dialog's current data url.
+
+ :param Union[str,DataUrl] url: URL identifying a data (it can be a
+ `DataUrl` object)
+ """
+ if isinstance(url, silx.io.url.DataUrl):
+ url = url.path()
+ self.__directoryLoadedFilter = ""
+ old = self.__pathEdit.blockSignals(True)
+ try:
+ self.__pathEdit.setText(url)
+ finally:
+ self.__pathEdit.blockSignals(old)
+ self.__pathChanged()
+
+ def selectedUrl(self):
+ """Returns the URL from the file system to the data.
+
+ If the dialog is not validated, the path can be an intermediat
+ selected path, or an invalid path.
+
+ :rtype: str
+ """
+ return self.__pathEdit.text()
+
+ def selectedDataUrl(self):
+ """Returns the URL as a :class:`DataUrl` from the file system to the
+ data.
+
+ If the dialog is not validated, the path can be an intermediat
+ selected path, or an invalid path.
+
+ :rtype: DataUrl
+ """
+ url = self.selectedUrl()
+ return silx.io.url.DataUrl(url)
+
+ def directory(self):
+ """Returns the path from the current browsed directory.
+
+ :rtype: str
+ """
+ if self.__directory is not None:
+ # At post execution, returns the cache
+ return self.__directory
+
+ index = self.__browser.rootIndex()
+ if index.model() is self.__fileModel:
+ path = self.__fileModel.filePath(index)
+ return path
+ elif index.model() is self.__dataModel:
+ path = os.path.dirname(self.__h5.file.filename)
+ return path
+ else:
+ return ""
+
+ def _selectedData(self):
+ """Returns the internal selected data
+
+ :rtype: numpy.ndarray
+ """
+ return self.__selectedData
+
+ # Filters
+
+ def selectedNameFilter(self):
+ """Returns the filter that the user selected in the file dialog."""
+ return self.__fileTypeCombo.currentText()
+
+ # History
+
+ def history(self):
+ """Returns the browsing history of the filedialog as a list of paths.
+
+ :rtype: List<str>
+ """
+ if len(self.__currentHistory) <= 1:
+ return []
+ history = self.__currentHistory[0:self.__currentHistoryLocation]
+ return list(history)
+
+ def setHistory(self, history):
+ self.__currentHistory = []
+ self.__currentHistory.extend(history)
+ self.__currentHistoryLocation = len(self.__currentHistory) - 1
+ self.__updateActionHistory()
+
+ # Colormap
+
+ def colormap(self):
+ if self.__previewWidget is None:
+ return None
+ return self.__previewWidget.colormap()
+
+ def setColormap(self, colormap):
+ if self.__previewWidget is None:
+ raise RuntimeError("No preview widget defined")
+ self.__previewWidget.setColormap(colormap)
+
+ # Sidebar
+
+ def setSidebarUrls(self, urls):
+ """Sets the urls that are located in the sidebar."""
+ if self.__sidebar is None:
+ return
+ self.__sidebar.setUrls(urls)
+
+ def sidebarUrls(self):
+ """Returns a list of urls that are currently in the sidebar."""
+ if self.__sidebar is None:
+ return []
+ return self.__sidebar.urls()
+
+ # State
+
+ __serialVersion = 1
+ """Store the current version of the serialized data"""
+
+ @classmethod
+ def qualifiedName(cls):
+ return "%s.%s" % (cls.__module__, cls.__name__)
+
+ def restoreState(self, state):
+ """Restores the dialogs's layout, history and current directory to the
+ state specified.
+
+ :param qt.QByteArray state: Stream containing the new state
+ :rtype: bool
+ """
+ stream = qt.QDataStream(state, qt.QIODevice.ReadOnly)
+
+ qualifiedName = stream.readQString()
+ if qualifiedName != self.qualifiedName():
+ _logger.warning("Stored state contains an invalid qualified name. %s restoration cancelled.", self.__class__.__name__)
+ return False
+
+ version = stream.readInt32()
+ if version != self.__serialVersion:
+ _logger.warning("Stored state contains an invalid version. %s restoration cancelled.", self.__class__.__name__)
+ return False
+
+ result = True
+
+ splitterData = stream.readQVariant()
+ sidebarUrls = stream.readQStringList()
+ history = stream.readQStringList()
+ workingDirectory = stream.readQString()
+ browserData = stream.readQVariant()
+ viewMode = stream.readInt32()
+ colormapData = stream.readQVariant()
+
+ result &= self.__splitter.restoreState(splitterData)
+ sidebarUrls = [qt.QUrl(s) for s in sidebarUrls]
+ self.setSidebarUrls(list(sidebarUrls))
+ history = [s for s in history]
+ self.setHistory(list(history))
+ if workingDirectory is not None:
+ self.setDirectory(workingDirectory)
+ result &= self.__browser.restoreState(browserData)
+ self.setViewMode(viewMode)
+ colormap = self.colormap()
+ if colormap is not None:
+ result &= self.colormap().restoreState(colormapData)
+
+ return result
+
+ def saveState(self):
+ """Saves the state of the dialog's layout, history and current
+ directory.
+
+ :rtype: qt.QByteArray
+ """
+ data = qt.QByteArray()
+ stream = qt.QDataStream(data, qt.QIODevice.WriteOnly)
+
+ s = self.qualifiedName()
+ stream.writeQString(u"%s" % s)
+ stream.writeInt32(self.__serialVersion)
+ stream.writeQVariant(self.__splitter.saveState())
+ strings = [u"%s" % s.toString() for s in self.sidebarUrls()]
+ stream.writeQStringList(strings)
+ strings = [u"%s" % s for s in self.history()]
+ stream.writeQStringList(strings)
+ stream.writeQString(u"%s" % self.directory())
+ stream.writeQVariant(self.__browser.saveState())
+ stream.writeInt32(self.viewMode())
+ colormap = self.colormap()
+ if colormap is not None:
+ stream.writeQVariant(self.colormap().saveState())
+ else:
+ stream.writeQVariant(None)
+
+ return data
diff --git a/silx/gui/dialog/DataFileDialog.py b/silx/gui/dialog/DataFileDialog.py
new file mode 100644
index 0000000..7ff1258
--- /dev/null
+++ b/silx/gui/dialog/DataFileDialog.py
@@ -0,0 +1,342 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This module contains an :class:`DataFileDialog`.
+"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "14/02/2018"
+
+import logging
+from silx.gui import qt
+from silx.gui.hdf5.Hdf5Formatter import Hdf5Formatter
+import silx.io
+from .AbstractDataFileDialog import AbstractDataFileDialog
+from silx.third_party import enum
+try:
+ import fabio
+except ImportError:
+ fabio = None
+
+
+_logger = logging.getLogger(__name__)
+
+
+class _DataPreview(qt.QWidget):
+ """Provide a preview of the selected image"""
+
+ def __init__(self, parent=None):
+ super(_DataPreview, self).__init__(parent)
+
+ self.__formatter = Hdf5Formatter(self)
+ self.__data = None
+ self.__info = qt.QTableView(self)
+ self.__model = qt.QStandardItemModel(self)
+ self.__info.setModel(self.__model)
+ self.__info.horizontalHeader().hide()
+ self.__info.horizontalHeader().setStretchLastSection(True)
+ layout = qt.QVBoxLayout()
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.addWidget(self.__info)
+ self.setLayout(layout)
+
+ def colormap(self):
+ return None
+
+ def setColormap(self, colormap):
+ # Ignored
+ pass
+
+ def sizeHint(self):
+ return qt.QSize(200, 200)
+
+ def setData(self, data, fromDataSelector=False):
+ self.__info.setEnabled(data is not None)
+ if data is None:
+ self.__model.clear()
+ else:
+ self.__model.clear()
+
+ if silx.io.is_dataset(data):
+ kind = "Dataset"
+ elif silx.io.is_group(data):
+ kind = "Group"
+ elif silx.io.is_file(data):
+ kind = "File"
+ else:
+ kind = "Unknown"
+
+ headers = []
+
+ basename = data.name.split("/")[-1]
+ if basename == "":
+ basename = "/"
+ headers.append("Basename")
+ self.__model.appendRow([qt.QStandardItem(basename)])
+ headers.append("Kind")
+ self.__model.appendRow([qt.QStandardItem(kind)])
+ if hasattr(data, "dtype"):
+ headers.append("Type")
+ text = self.__formatter.humanReadableType(data)
+ self.__model.appendRow([qt.QStandardItem(text)])
+ if hasattr(data, "shape"):
+ headers.append("Shape")
+ text = self.__formatter.humanReadableShape(data)
+ self.__model.appendRow([qt.QStandardItem(text)])
+ if hasattr(data, "attrs") and "NX_class" in data.attrs:
+ headers.append("NX_class")
+ value = data.attrs["NX_class"]
+ formatter = self.__formatter.textFormatter()
+ old = formatter.useQuoteForText()
+ formatter.setUseQuoteForText(False)
+ text = self.__formatter.textFormatter().toString(value)
+ formatter.setUseQuoteForText(old)
+ self.__model.appendRow([qt.QStandardItem(text)])
+ self.__model.setVerticalHeaderLabels(headers)
+ self.__data = data
+
+ def __imageItem(self):
+ image = self.__plot.getImage("data")
+ return image
+
+ def data(self):
+ if self.__data is not None:
+ if hasattr(self.__data, "name"):
+ # in case of HDF5
+ if self.__data.name is None:
+ # The dataset was closed
+ self.__data = None
+ return self.__data
+
+ def clear(self):
+ self.__data = None
+ self.__info.setText("")
+
+
+class DataFileDialog(AbstractDataFileDialog):
+ """The `DataFileDialog` class provides a dialog that allow users to select
+ any datasets or groups from an HDF5-like file.
+
+ The `DataFileDialog` class enables a user to traverse the file system in
+ order to select an HDF5-like file. Then to traverse the file to select an
+ HDF5 node.
+
+ .. image:: img/datafiledialog.png
+
+ The selected data is any kind of group or dataset. It can be restricted
+ to only existing datasets or only existing groups using
+ :meth:`setFilterMode`. A callback can be defining using
+ :meth:`setFilterCallback` to filter even more data which can be returned.
+
+ Filtering data which can be returned by a `DataFileDialog` can be done like
+ that:
+
+ .. code-block:: python
+
+ # Force to return only a dataset
+ dialog = DataFileDialog()
+ dialog.setFilterMode(DataFileDialog.FilterMode.ExistingDataset)
+
+ .. code-block:: python
+
+ def customFilter(obj):
+ if "NX_class" in obj.attrs:
+ return obj.attrs["NX_class"] in [b"NXentry", u"NXentry"]
+ return False
+
+ # Force to return an NX entry
+ dialog = DataFileDialog()
+ # 1st, filter out everything which is not a group
+ dialog.setFilterMode(DataFileDialog.FilterMode.ExistingGroup)
+ # 2nd, check what NX_class is an NXentry
+ dialog.setFilterCallback(customFilter)
+
+ Executing a `DataFileDialog` can be done like that:
+
+ .. code-block:: python
+
+ dialog = DataFileDialog()
+ result = dialog.exec_()
+ if result:
+ print("Selection:")
+ print(dialog.selectedFile())
+ print(dialog.selectedUrl())
+ else:
+ print("Nothing selected")
+
+ If the selection is a dataset you can access to the data using
+ :meth:`selectedData`.
+
+ If the selection is a group or if you want to read the selected object on
+ your own you can use the `silx.io` API.
+
+ .. code-block:: python
+
+ url = dialog.selectedUrl()
+ with silx.io.open(url) as data:
+ pass
+
+ Or by loading the file first
+
+ .. code-block:: python
+
+ url = dialog.selectedDataUrl()
+ with silx.io.open(url.file_path()) as h5:
+ data = h5[url.data_path()]
+
+ Or by using `h5py` library
+
+ .. code-block:: python
+
+ url = dialog.selectedDataUrl()
+ with h5py.File(url.file_path()) as h5:
+ data = h5[url.data_path()]
+ """
+
+ class FilterMode(enum.Enum):
+ """This enum is used to indicate what the user may select in the
+ dialog; i.e. what the dialog will return if the user clicks OK."""
+
+ AnyNode = 0
+ """Any existing node from an HDF5-like file."""
+ ExistingDataset = 1
+ """An existing HDF5-like dataset."""
+ ExistingGroup = 2
+ """An existing HDF5-like group. A file root is a group."""
+
+ def __init__(self, parent=None):
+ AbstractDataFileDialog.__init__(self, parent=parent)
+ self.__filter = DataFileDialog.FilterMode.AnyNode
+ self.__filterCallback = None
+
+ def selectedData(self):
+ """Returns the selected data by using the :meth:`silx.io.get_data`
+ API with the selected URL provided by the dialog.
+
+ If the URL identify a group of a file it will raise an exception. For
+ group or file you have to use on your own the API :meth:`silx.io.open`.
+
+ :rtype: numpy.ndarray
+ :raise ValueError: If the URL do not link to a dataset
+ """
+ url = self.selectedUrl()
+ return silx.io.get_data(url)
+
+ def _createPreviewWidget(self, parent):
+ previewWidget = _DataPreview(parent)
+ previewWidget.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding)
+ return previewWidget
+
+ def _createSelectorWidget(self, parent):
+ # There is no selector
+ return None
+
+ def _createPreviewToolbar(self, parent, dataPreviewWidget, dataSelectorWidget):
+ # There is no toolbar
+ return None
+
+ def _isDataSupportable(self, data):
+ """Check if the selected data can be supported at one point.
+
+ If true, the data selector will be checked and it will update the data
+ preview. Else the selecting is disabled.
+
+ :rtype: bool
+ """
+ # Everything is supported
+ return True
+
+ def _isFabioFilesSupported(self):
+ # Everything is supported
+ return False
+
+ def _isDataSupported(self, data):
+ """Check if the data can be returned by the dialog.
+
+ If true, this data can be returned by the dialog and the open button
+ will be enabled. If false the button will be disabled.
+
+ :rtype: bool
+ """
+ if self.__filter == DataFileDialog.FilterMode.AnyNode:
+ accepted = True
+ elif self.__filter == DataFileDialog.FilterMode.ExistingDataset:
+ accepted = silx.io.is_dataset(data)
+ elif self.__filter == DataFileDialog.FilterMode.ExistingGroup:
+ accepted = silx.io.is_group(data)
+ else:
+ raise ValueError("Filter %s is not supported" % self.__filter)
+ if not accepted:
+ return False
+ if self.__filterCallback is not None:
+ try:
+ return self.__filterCallback(data)
+ except Exception:
+ _logger.error("Error while executing custom callback", exc_info=True)
+ return False
+ return True
+
+ def setFilterCallback(self, callback):
+ """Set the filter callback. This filter is applied only if the filter
+ mode (:meth:`filterMode`) first accepts the selected data.
+
+ It is not supposed to be set while the dialog is being used.
+
+ :param callable callback: Define a custom function returning a boolean
+ and taking as argument an h5-like node. If the function returns true
+ the dialog can return the associated URL.
+ """
+ self.__filterCallback = callback
+
+ def setFilterMode(self, mode):
+ """Set the filter mode.
+
+ It is not supposed to be set while the dialog is being used.
+
+ :param DataFileDialog.FilterMode mode: The new filter.
+ """
+ self.__filter = mode
+
+ def fileMode(self):
+ """Returns the filter mode.
+
+ :rtype: DataFileDialog.FilterMode
+ """
+ return self.__filter
+
+ def _displayedDataInfo(self, dataBeforeSelection, dataAfterSelection):
+ """Returns the text displayed under the data preview.
+
+ This zone is used to display error in case or problem of data selection
+ or problems with IO.
+
+ :param numpy.ndarray dataAfterSelection: Data as it is after the
+ selection widget (basically the data from the preview widget)
+ :param numpy.ndarray dataAfterSelection: Data as it is before the
+ selection widget (basically the data from the browsing widget)
+ :rtype: bool
+ """
+ return u""
diff --git a/silx/gui/dialog/FileTypeComboBox.py b/silx/gui/dialog/FileTypeComboBox.py
new file mode 100644
index 0000000..07b11cf
--- /dev/null
+++ b/silx/gui/dialog/FileTypeComboBox.py
@@ -0,0 +1,213 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This module contains utilitaries used by other dialog modules.
+"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "06/02/2018"
+
+try:
+ import fabio
+except ImportError:
+ fabio = None
+import silx.io
+from silx.gui import qt
+
+
+class Codec(object):
+
+ def __init__(self, any_fabio=False, any_silx=False, fabio_codec=None, auto=False):
+ self.__any_fabio = any_fabio
+ self.__any_silx = any_silx
+ self.fabio_codec = fabio_codec
+ self.__auto = auto
+
+ def is_autodetect(self):
+ return self.__auto
+
+ def is_fabio_codec(self):
+ return self.__any_fabio or self.fabio_codec is not None
+
+ def is_silx_codec(self):
+ return self.__any_silx
+
+
+class FileTypeComboBox(qt.QComboBox):
+ """
+ A combobox providing all image file formats supported by fabio and silx.
+
+ It provides access for each fabio codecs individually.
+ """
+
+ EXTENSIONS_ROLE = qt.Qt.UserRole + 1
+
+ CODEC_ROLE = qt.Qt.UserRole + 2
+
+ INDENTATION = u"\u2022 "
+
+ def __init__(self, parent=None):
+ qt.QComboBox.__init__(self, parent)
+ self.__fabioUrlSupported = True
+ self.__initItems()
+
+ def setFabioUrlSupproted(self, isSupported):
+ if self.__fabioUrlSupported == isSupported:
+ return
+ self.__fabioUrlSupported = isSupported
+ self.__initItems()
+
+ def __initItems(self):
+ self.clear()
+ if fabio is not None and self.__fabioUrlSupported:
+ self.__insertFabioFormats()
+ self.__insertSilxFormats()
+ self.__insertAllSupported()
+ self.__insertAnyFiles()
+
+ def __insertAnyFiles(self):
+ index = self.count()
+ self.addItem("All files (*)")
+ self.setItemData(index, ["*"], role=self.EXTENSIONS_ROLE)
+ self.setItemData(index, Codec(auto=True), role=self.CODEC_ROLE)
+
+ def __insertAllSupported(self):
+ allExtensions = set([])
+ for index in range(self.count()):
+ ext = self.itemExtensions(index)
+ allExtensions.update(ext)
+ allExtensions = allExtensions - set("*")
+ list(sorted(list(allExtensions)))
+ index = 0
+ self.insertItem(index, "All supported files")
+ self.setItemData(index, allExtensions, role=self.EXTENSIONS_ROLE)
+ self.setItemData(index, Codec(auto=True), role=self.CODEC_ROLE)
+
+ def __insertSilxFormats(self):
+ formats = silx.io.supported_extensions()
+
+ extensions = []
+ allExtensions = set([])
+
+ for description, ext in formats.items():
+ allExtensions.update(ext)
+ if ext == []:
+ ext = ["*"]
+ extensions.append((description, ext, "silx"))
+ extensions = list(sorted(extensions))
+
+ allExtensions = list(sorted(list(allExtensions)))
+ index = self.count()
+ self.addItem("All supported files, using Silx")
+ self.setItemData(index, allExtensions, role=self.EXTENSIONS_ROLE)
+ self.setItemData(index, Codec(any_silx=True), role=self.CODEC_ROLE)
+
+ for e in extensions:
+ index = self.count()
+ if len(e[1]) < 10:
+ self.addItem("%s%s (%s)" % (self.INDENTATION, e[0], " ".join(e[1])))
+ else:
+ self.addItem("%s%s" % (self.INDENTATION, e[0]))
+ codec = Codec(any_silx=True)
+ self.setItemData(index, e[1], role=self.EXTENSIONS_ROLE)
+ self.setItemData(index, codec, role=self.CODEC_ROLE)
+
+ def __insertFabioFormats(self):
+ formats = fabio.fabioformats.get_classes(reader=True)
+
+ extensions = []
+ allExtensions = set([])
+
+ for reader in formats:
+ if not hasattr(reader, "DESCRIPTION"):
+ continue
+ if not hasattr(reader, "DEFAULT_EXTENSIONS"):
+ continue
+
+ ext = reader.DEFAULT_EXTENSIONS
+ ext = ["*.%s" % e for e in ext]
+ allExtensions.update(ext)
+ if ext == []:
+ ext = ["*"]
+ extensions.append((reader.DESCRIPTION, ext, reader.codec_name()))
+ extensions = list(sorted(extensions))
+
+ allExtensions = list(sorted(list(allExtensions)))
+ index = self.count()
+ self.addItem("All supported files, using Fabio")
+ self.setItemData(index, allExtensions, role=self.EXTENSIONS_ROLE)
+ self.setItemData(index, Codec(any_fabio=True), role=self.CODEC_ROLE)
+
+ for e in extensions:
+ index = self.count()
+ if len(e[1]) < 10:
+ self.addItem("%s%s (%s)" % (self.INDENTATION, e[0], " ".join(e[1])))
+ else:
+ self.addItem(e[0])
+ codec = Codec(fabio_codec=e[2])
+ self.setItemData(index, e[1], role=self.EXTENSIONS_ROLE)
+ self.setItemData(index, codec, role=self.CODEC_ROLE)
+
+ def itemExtensions(self, index):
+ """Returns the extensions associated to an index."""
+ result = self.itemData(index, self.EXTENSIONS_ROLE)
+ if result is None:
+ result = None
+ return result
+
+ def currentExtensions(self):
+ """Returns the current selected extensions."""
+ index = self.currentIndex()
+ return self.itemExtensions(index)
+
+ def indexFromCodec(self, codecName):
+ for i in range(self.count()):
+ codec = self.itemCodec(i)
+ if codecName == "auto":
+ if codec.is_autodetect():
+ return i
+ elif codecName == "silx":
+ if codec.is_silx_codec():
+ return i
+ elif codecName == "fabio":
+ if codec.is_fabio_codec() and codec.fabio_codec is None:
+ return i
+ elif codecName == codec.fabio_codec:
+ return i
+ return -1
+
+ def itemCodec(self, index):
+ """Returns the codec associated to an index."""
+ result = self.itemData(index, self.CODEC_ROLE)
+ if result is None:
+ result = None
+ return result
+
+ def currentCodec(self):
+ """Returns the current selected codec. None if nothing selected
+ or if the item is not a codec"""
+ index = self.currentIndex()
+ return self.itemCodec(index)
diff --git a/silx/gui/dialog/ImageFileDialog.py b/silx/gui/dialog/ImageFileDialog.py
new file mode 100644
index 0000000..c324071
--- /dev/null
+++ b/silx/gui/dialog/ImageFileDialog.py
@@ -0,0 +1,338 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This module contains an :class:`ImageFileDialog`.
+"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "12/02/2018"
+
+import logging
+from silx.gui.plot import actions
+from silx.gui import qt
+from silx.gui.plot.PlotWidget import PlotWidget
+from .AbstractDataFileDialog import AbstractDataFileDialog
+import silx.io
+try:
+ import fabio
+except ImportError:
+ fabio = None
+
+
+_logger = logging.getLogger(__name__)
+
+
+class _ImageSelection(qt.QWidget):
+ """Provide a widget allowing to select an image from an hypercube by
+ selecting a slice."""
+
+ selectionChanged = qt.Signal()
+ """Emitted when the selection change."""
+
+ def __init__(self, parent=None):
+ qt.QWidget.__init__(self, parent)
+ self.__shape = None
+ self.__axis = []
+ layout = qt.QVBoxLayout()
+ self.setLayout(layout)
+
+ def hasVisibleSelectors(self):
+ return self.__visibleSliders > 0
+
+ def isUsed(self):
+ if self.__shape is None:
+ return None
+ return len(self.__shape) > 2
+
+ def getSelectedData(self, data):
+ slicing = self.slicing()
+ image = data[slicing]
+ return image
+
+ def setData(self, data):
+ shape = data.shape
+ if self.__shape is not None:
+ # clean up
+ for widget in self.__axis:
+ self.layout().removeWidget(widget)
+ widget.deleteLater()
+ self.__axis = []
+
+ self.__shape = shape
+ self.__visibleSliders = 0
+
+ if shape is not None:
+ # create expected axes
+ for index in range(len(shape) - 2):
+ axis = qt.QSlider(self)
+ axis.setMinimum(0)
+ axis.setMaximum(shape[index] - 1)
+ axis.setOrientation(qt.Qt.Horizontal)
+ if shape[index] == 1:
+ axis.setVisible(False)
+ else:
+ self.__visibleSliders += 1
+
+ axis.valueChanged.connect(self.__axisValueChanged)
+ self.layout().addWidget(axis)
+ self.__axis.append(axis)
+
+ self.selectionChanged.emit()
+
+ def __axisValueChanged(self):
+ self.selectionChanged.emit()
+
+ def slicing(self):
+ slicing = []
+ for axes in self.__axis:
+ slicing.append(axes.value())
+ return tuple(slicing)
+
+ def setSlicing(self, slicing):
+ for i, value in enumerate(slicing):
+ if i > len(self.__axis):
+ break
+ self.__axis[i].setValue(value)
+
+
+class _ImagePreview(qt.QWidget):
+ """Provide a preview of the selected image"""
+
+ def __init__(self, parent=None):
+ super(_ImagePreview, self).__init__(parent)
+
+ self.__data = None
+ self.__plot = PlotWidget(self)
+ self.__plot.setAxesDisplayed(False)
+ self.__plot.setKeepDataAspectRatio(True)
+ layout = qt.QVBoxLayout()
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.addWidget(self.__plot)
+ self.setLayout(layout)
+
+ def resizeEvent(self, event):
+ self.__updateConstraints()
+ return qt.QWidget.resizeEvent(self, event)
+
+ def sizeHint(self):
+ return qt.QSize(200, 200)
+
+ def plot(self):
+ return self.__plot
+
+ def setData(self, data, fromDataSelector=False):
+ if data is None:
+ self.clear()
+ return
+
+ resetzoom = not fromDataSelector
+ previousImage = self.data()
+ if previousImage is not None and data.shape != previousImage.shape:
+ resetzoom = True
+
+ self.__plot.addImage(legend="data", data=data, resetzoom=resetzoom)
+ self.__data = data
+ self.__updateConstraints()
+
+ def __updateConstraints(self):
+ """
+ Update the constraints depending on the size of the widget
+ """
+ image = self.data()
+ if image is None:
+ return
+ size = self.size()
+ if size.width() == 0 or size.height() == 0:
+ return
+
+ heightData, widthData = image.shape
+
+ widthContraint = heightData * size.width() / size.height()
+ if widthContraint > widthData:
+ heightContraint = heightData
+ else:
+ heightContraint = heightData * size.height() / size.width()
+ widthContraint = widthData
+
+ midWidth, midHeight = widthData * 0.5, heightData * 0.5
+ heightContraint, widthContraint = heightContraint * 0.5, widthContraint * 0.5
+
+ axis = self.__plot.getXAxis()
+ axis.setLimitsConstraints(midWidth - widthContraint, midWidth + widthContraint)
+ axis = self.__plot.getYAxis()
+ axis.setLimitsConstraints(midHeight - heightContraint, midHeight + heightContraint)
+
+ def __imageItem(self):
+ image = self.__plot.getImage("data")
+ return image
+
+ def data(self):
+ if self.__data is not None:
+ if hasattr(self.__data, "name"):
+ # in case of HDF5
+ if self.__data.name is None:
+ # The dataset was closed
+ self.__data = None
+ return self.__data
+
+ def colormap(self):
+ image = self.__imageItem()
+ if image is not None:
+ return image.getColormap()
+ return self.__plot.getDefaultColormap()
+
+ def setColormap(self, colormap):
+ self.__plot.setDefaultColormap(colormap)
+
+ def clear(self):
+ self.__data = None
+ image = self.__imageItem()
+ if image is not None:
+ self.__plot.removeImage(legend="data")
+
+
+class ImageFileDialog(AbstractDataFileDialog):
+ """The `ImageFileDialog` class provides a dialog that allow users to select
+ an image from a file.
+
+ The `ImageFileDialog` class enables a user to traverse the file system in
+ order to select one file. Then to traverse the file to select a frame or
+ a slice of a dataset.
+
+ .. image:: img/imagefiledialog_h5.png
+
+ It supports fast access to image files using `FabIO`. Which is not the case
+ of the default silx API. Image files still also can be available using the
+ NeXus layout, by editing the file type combo box.
+
+ .. image:: img/imagefiledialog_edf.png
+
+ The selected data is an numpy array with 2 dimension.
+
+ Using an `ImageFileDialog` can be done like that.
+
+ .. code-block:: python
+
+ dialog = ImageFileDialog()
+ result = dialog.exec_()
+ if result:
+ print("Selection:")
+ print(dialog.selectedFile())
+ print(dialog.selectedUrl())
+ print(dialog.selectedImage())
+ else:
+ print("Nothing selected")
+ """
+
+ def selectedImage(self):
+ """Returns the selected image data as numpy
+
+ :rtype: numpy.ndarray
+ """
+ url = self.selectedUrl()
+ return silx.io.get_data(url)
+
+ def _createPreviewWidget(self, parent):
+ previewWidget = _ImagePreview(parent)
+ previewWidget.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding)
+ return previewWidget
+
+ def _createSelectorWidget(self, parent):
+ return _ImageSelection(parent)
+
+ def _createPreviewToolbar(self, parent, dataPreviewWidget, dataSelectorWidget):
+ plot = dataPreviewWidget.plot()
+ toolbar = qt.QToolBar(parent)
+ toolbar.setIconSize(qt.QSize(16, 16))
+ toolbar.setStyleSheet("QToolBar { border: 0px }")
+ toolbar.addAction(actions.mode.ZoomModeAction(plot, parent))
+ toolbar.addAction(actions.mode.PanModeAction(plot, parent))
+ toolbar.addSeparator()
+ toolbar.addAction(actions.control.ResetZoomAction(plot, parent))
+ toolbar.addSeparator()
+ toolbar.addAction(actions.control.ColormapAction(plot, parent))
+ return toolbar
+
+ def _isDataSupportable(self, data):
+ """Check if the selected data can be supported at one point.
+
+ If true, the data selector will be checked and it will update the data
+ preview. Else the selecting is disabled.
+
+ :rtype: bool
+ """
+ if not hasattr(data, "dtype"):
+ # It is not an HDF5 dataset nor a fabio image wrapper
+ return False
+
+ if data is None or data.shape is None:
+ return False
+
+ if data.dtype.kind not in set(["f", "u", "i", "b"]):
+ return False
+
+ dim = len(data.shape)
+ return dim >= 2
+
+ def _isFabioFilesSupported(self):
+ return True
+
+ def _isDataSupported(self, data):
+ """Check if the data can be returned by the dialog.
+
+ If true, this data can be returned by the dialog and the open button
+ while be enabled. If false the button will be disabled.
+
+ :rtype: bool
+ """
+ dim = len(data.shape)
+ return dim == 2
+
+ def _displayedDataInfo(self, dataBeforeSelection, dataAfterSelection):
+ """Returns the text displayed under the data preview.
+
+ This zone is used to display error in case or problem of data selection
+ or problems with IO.
+
+ :param numpy.ndarray dataAfterSelection: Data as it is after the
+ selection widget (basically the data from the preview widget)
+ :param numpy.ndarray dataAfterSelection: Data as it is before the
+ selection widget (basically the data from the browsing widget)
+ :rtype: bool
+ """
+ destination = self.__formatShape(dataAfterSelection.shape)
+ source = self.__formatShape(dataBeforeSelection.shape)
+ return u"%s \u2192 %s" % (source, destination)
+
+ def __formatShape(self, shape):
+ result = []
+ for s in shape:
+ if isinstance(s, slice):
+ v = u"\u2026"
+ else:
+ v = str(s)
+ result.append(v)
+ return u" \u00D7 ".join(result)
diff --git a/silx/gui/dialog/SafeFileIconProvider.py b/silx/gui/dialog/SafeFileIconProvider.py
new file mode 100644
index 0000000..7fac7c0
--- /dev/null
+++ b/silx/gui/dialog/SafeFileIconProvider.py
@@ -0,0 +1,150 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This module contains :class:`SafeIconProvider`.
+"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "31/10/2017"
+
+import sys
+import logging
+from silx.gui import qt
+
+
+_logger = logging.getLogger(__name__)
+
+
+class SafeFileIconProvider(qt.QFileIconProvider):
+ """
+ This class reimplement :class:`qt.QFileIconProvider` to avoid blocking
+ access to the file system.
+
+ It avoid to use `qt.QFileInfo.absoluteFilePath` or
+ `qt.QFileInfo.canonicalPath` to reach drive icons which are known to
+ freeze the file system using network drives.
+
+ Computer root, and drive root paths are filtered. Other paths are not
+ filtered while it is anyway needed to synchronoze a drive to accesss to it.
+ """
+
+ WIN32_DRIVE_UNKNOWN = 0
+ """The drive type cannot be determined."""
+ WIN32_DRIVE_NO_ROOT_DIR = 1
+ """The root path is invalid; for example, there is no volume mounted at the
+ specified path."""
+ WIN32_DRIVE_REMOVABLE = 2
+ """The drive has removable media; for example, a floppy drive, thumb drive,
+ or flash card reader."""
+ WIN32_DRIVE_FIXED = 3
+ """The drive has fixed media; for example, a hard disk drive or flash
+ drive."""
+ WIN32_DRIVE_REMOTE = 4
+ """The drive is a remote (network) drive."""
+ WIN32_DRIVE_CDROM = 5
+ """The drive is a CD-ROM drive."""
+ WIN32_DRIVE_RAMDISK = 6
+ """The drive is a RAM disk."""
+
+ def __init__(self):
+ qt.QFileIconProvider.__init__(self)
+ self.__filterDirAndFiles = False
+ if sys.platform == "win32":
+ self._windowsTypes = {}
+ item = "Drive", qt.QStyle.SP_DriveHDIcon
+ self._windowsTypes[self.WIN32_DRIVE_UNKNOWN] = item
+ item = "Invalid root", qt.QStyle.SP_DriveHDIcon
+ self._windowsTypes[self.WIN32_DRIVE_NO_ROOT_DIR] = item
+ item = "Removable", qt.QStyle.SP_DriveNetIcon
+ self._windowsTypes[self.WIN32_DRIVE_REMOVABLE] = item
+ item = "Drive", qt.QStyle.SP_DriveHDIcon
+ self._windowsTypes[self.WIN32_DRIVE_FIXED] = item
+ item = "Remote", qt.QStyle.SP_DriveNetIcon
+ self._windowsTypes[self.WIN32_DRIVE_REMOTE] = item
+ item = "CD-ROM", qt.QStyle.SP_DriveCDIcon
+ self._windowsTypes[self.WIN32_DRIVE_CDROM] = item
+ item = "RAM disk", qt.QStyle.SP_DriveHDIcon
+ self._windowsTypes[self.WIN32_DRIVE_RAMDISK] = item
+
+ def __windowsDriveTypeId(self, info):
+ try:
+ import ctypes
+ path = info.filePath()
+ dtype = ctypes.cdll.kernel32.GetDriveTypeW(path)
+ except Exception:
+ _logger.warning("Impossible to identify drive %s" % path)
+ _logger.debug("Backtrace", exc_info=True)
+ return self.WIN32_DRIVE_UNKNOWN
+ return dtype
+
+ def __windowsDriveIcon(self, info):
+ dtype = self.__windowsDriveTypeId(info)
+ default = self._windowsTypes[self.WIN32_DRIVE_UNKNOWN]
+ driveInfo = self._windowsTypes.get(dtype, default)
+ style = qt.QApplication.instance().style()
+ icon = style.standardIcon(driveInfo[1])
+ return icon
+
+ def __windowsDriveType(self, info):
+ dtype = self.__windowsDriveTypeId(info)
+ default = self._windowsTypes[self.WIN32_DRIVE_UNKNOWN]
+ driveInfo = self._windowsTypes.get(dtype, default)
+ return driveInfo[0]
+
+ def icon(self, info):
+ style = qt.QApplication.instance().style()
+ path = info.filePath()
+ if path in ["", "/"]:
+ # That's the computer root on Windows or Linux
+ result = style.standardIcon(qt.QStyle.SP_ComputerIcon)
+ elif sys.platform == "win32" and path[-2] == ":":
+ # That's a drive on Windows
+ result = self.__windowsDriveIcon(info)
+ elif self.__filterDirAndFiles:
+ if info.isDir():
+ result = style.standardIcon(qt.QStyle.SP_DirIcon)
+ else:
+ result = style.standardIcon(qt.QStyle.SP_FileIcon)
+ else:
+ result = qt.QFileIconProvider.icon(self, info)
+ return result
+
+ def type(self, info):
+ path = info.filePath()
+ if path in ["", "/"]:
+ # That's the computer root on Windows or Linux
+ result = "Computer"
+ elif sys.platform == "win32" and path[-2] == ":":
+ # That's a drive on Windows
+ result = self.__windowsDriveType(info)
+ elif self.__filterDirAndFiles:
+ if info.isDir():
+ result = "Directory"
+ else:
+ result = info.suffix()
+ else:
+ result = qt.QFileIconProvider.type(self, info)
+ return result
diff --git a/silx/gui/dialog/SafeFileSystemModel.py b/silx/gui/dialog/SafeFileSystemModel.py
new file mode 100644
index 0000000..8a97974
--- /dev/null
+++ b/silx/gui/dialog/SafeFileSystemModel.py
@@ -0,0 +1,802 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This module contains an :class:`SafeFileSystemModel`.
+"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "22/11/2017"
+
+import sys
+import os.path
+import logging
+import weakref
+from silx.gui import qt
+from silx.third_party import six
+from .SafeFileIconProvider import SafeFileIconProvider
+
+_logger = logging.getLogger(__name__)
+
+
+class _Item(object):
+
+ def __init__(self, fileInfo):
+ self.__fileInfo = fileInfo
+ self.__parent = None
+ self.__children = None
+ self.__absolutePath = None
+
+ def isDrive(self):
+ if sys.platform == "win32":
+ return self.parent().parent() is None
+ else:
+ return False
+
+ def isRoot(self):
+ return self.parent() is None
+
+ def isFile(self):
+ """
+ Returns true if the path is a file.
+
+ It avoid to access to the `Qt.QFileInfo` in case the file is a drive.
+ """
+ if self.isDrive():
+ return False
+ return self.__fileInfo.isFile()
+
+ def isDir(self):
+ """
+ Returns true if the path is a directory.
+
+ The default `qt.QFileInfo.isDir` can freeze the file system with
+ network drives. This function avoid the freeze in case of browsing
+ the root.
+ """
+ if self.isDrive():
+ # A drive is a directory, we don't have to synchronize the
+ # drive to know that
+ return True
+ return self.__fileInfo.isDir()
+
+ def absoluteFilePath(self):
+ """
+ Returns an absolute path including the file name.
+
+ This function uses in most cases the default
+ `qt.QFileInfo.absoluteFilePath`. But it is known to freeze the file
+ system with network drives.
+
+ This function uses `qt.QFileInfo.filePath` in case of root drives, to
+ avoid this kind of issues. In case of drive, the result is the same,
+ while the file path is already absolute.
+
+ :rtype: str
+ """
+ if self.__absolutePath is None:
+ if self.isRoot():
+ path = ""
+ elif self.isDrive():
+ path = self.__fileInfo.filePath()
+ else:
+ path = os.path.join(self.parent().absoluteFilePath(), self.__fileInfo.fileName())
+ if path == "":
+ return "/"
+ self.__absolutePath = path
+ return self.__absolutePath
+
+ def child(self):
+ self.populate()
+ return self.__children
+
+ def childAt(self, position):
+ self.populate()
+ return self.__children[position]
+
+ def childCount(self):
+ self.populate()
+ return len(self.__children)
+
+ def indexOf(self, item):
+ self.populate()
+ return self.__children.index(item)
+
+ def parent(self):
+ parent = self.__parent
+ if parent is None:
+ return None
+ return parent()
+
+ def filePath(self):
+ return self.__fileInfo.filePath()
+
+ def fileName(self):
+ if self.isDrive():
+ name = self.absoluteFilePath()
+ if name[-1] == "/":
+ name = name[:-1]
+ return name
+ return os.path.basename(self.absoluteFilePath())
+
+ def fileInfo(self):
+ """
+ Returns the Qt file info.
+
+ :rtype: Qt.QFileInfo
+ """
+ return self.__fileInfo
+
+ def _setParent(self, parent):
+ self.__parent = weakref.ref(parent)
+
+ def findChildrenByPath(self, path):
+ if path == "":
+ return self
+ path = path.replace("\\", "/")
+ if path[-1] == "/":
+ path = path[:-1]
+ names = path.split("/")
+ caseSensitive = qt.QFSFileEngine(path).caseSensitive()
+ count = len(names)
+ cursor = self
+ for name in names:
+ for item in cursor.child():
+ if caseSensitive:
+ same = item.fileName() == name
+ else:
+ same = item.fileName().lower() == name.lower()
+ if same:
+ cursor = item
+ count -= 1
+ break
+ else:
+ return None
+ if count == 0:
+ break
+ else:
+ return None
+ return cursor
+
+ def populate(self):
+ if self.__children is not None:
+ return
+ self.__children = []
+ if self.isRoot():
+ items = qt.QDir.drives()
+ else:
+ directory = qt.QDir(self.absoluteFilePath())
+ filters = qt.QDir.AllEntries | qt.QDir.Hidden | qt.QDir.System
+ items = directory.entryInfoList(filters)
+ for fileInfo in items:
+ i = _Item(fileInfo)
+ self.__children.append(i)
+ i._setParent(self)
+
+
+class _RawFileSystemModel(qt.QAbstractItemModel):
+ """
+ This class implement a file system model and try to avoid freeze. On Qt4,
+ :class:`qt.QFileSystemModel` is known to freeze the file system when
+ network drives are available.
+
+ To avoid this behaviour, this class does not use
+ `qt.QFileInfo.absoluteFilePath` nor `qt.QFileInfo.canonicalPath` to reach
+ information on drives.
+
+ This model do not take care of sorting and filtering. This features are
+ managed by another model, by composition.
+
+ And because it is the end of life of Qt4, we do not implement asynchronous
+ loading of files as it is done by :class:`qt.QFileSystemModel`, nor some
+ useful features.
+ """
+
+ __directoryLoadedSync = qt.Signal(str)
+ """This signal is connected asynchronously to a slot. It allows to
+ emit directoryLoaded as an asynchronous signal."""
+
+ directoryLoaded = qt.Signal(str)
+ """This signal is emitted when the gatherer thread has finished to load the
+ path."""
+
+ rootPathChanged = qt.Signal(str)
+ """This signal is emitted whenever the root path has been changed to a
+ newPath."""
+
+ NAME_COLUMN = 0
+ SIZE_COLUMN = 1
+ TYPE_COLUMN = 2
+ LAST_MODIFIED_COLUMN = 3
+
+ def __init__(self, parent=None):
+ qt.QAbstractItemModel.__init__(self, parent)
+ self.__computer = _Item(qt.QFileInfo())
+ self.__header = "Name", "Size", "Type", "Last modification"
+ self.__currentPath = ""
+ self.__iconProvider = SafeFileIconProvider()
+ self.__directoryLoadedSync.connect(self.__emitDirectoryLoaded, qt.Qt.QueuedConnection)
+
+ def headerData(self, section, orientation, role=qt.Qt.DisplayRole):
+ if orientation == qt.Qt.Horizontal:
+ if role == qt.Qt.DisplayRole:
+ return self.__header[section]
+ if role == qt.Qt.TextAlignmentRole:
+ return qt.Qt.AlignRight if section == 1 else qt.Qt.AlignLeft
+ return None
+
+ def flags(self, index):
+ if not index.isValid():
+ return 0
+ return qt.Qt.ItemIsEnabled | qt.Qt.ItemIsSelectable
+
+ def columnCount(self, parent=qt.QModelIndex()):
+ return len(self.__header)
+
+ def rowCount(self, parent=qt.QModelIndex()):
+ item = self.__getItem(parent)
+ return item.childCount()
+
+ def data(self, index, role=qt.Qt.DisplayRole):
+ if not index.isValid():
+ return None
+
+ column = index.column()
+ if role in [qt.Qt.DisplayRole, qt.Qt.EditRole]:
+ if column == self.NAME_COLUMN:
+ return self.__displayName(index)
+ elif column == self.SIZE_COLUMN:
+ return self.size(index)
+ elif column == self.TYPE_COLUMN:
+ return self.type(index)
+ elif column == self.LAST_MODIFIED_COLUMN:
+ return self.lastModified(index)
+ else:
+ _logger.warning("data: invalid display value column %d", index.column())
+ elif role == qt.QFileSystemModel.FilePathRole:
+ return self.filePath(index)
+ elif role == qt.QFileSystemModel.FileNameRole:
+ return self.fileName(index)
+ elif role == qt.Qt.DecorationRole:
+ if column == self.NAME_COLUMN:
+ icon = self.fileIcon(index)
+ if icon is None or icon.isNull():
+ if self.isDir(index):
+ self.__iconProvider.icon(qt.QFileIconProvider.Folder)
+ else:
+ self.__iconProvider.icon(qt.QFileIconProvider.File)
+ return icon
+ elif role == qt.Qt.TextAlignmentRole:
+ if column == self.SIZE_COLUMN:
+ return qt.Qt.AlignRight
+ elif role == qt.QFileSystemModel.FilePermissions:
+ return self.permissions(index)
+
+ return None
+
+ def index(self, *args, **kwargs):
+ path_api = False
+ path_api |= len(args) >= 1 and isinstance(args[0], six.string_types)
+ path_api |= "path" in kwargs
+
+ if path_api:
+ return self.__indexFromPath(*args, **kwargs)
+ else:
+ return self.__index(*args, **kwargs)
+
+ def __index(self, row, column, parent=qt.QModelIndex()):
+ if parent.isValid() and parent.column() != 0:
+ return None
+
+ parentItem = self.__getItem(parent)
+ item = parentItem.childAt(row)
+ return self.createIndex(row, column, item)
+
+ def __indexFromPath(self, path, column=0):
+ """
+ Uses the index(str) C++ API
+
+ :rtype: qt.QModelIndex
+ """
+ if path == "":
+ return qt.QModelIndex()
+
+ item = self.__computer.findChildrenByPath(path)
+ if item is None:
+ return qt.QModelIndex()
+
+ return self.createIndex(item.parent().indexOf(item), column, item)
+
+ def parent(self, index):
+ if not index.isValid():
+ return qt.QModelIndex()
+
+ item = self.__getItem(index)
+ if index is None:
+ return qt.QModelIndex()
+
+ parent = item.parent()
+ if parent is None or parent is self.__computer:
+ return qt.QModelIndex()
+
+ return self.createIndex(parent.parent().indexOf(parent), 0, parent)
+
+ def __emitDirectoryLoaded(self, path):
+ self.directoryLoaded.emit(path)
+
+ def __emitRootPathChanged(self, path):
+ self.rootPathChanged.emit(path)
+
+ def __getItem(self, index):
+ if not index.isValid():
+ return self.__computer
+ item = index.internalPointer()
+ return item
+
+ def fileIcon(self, index):
+ item = self.__getItem(index)
+ if self.__iconProvider is not None:
+ fileInfo = item.fileInfo()
+ result = self.__iconProvider.icon(fileInfo)
+ else:
+ style = qt.QApplication.instance().style()
+ if item.isRoot():
+ result = style.standardIcon(qt.QStyle.SP_ComputerIcon)
+ elif item.isDrive():
+ result = style.standardIcon(qt.QStyle.SP_DriveHDIcon)
+ elif item.isDir():
+ result = style.standardIcon(qt.QStyle.SP_DirIcon)
+ else:
+ result = style.standardIcon(qt.QStyle.SP_FileIcon)
+ return result
+
+ def _item(self, index):
+ item = self.__getItem(index)
+ return item
+
+ def fileInfo(self, index):
+ item = self.__getItem(index)
+ result = item.fileInfo()
+ return result
+
+ def __fileIcon(self, index):
+ item = self.__getItem(index)
+ result = item.fileName()
+ return result
+
+ def __displayName(self, index):
+ item = self.__getItem(index)
+ result = item.fileName()
+ return result
+
+ def fileName(self, index):
+ item = self.__getItem(index)
+ result = item.fileName()
+ return result
+
+ def filePath(self, index):
+ item = self.__getItem(index)
+ result = item.fileInfo().filePath()
+ return result
+
+ def isDir(self, index):
+ item = self.__getItem(index)
+ result = item.isDir()
+ return result
+
+ def lastModified(self, index):
+ item = self.__getItem(index)
+ result = item.fileInfo().lastModified()
+ return result
+
+ def permissions(self, index):
+ item = self.__getItem(index)
+ result = item.fileInfo().permissions()
+ return result
+
+ def size(self, index):
+ item = self.__getItem(index)
+ result = item.fileInfo().size()
+ return result
+
+ def type(self, index):
+ item = self.__getItem(index)
+ if self.__iconProvider is not None:
+ fileInfo = item.fileInfo()
+ result = self.__iconProvider.type(fileInfo)
+ else:
+ if item.isRoot():
+ result = "Computer"
+ elif item.isDrive():
+ result = "Drive"
+ elif item.isDir():
+ result = "Directory"
+ else:
+ fileInfo = item.fileInfo()
+ result = fileInfo.suffix()
+ return result
+
+ # File manipulation
+
+ # bool remove(const QModelIndex & index) const
+ # bool rmdir(const QModelIndex & index) const
+ # QModelIndex mkdir(const QModelIndex & parent, const QString & name)
+
+ # Configuration
+
+ def rootDirectory(self):
+ return qt.QDir(self.rootPath())
+
+ def rootPath(self):
+ return self.__currentPath
+
+ def setRootPath(self, path):
+ if self.__currentPath == path:
+ return
+ self.__currentPath = path
+ item = self.__computer.findChildrenByPath(path)
+ self.__emitRootPathChanged(path)
+ if item is None or item.parent() is None:
+ return qt.QModelIndex()
+ index = self.createIndex(item.parent().indexOf(item), 0, item)
+ self.__directoryLoadedSync.emit(path)
+ return index
+
+ def iconProvider(self):
+ # FIXME: invalidate the model
+ return self.__iconProvider
+
+ def setIconProvider(self, provider):
+ # FIXME: invalidate the model
+ self.__iconProvider = provider
+
+ # bool resolveSymlinks() const
+ # void setResolveSymlinks(bool enable)
+
+ def setNameFilterDisables(self, enable):
+ return None
+
+ def nameFilterDisables(self):
+ return None
+
+ def myComputer(self, role=qt.Qt.DisplayRole):
+ return None
+
+ def setNameFilters(self, filters):
+ return
+
+ def nameFilters(self):
+ return None
+
+ def filter(self):
+ return self.__filters
+
+ def setFilter(self, filters):
+ return
+
+ def setReadOnly(self, enable):
+ assert(enable is True)
+
+ def isReadOnly(self):
+ return False
+
+
+class SafeFileSystemModel(qt.QSortFilterProxyModel):
+ """
+ This class implement a file system model and try to avoid freeze. On Qt4,
+ :class:`qt.QFileSystemModel` is known to freeze the file system when
+ network drives are available.
+
+ To avoid this behaviour, this class does not use
+ `qt.QFileInfo.absoluteFilePath` nor `qt.QFileInfo.canonicalPath` to reach
+ information on drives.
+
+ And because it is the end of life of Qt4, we do not implement asynchronous
+ loading of files as it is done by :class:`qt.QFileSystemModel`, nor some
+ useful features.
+ """
+
+ def __init__(self, parent=None):
+ qt.QSortFilterProxyModel.__init__(self, parent=parent)
+ self.__nameFilterDisables = sys.platform == "darwin"
+ self.__nameFilters = []
+ self.__filters = qt.QDir.AllEntries | qt.QDir.NoDotAndDotDot | qt.QDir.AllDirs
+ sourceModel = _RawFileSystemModel(self)
+ self.setSourceModel(sourceModel)
+
+ @property
+ def directoryLoaded(self):
+ return self.sourceModel().directoryLoaded
+
+ @property
+ def rootPathChanged(self):
+ return self.sourceModel().rootPathChanged
+
+ def index(self, *args, **kwargs):
+ path_api = False
+ path_api |= len(args) >= 1 and isinstance(args[0], six.string_types)
+ path_api |= "path" in kwargs
+
+ if path_api:
+ return self.__indexFromPath(*args, **kwargs)
+ else:
+ return self.__index(*args, **kwargs)
+
+ def __index(self, row, column, parent=qt.QModelIndex()):
+ return qt.QSortFilterProxyModel.index(self, row, column, parent)
+
+ def __indexFromPath(self, path, column=0):
+ """
+ Uses the index(str) C++ API
+
+ :rtype: qt.QModelIndex
+ """
+ if path == "":
+ return qt.QModelIndex()
+
+ index = self.sourceModel().index(path, column)
+ index = self.mapFromSource(index)
+ return index
+
+ def lessThan(self, leftSourceIndex, rightSourceIndex):
+ sourceModel = self.sourceModel()
+ sortColumn = self.sortColumn()
+ if sortColumn == _RawFileSystemModel.NAME_COLUMN:
+ leftItem = sourceModel._item(leftSourceIndex)
+ rightItem = sourceModel._item(rightSourceIndex)
+ if sys.platform != "darwin":
+ # Sort directories before files
+ leftIsDir = leftItem.isDir()
+ rightIsDir = rightItem.isDir()
+ if leftIsDir ^ rightIsDir:
+ return leftIsDir
+ return leftItem.fileName().lower() < rightItem.fileName().lower()
+ elif sortColumn == _RawFileSystemModel.SIZE_COLUMN:
+ left = sourceModel.fileInfo(leftSourceIndex)
+ right = sourceModel.fileInfo(rightSourceIndex)
+ return left.size() < right.size()
+ elif sortColumn == _RawFileSystemModel.TYPE_COLUMN:
+ left = sourceModel.type(leftSourceIndex)
+ right = sourceModel.type(rightSourceIndex)
+ return left < right
+ elif sortColumn == _RawFileSystemModel.LAST_MODIFIED_COLUMN:
+ left = sourceModel.fileInfo(leftSourceIndex)
+ right = sourceModel.fileInfo(rightSourceIndex)
+ return left.lastModified() < right.lastModified()
+ else:
+ _logger.warning("Unsupported sorted column %d", sortColumn)
+
+ return False
+
+ def __filtersAccepted(self, item, filters):
+ """
+ Check individual flag filters.
+ """
+ if not (filters & (qt.QDir.Dirs | qt.QDir.AllDirs)):
+ # Hide dirs
+ if item.isDir():
+ return False
+ if not (filters & qt.QDir.Files):
+ # Hide files
+ if item.isFile():
+ return False
+ if not (filters & qt.QDir.Drives):
+ # Hide drives
+ if item.isDrive():
+ return False
+
+ fileInfo = item.fileInfo()
+ if fileInfo is None:
+ return False
+
+ filterPermissions = (filters & qt.QDir.PermissionMask) != 0
+ if filterPermissions and (filters & (qt.QDir.Dirs | qt.QDir.Files)):
+ if (filters & qt.QDir.Readable):
+ # Hide unreadable
+ if not fileInfo.isReadable():
+ return False
+ if (filters & qt.QDir.Writable):
+ # Hide unwritable
+ if not fileInfo.isWritable():
+ return False
+ if (filters & qt.QDir.Executable):
+ # Hide unexecutable
+ if not fileInfo.isExecutable():
+ return False
+
+ if (filters & qt.QDir.NoSymLinks):
+ # Hide sym links
+ if fileInfo.isSymLink():
+ return False
+
+ if not (filters & qt.QDir.System):
+ # Hide system
+ if not item.isDir() and not item.isFile():
+ return False
+
+ fileName = item.fileName()
+ isDot = fileName == "."
+ isDotDot = fileName == ".."
+
+ if not (filters & qt.QDir.Hidden):
+ # Hide hidden
+ if not (isDot or isDotDot) and fileInfo.isHidden():
+ return False
+
+ if filters & (qt.QDir.NoDot | qt.QDir.NoDotDot | qt.QDir.NoDotAndDotDot):
+ # Hide parent/self references
+ if filters & qt.QDir.NoDot:
+ if isDot:
+ return False
+ if filters & qt.QDir.NoDotDot:
+ if isDotDot:
+ return False
+ if filters & qt.QDir.NoDotAndDotDot:
+ if isDot or isDotDot:
+ return False
+
+ return True
+
+ def filterAcceptsRow(self, sourceRow, sourceParent):
+ if not sourceParent.isValid():
+ return True
+
+ sourceModel = self.sourceModel()
+ index = sourceModel.index(sourceRow, 0, sourceParent)
+ if not index.isValid():
+ return True
+ item = sourceModel._item(index)
+
+ filters = self.__filters
+
+ if item.isDrive():
+ # Let say a user always have access to a drive
+ # It avoid to access to fileInfo then avoid to freeze the file
+ # system
+ return True
+
+ if not self.__filtersAccepted(item, filters):
+ return False
+
+ if self.__nameFilterDisables:
+ return True
+
+ if item.isDir() and (filters & qt.QDir.AllDirs):
+ # dont apply the filters to directory names
+ return True
+
+ return self.__nameFiltersAccepted(item)
+
+ def __nameFiltersAccepted(self, item):
+ if len(self.__nameFilters) == 0:
+ return True
+
+ fileName = item.fileName()
+ for reg in self.__nameFilters:
+ if reg.exactMatch(fileName):
+ return True
+ return False
+
+ def setNameFilterDisables(self, enable):
+ self.__nameFilterDisables = enable
+ self.invalidate()
+
+ def nameFilterDisables(self):
+ return self.__nameFilterDisables
+
+ def myComputer(self, role=qt.Qt.DisplayRole):
+ return self.sourceModel().myComputer(role)
+
+ def setNameFilters(self, filters):
+ self.__nameFilters = []
+ isCaseSensitive = self.__filters & qt.QDir.CaseSensitive
+ caseSensitive = qt.Qt.CaseSensitive if isCaseSensitive else qt.Qt.CaseInsensitive
+ for f in filters:
+ reg = qt.QRegExp(f, caseSensitive, qt.QRegExp.Wildcard)
+ self.__nameFilters.append(reg)
+ self.invalidate()
+
+ def nameFilters(self):
+ return [f.pattern() for f in self.__nameFilters]
+
+ def filter(self):
+ return self.__filters
+
+ def setFilter(self, filters):
+ self.__filters = filters
+ # In case of change of case sensitivity
+ self.setNameFilters(self.nameFilters())
+ self.invalidate()
+
+ def setReadOnly(self, enable):
+ assert(enable is True)
+
+ def isReadOnly(self):
+ return False
+
+ def rootPath(self):
+ return self.sourceModel().rootPath()
+
+ def setRootPath(self, path):
+ index = self.sourceModel().setRootPath(path)
+ index = self.mapFromSource(index)
+ return index
+
+ def flags(self, index):
+ sourceModel = self.sourceModel()
+ index = self.mapToSource(index)
+ filters = sourceModel.flags(index)
+
+ if self.__nameFilterDisables:
+ item = sourceModel._item(index)
+ if not self.__nameFiltersAccepted(item):
+ filters &= ~qt.Qt.ItemIsEnabled
+
+ return filters
+
+ def fileIcon(self, index):
+ sourceModel = self.sourceModel()
+ index = self.mapToSource(index)
+ return sourceModel.fileIcon(index)
+
+ def fileInfo(self, index):
+ sourceModel = self.sourceModel()
+ index = self.mapToSource(index)
+ return sourceModel.fileInfo(index)
+
+ def fileName(self, index):
+ sourceModel = self.sourceModel()
+ index = self.mapToSource(index)
+ return sourceModel.fileName(index)
+
+ def filePath(self, index):
+ sourceModel = self.sourceModel()
+ index = self.mapToSource(index)
+ return sourceModel.filePath(index)
+
+ def isDir(self, index):
+ sourceModel = self.sourceModel()
+ index = self.mapToSource(index)
+ return sourceModel.isDir(index)
+
+ def lastModified(self, index):
+ sourceModel = self.sourceModel()
+ index = self.mapToSource(index)
+ return sourceModel.lastModified(index)
+
+ def permissions(self, index):
+ sourceModel = self.sourceModel()
+ index = self.mapToSource(index)
+ return sourceModel.permissions(index)
+
+ def size(self, index):
+ sourceModel = self.sourceModel()
+ index = self.mapToSource(index)
+ return sourceModel.size(index)
+
+ def type(self, index):
+ sourceModel = self.sourceModel()
+ index = self.mapToSource(index)
+ return sourceModel.type(index)
diff --git a/silx/gui/dialog/__init__.py b/silx/gui/dialog/__init__.py
new file mode 100644
index 0000000..77c5949
--- /dev/null
+++ b/silx/gui/dialog/__init__.py
@@ -0,0 +1,29 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Qt dialogs"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "11/10/2017"
diff --git a/silx/gui/dialog/setup.py b/silx/gui/dialog/setup.py
new file mode 100644
index 0000000..48ab8d8
--- /dev/null
+++ b/silx/gui/dialog/setup.py
@@ -0,0 +1,40 @@
+# coding: utf-8
+# /*##########################################################################
+# Copyright (C) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ############################################################################*/
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "23/10/2017"
+
+from numpy.distutils.misc_util import Configuration
+
+
+def configuration(parent_package='', top_path=None):
+ config = Configuration('dialog', parent_package, top_path)
+ config.add_subpackage('test')
+ return config
+
+
+if __name__ == "__main__":
+ from numpy.distutils.core import setup
+ setup(configuration=configuration)
diff --git a/silx/gui/dialog/test/__init__.py b/silx/gui/dialog/test/__init__.py
new file mode 100644
index 0000000..eee8aea
--- /dev/null
+++ b/silx/gui/dialog/test/__init__.py
@@ -0,0 +1,47 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Tests for Qt dialogs"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "07/02/2018"
+
+
+import logging
+import os
+import sys
+import unittest
+
+
+_logger = logging.getLogger(__name__)
+
+
+def suite():
+ test_suite = unittest.TestSuite()
+ from . import test_imagefiledialog
+ from . import test_datafiledialog
+ test_suite.addTest(test_imagefiledialog.suite())
+ test_suite.addTest(test_datafiledialog.suite())
+ return test_suite
diff --git a/silx/gui/dialog/test/test_datafiledialog.py b/silx/gui/dialog/test/test_datafiledialog.py
new file mode 100644
index 0000000..bdda810
--- /dev/null
+++ b/silx/gui/dialog/test/test_datafiledialog.py
@@ -0,0 +1,981 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Test for silx.gui.hdf5 module"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "14/02/2018"
+
+
+import unittest
+import tempfile
+import numpy
+import shutil
+import os
+import io
+import weakref
+
+try:
+ import fabio
+except ImportError:
+ fabio = None
+try:
+ import h5py
+except ImportError:
+ h5py = None
+
+import silx.io.url
+from silx.gui import qt
+from silx.gui.test import utils
+from ..DataFileDialog import DataFileDialog
+from silx.gui.hdf5 import Hdf5TreeModel
+
+_tmpDirectory = None
+
+
+def setUpModule():
+ global _tmpDirectory
+ _tmpDirectory = tempfile.mkdtemp(prefix=__name__)
+
+ data = numpy.arange(100 * 100)
+ data.shape = 100, 100
+
+ if fabio is not None:
+ filename = _tmpDirectory + "/singleimage.edf"
+ image = fabio.edfimage.EdfImage(data=data)
+ image.write(filename)
+
+ if h5py is not None:
+ filename = _tmpDirectory + "/data.h5"
+ f = h5py.File(filename, "w")
+ f["scalar"] = 10
+ f["image"] = data
+ f["cube"] = [data, data + 1, data + 2]
+ f["complex_image"] = data * 1j
+ f["group/image"] = data
+ f["nxdata/foo"] = 10
+ f["nxdata"].attrs["NX_class"] = u"NXdata"
+ f.close()
+
+ filename = _tmpDirectory + "/badformat.h5"
+ with io.open(filename, "wb") as f:
+ f.write(b"{\nHello Nurse!")
+
+
+def tearDownModule():
+ global _tmpDirectory
+ shutil.rmtree(_tmpDirectory)
+ _tmpDirectory = None
+
+
+class _UtilsMixin(object):
+
+ def createDialog(self):
+ self._deleteDialog()
+ self._dialog = self._createDialog()
+ return self._dialog
+
+ def _createDialog(self):
+ return DataFileDialog()
+
+ def _deleteDialog(self):
+ if not hasattr(self, "_dialog"):
+ return
+ if self._dialog is not None:
+ ref = weakref.ref(self._dialog)
+ self._dialog = None
+ self.qWaitForDestroy(ref)
+
+ def qWaitForPendingActions(self, dialog):
+ for _ in range(20):
+ if not dialog.hasPendingEvents():
+ return
+ self.qWait(10)
+ raise RuntimeError("Still have pending actions")
+
+ def assertSamePath(self, path1, path2):
+ path1_ = os.path.normcase(path1)
+ path2_ = os.path.normcase(path2)
+ if path1_ != path2_:
+ # Use the unittest API to log and display error
+ self.assertEquals(path1, path2)
+
+ def assertNotSamePath(self, path1, path2):
+ path1_ = os.path.normcase(path1)
+ path2_ = os.path.normcase(path2)
+ if path1_ == path2_:
+ # Use the unittest API to log and display error
+ self.assertNotEquals(path1, path2)
+
+
+class TestDataFileDialogInteraction(utils.TestCaseQt, _UtilsMixin):
+
+ def tearDown(self):
+ self._deleteDialog()
+ utils.TestCaseQt.tearDown(self)
+
+ def testDisplayAndKeyEscape(self):
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+
+ self.keyClick(dialog, qt.Qt.Key_Escape)
+ self.assertFalse(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Rejected)
+
+ def testDisplayAndClickCancel(self):
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="cancel")[0]
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.assertFalse(dialog.isVisible())
+ self.assertFalse(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Rejected)
+
+ def testDisplayAndClickLockedOpen(self):
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.mouseClick(button, qt.Qt.LeftButton)
+ # open button locked, dialog is not closed
+ self.assertTrue(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Rejected)
+
+ def testSelectRoot_Activate(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+ filename = _tmpDirectory + "/data.h5"
+ dialog.selectFile(os.path.dirname(filename))
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().index(filename)
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.assertTrue(button.isEnabled())
+ self.mouseClick(button, qt.Qt.LeftButton)
+ url = silx.io.url.DataUrl(dialog.selectedUrl())
+ self.assertTrue(url.data_path() is not None)
+ self.assertFalse(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Accepted)
+
+ def testSelectGroup_Activate(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+ filename = _tmpDirectory + "/data.h5"
+ dialog.selectFile(os.path.dirname(filename))
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().index(filename)
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"])
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.assertTrue(button.isEnabled())
+ self.mouseClick(button, qt.Qt.LeftButton)
+ url = silx.io.url.DataUrl(dialog.selectedUrl())
+ self.assertEqual(url.data_path(), "/group")
+ self.assertFalse(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Accepted)
+
+ def testSelectDataset_Activate(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+ filename = _tmpDirectory + "/data.h5"
+ dialog.selectFile(os.path.dirname(filename))
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().index(filename)
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"])
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.assertTrue(button.isEnabled())
+ self.mouseClick(button, qt.Qt.LeftButton)
+ url = silx.io.url.DataUrl(dialog.selectedUrl())
+ self.assertEqual(url.data_path(), "/scalar")
+ self.assertFalse(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Accepted)
+
+ def testClickOnBackToParentTool(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ url = utils.findChildren(dialog, qt.QLineEdit, name="url")[0]
+ action = utils.findChildren(dialog, qt.QAction, name="toParentAction")[0]
+ toParentButton = utils.getQToolButtonFromAction(action)
+ filename = _tmpDirectory + "/data.h5"
+
+ # init state
+ path = silx.io.url.DataUrl(file_path=filename, data_path="/group/image").path()
+ dialog.selectUrl(path)
+ self.qWaitForPendingActions(dialog)
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path()
+ self.assertSamePath(url.text(), path)
+ # test
+ self.mouseClick(toParentButton, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path()
+ self.assertSamePath(url.text(), path)
+
+ self.mouseClick(toParentButton, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ self.assertSamePath(url.text(), _tmpDirectory)
+
+ self.mouseClick(toParentButton, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ self.assertSamePath(url.text(), os.path.dirname(_tmpDirectory))
+
+ def testClickOnBackToRootTool(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ url = utils.findChildren(dialog, qt.QLineEdit, name="url")[0]
+ action = utils.findChildren(dialog, qt.QAction, name="toRootFileAction")[0]
+ button = utils.getQToolButtonFromAction(action)
+ filename = _tmpDirectory + "/data.h5"
+
+ # init state
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path()
+ dialog.selectUrl(path)
+ self.qWaitForPendingActions(dialog)
+ self.assertSamePath(url.text(), path)
+ self.assertTrue(button.isEnabled())
+ # test
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path()
+ self.assertSamePath(url.text(), path)
+ # self.assertFalse(button.isEnabled())
+
+ def testClickOnBackToDirectoryTool(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ url = utils.findChildren(dialog, qt.QLineEdit, name="url")[0]
+ action = utils.findChildren(dialog, qt.QAction, name="toDirectoryAction")[0]
+ button = utils.getQToolButtonFromAction(action)
+ filename = _tmpDirectory + "/data.h5"
+
+ # init state
+ path = silx.io.url.DataUrl(file_path=filename, data_path="/group/image").path()
+ dialog.selectUrl(path)
+ self.qWaitForPendingActions(dialog)
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path()
+ self.assertSamePath(url.text(), path)
+ self.assertTrue(button.isEnabled())
+ # test
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ self.assertSamePath(url.text(), _tmpDirectory)
+ self.assertFalse(button.isEnabled())
+
+ # FIXME: There is an unreleased qt.QWidget without nameObject
+ # No idea where it come from.
+ self.allowedLeakingWidgets = 1
+
+ def testClickOnHistoryTools(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ url = utils.findChildren(dialog, qt.QLineEdit, name="url")[0]
+ forwardAction = utils.findChildren(dialog, qt.QAction, name="forwardAction")[0]
+ backwardAction = utils.findChildren(dialog, qt.QAction, name="backwardAction")[0]
+ filename = _tmpDirectory + "/data.h5"
+
+ dialog.setDirectory(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ # No way to use QTest.mouseDClick with QListView, QListWidget
+ # Then we feed the history using selectPath
+ dialog.selectUrl(filename)
+ self.qWaitForPendingActions(dialog)
+ path2 = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path()
+ dialog.selectUrl(path2)
+ self.qWaitForPendingActions(dialog)
+ path3 = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group").path()
+ dialog.selectUrl(path3)
+ self.qWaitForPendingActions(dialog)
+ self.assertFalse(forwardAction.isEnabled())
+ self.assertTrue(backwardAction.isEnabled())
+
+ button = utils.getQToolButtonFromAction(backwardAction)
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ self.assertTrue(forwardAction.isEnabled())
+ self.assertTrue(backwardAction.isEnabled())
+ self.assertSamePath(url.text(), path2)
+
+ button = utils.getQToolButtonFromAction(forwardAction)
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ self.assertFalse(forwardAction.isEnabled())
+ self.assertTrue(backwardAction.isEnabled())
+ self.assertSamePath(url.text(), path3)
+
+ def testSelectImageFromEdf(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ filename = _tmpDirectory + "/singleimage.edf"
+ url = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/scan_0/instrument/detector_0/data")
+ dialog.selectUrl(url.path())
+ self.assertTrue(dialog._selectedData().shape, (100, 100))
+ self.assertSamePath(dialog.selectedFile(), filename)
+ self.assertSamePath(dialog.selectedUrl(), url.path())
+
+ def testSelectImage(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ filename = _tmpDirectory + "/data.h5"
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/image").path()
+ dialog.selectUrl(path)
+ # test
+ self.assertTrue(dialog._selectedData().shape, (100, 100))
+ self.assertSamePath(dialog.selectedFile(), filename)
+ self.assertSamePath(dialog.selectedUrl(), path)
+
+ def testSelectScalar(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ filename = _tmpDirectory + "/data.h5"
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/scalar").path()
+ dialog.selectUrl(path)
+ # test
+ self.assertEqual(dialog._selectedData()[()], 10)
+ self.assertSamePath(dialog.selectedFile(), filename)
+ self.assertSamePath(dialog.selectedUrl(), path)
+
+ def testSelectGroup(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ filename = _tmpDirectory + "/data.h5"
+ uri = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group")
+ dialog.selectUrl(uri.path())
+ self.qWaitForPendingActions(dialog)
+ # test
+ self.assertTrue(silx.io.is_group(dialog._selectedData()))
+ self.assertSamePath(dialog.selectedFile(), filename)
+ uri = silx.io.url.DataUrl(dialog.selectedUrl())
+ self.assertSamePath(uri.data_path(), "/group")
+
+ def testSelectRoot(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ filename = _tmpDirectory + "/data.h5"
+ uri = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/")
+ dialog.selectUrl(uri.path())
+ self.qWaitForPendingActions(dialog)
+ # test
+ self.assertTrue(silx.io.is_file(dialog._selectedData()))
+ self.assertSamePath(dialog.selectedFile(), filename)
+ uri = silx.io.url.DataUrl(dialog.selectedUrl())
+ self.assertSamePath(uri.data_path(), "/")
+
+ def testSelectH5_Activate(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ dialog.selectUrl(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ filename = _tmpDirectory + "/data.h5"
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path()
+ index = browser.rootIndex().model().index(filename)
+ # click
+ browser.selectIndex(index)
+ # double click
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+ # test
+ self.assertSamePath(dialog.selectedUrl(), path)
+
+ def testSelectBadFileFormat_Activate(self):
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ dialog.selectUrl(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ filename = _tmpDirectory + "/badformat.h5"
+ index = browser.rootIndex().model().index(filename)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+ # test
+ self.assertTrue(dialog.selectedUrl(), filename)
+
+ def _countSelectableItems(self, model, rootIndex):
+ selectable = 0
+ for i in range(model.rowCount(rootIndex)):
+ index = model.index(i, 0, rootIndex)
+ flags = model.flags(index)
+ isEnabled = (int(flags) & qt.Qt.ItemIsEnabled) != 0
+ if isEnabled:
+ selectable += 1
+ return selectable
+
+ def testFilterExtensions(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ dialog.selectUrl(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ self.assertEqual(self._countSelectableItems(browser.model(), browser.rootIndex()), 3)
+
+
+class TestDataFileDialog_FilterDataset(utils.TestCaseQt, _UtilsMixin):
+
+ def tearDown(self):
+ self._deleteDialog()
+ utils.TestCaseQt.tearDown(self)
+
+ def _createDialog(self):
+ dialog = DataFileDialog()
+ dialog.setFilterMode(DataFileDialog.FilterMode.ExistingDataset)
+ return dialog
+
+ def testSelectGroup_Activate(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+ filename = _tmpDirectory + "/data.h5"
+ dialog.selectFile(os.path.dirname(filename))
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().index(filename)
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"])
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.assertFalse(button.isEnabled())
+
+ def testSelectDataset_Activate(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+ filename = _tmpDirectory + "/data.h5"
+ dialog.selectFile(os.path.dirname(filename))
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().index(filename)
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"])
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.assertTrue(button.isEnabled())
+ self.mouseClick(button, qt.Qt.LeftButton)
+ url = silx.io.url.DataUrl(dialog.selectedUrl())
+ self.assertEqual(url.data_path(), "/scalar")
+ self.assertFalse(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Accepted)
+
+ data = dialog.selectedData()
+ self.assertEqual(data, 10)
+
+
+class TestDataFileDialog_FilterGroup(utils.TestCaseQt, _UtilsMixin):
+
+ def tearDown(self):
+ self._deleteDialog()
+ utils.TestCaseQt.tearDown(self)
+
+ def _createDialog(self):
+ dialog = DataFileDialog()
+ dialog.setFilterMode(DataFileDialog.FilterMode.ExistingGroup)
+ return dialog
+
+ def testSelectGroup_Activate(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+ filename = _tmpDirectory + "/data.h5"
+ dialog.selectFile(os.path.dirname(filename))
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().index(filename)
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"])
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.assertTrue(button.isEnabled())
+ self.mouseClick(button, qt.Qt.LeftButton)
+ url = silx.io.url.DataUrl(dialog.selectedUrl())
+ self.assertEqual(url.data_path(), "/group")
+ self.assertFalse(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Accepted)
+
+ self.assertRaises(Exception, dialog.selectedData)
+
+ def testSelectDataset_Activate(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+ filename = _tmpDirectory + "/data.h5"
+ dialog.selectFile(os.path.dirname(filename))
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().index(filename)
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"])
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.assertFalse(button.isEnabled())
+
+
+class TestDataFileDialog_FilterNXdata(utils.TestCaseQt, _UtilsMixin):
+
+ def tearDown(self):
+ self._deleteDialog()
+ utils.TestCaseQt.tearDown(self)
+
+ def _createDialog(self):
+ def customFilter(obj):
+ if "NX_class" in obj.attrs:
+ return obj.attrs["NX_class"] == u"NXdata"
+ return False
+
+ dialog = DataFileDialog()
+ dialog.setFilterMode(DataFileDialog.FilterMode.ExistingGroup)
+ dialog.setFilterCallback(customFilter)
+ return dialog
+
+ def testSelectGroupRefused_Activate(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+ filename = _tmpDirectory + "/data.h5"
+ dialog.selectFile(os.path.dirname(filename))
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().index(filename)
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"])
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.assertFalse(button.isEnabled())
+
+ self.assertRaises(Exception, dialog.selectedData)
+
+ def testSelectNXdataAccepted_Activate(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+ filename = _tmpDirectory + "/data.h5"
+ dialog.selectFile(os.path.dirname(filename))
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().index(filename)
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ # select, then double click on the file
+ index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/nxdata"])
+ browser.selectIndex(index)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.assertTrue(button.isEnabled())
+ self.mouseClick(button, qt.Qt.LeftButton)
+ url = silx.io.url.DataUrl(dialog.selectedUrl())
+ self.assertEqual(url.data_path(), "/nxdata")
+ self.assertFalse(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Accepted)
+
+
+class TestDataFileDialogApi(utils.TestCaseQt, _UtilsMixin):
+
+ def tearDown(self):
+ self._deleteDialog()
+ utils.TestCaseQt.tearDown(self)
+
+ def _createDialog(self):
+ dialog = DataFileDialog()
+ return dialog
+
+ def testSaveRestoreState(self):
+ dialog = self.createDialog()
+ dialog.setDirectory(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ state = dialog.saveState()
+ dialog = None
+
+ dialog2 = self.createDialog()
+ result = dialog2.restoreState(state)
+ self.assertTrue(result)
+ dialog2 = None
+
+ def printState(self):
+ """
+ Print state of the ImageFileDialog.
+
+ Can be used to add or regenerate `STATE_VERSION1_QT4` or
+ `STATE_VERSION1_QT5`.
+
+ >>> ./run_tests.py -v silx.gui.dialog.test.test_datafiledialog.TestDataFileDialogApi.printState
+ """
+ dialog = self.createDialog()
+ dialog.setDirectory("")
+ dialog.setHistory([])
+ dialog.setSidebarUrls([])
+ state = dialog.saveState()
+ string = ""
+ strings = []
+ for i in range(state.size()):
+ d = state.data()[i]
+ if not isinstance(d, int):
+ d = ord(d)
+ if d > 0x20 and d < 0x7F:
+ string += chr(d)
+ else:
+ string += "\\x%02X" % d
+ if len(string) > 60:
+ strings.append(string)
+ string = ""
+ strings.append(string)
+ strings = ["b'%s'" % s for s in strings]
+ print()
+ print("\\\n".join(strings))
+
+ STATE_VERSION1_QT4 = b''\
+ b'\x00\x00\x00Z\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00'\
+ b'd\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00a\x00F\x00i'\
+ b'\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00'\
+ b'a\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00\x00\x00'\
+ b'\x01\x00\x00\x00\x0C\x00\x00\x00\x00"\x00\x00\x00\xFF\x00\x00'\
+ b'\x00\x00\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'\
+ b'\xFF\xFF\x01\x00\x00\x00\x06\x01\x00\x00\x00\x01\x00\x00\x00\x00'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x00\x00\x00'\
+ b'}\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s\x00e\x00r\x00\x00\x00'\
+ b'\x01\x00\x00\x00\x0C\x00\x00\x00\x00Z\x00\x00\x00\xFF\x00\x00'\
+ b'\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
+ b'\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00\x00\x00\x00\x00\x00\x00'\
+ b'\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF\xFF\xFF\x00\x00\x00\x81'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x01\x90\x00\x00\x00\x04'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00'\
+ b'\x01\xFF\xFF\xFF\xFF'
+ """Serialized state on Qt4. Generated using :meth:`printState`"""
+
+ STATE_VERSION1_QT5 = b''\
+ b'\x00\x00\x00Z\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00'\
+ b'd\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00a\x00F\x00i'\
+ b'\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00'\
+ b'a\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00\x00\x00'\
+ b'\x01\x00\x00\x00\x0C\x00\x00\x00\x00#\x00\x00\x00\xFF\x00\x00'\
+ b'\x00\x01\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'\
+ b'\xFF\xFF\x01\xFF\xFF\xFF\xFF\x01\x00\x00\x00\x01\x00\x00\x00\x00'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x00\x00'\
+ b'\x00\xAA\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s\x00e\x00r\x00'\
+ b'\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00\x87\x00\x00\x00\xFF'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00'\
+ b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
+ b'\x00\x00\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00\x00\x00\x00\x00'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF\xFF\xFF\x00\x00'\
+ b'\x00\x81\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00d\x00\x00'\
+ b'\x00\x01\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00'\
+ b'\x00\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00'\
+ b'\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03\xE8\x00\xFF'\
+ b'\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x01'
+ """Serialized state on Qt5. Generated using :meth:`printState`"""
+
+ def testAvoidRestoreRegression_Version1(self):
+ version = qt.qVersion().split(".")[0]
+ if version == "4":
+ state = self.STATE_VERSION1_QT4
+ elif version == "5":
+ state = self.STATE_VERSION1_QT5
+ else:
+ self.skipTest("Resource not available")
+
+ state = qt.QByteArray(state)
+ dialog = self.createDialog()
+ result = dialog.restoreState(state)
+ self.assertTrue(result)
+
+ def testRestoreRobusness(self):
+ """What's happen if you try to open a config file with a different
+ binding."""
+ state = qt.QByteArray(self.STATE_VERSION1_QT4)
+ dialog = self.createDialog()
+ dialog.restoreState(state)
+ state = qt.QByteArray(self.STATE_VERSION1_QT5)
+ dialog = None
+ dialog = self.createDialog()
+ dialog.restoreState(state)
+
+ def testRestoreNonExistingDirectory(self):
+ directory = os.path.join(_tmpDirectory, "dir")
+ os.mkdir(directory)
+ dialog = self.createDialog()
+ dialog.setDirectory(directory)
+ self.qWaitForPendingActions(dialog)
+ state = dialog.saveState()
+ os.rmdir(directory)
+ dialog = None
+
+ dialog2 = self.createDialog()
+ result = dialog2.restoreState(state)
+ self.assertTrue(result)
+ self.assertNotEquals(dialog2.directory(), directory)
+
+ def testHistory(self):
+ dialog = self.createDialog()
+ history = dialog.history()
+ dialog.setHistory([])
+ self.assertEqual(dialog.history(), [])
+ dialog.setHistory(history)
+ self.assertEqual(dialog.history(), history)
+
+ def testSidebarUrls(self):
+ dialog = self.createDialog()
+ urls = dialog.sidebarUrls()
+ dialog.setSidebarUrls([])
+ self.assertEqual(dialog.sidebarUrls(), [])
+ dialog.setSidebarUrls(urls)
+ self.assertEqual(dialog.sidebarUrls(), urls)
+
+ def testDirectory(self):
+ dialog = self.createDialog()
+ self.qWaitForPendingActions(dialog)
+ dialog.selectUrl(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ self.assertSamePath(dialog.directory(), _tmpDirectory)
+
+ def testBadFileFormat(self):
+ dialog = self.createDialog()
+ dialog.selectUrl(_tmpDirectory + "/badformat.h5")
+ self.qWaitForPendingActions(dialog)
+ self.assertIsNone(dialog._selectedData())
+
+ def testBadPath(self):
+ dialog = self.createDialog()
+ dialog.selectUrl("#$%/#$%")
+ self.qWaitForPendingActions(dialog)
+ self.assertIsNone(dialog._selectedData())
+
+ def testBadSubpath(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ self.qWaitForPendingActions(dialog)
+
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+
+ filename = _tmpDirectory + "/data.h5"
+ url = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/foobar")
+ dialog.selectUrl(url.path())
+ self.qWaitForPendingActions(dialog)
+ self.assertIsNotNone(dialog._selectedData())
+
+ # an existing node is browsed, but the wrong path is selected
+ index = browser.rootIndex()
+ obj = index.model().data(index, role=Hdf5TreeModel.H5PY_OBJECT_ROLE)
+ self.assertEqual(obj.name, "/group")
+ url = silx.io.url.DataUrl(dialog.selectedUrl())
+ self.assertEqual(url.data_path(), "/group")
+
+ def testUnsupportedSlicingPath(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ self.qWaitForPendingActions(dialog)
+ dialog.selectUrl(_tmpDirectory + "/data.h5?path=/cube&slice=0")
+ self.qWaitForPendingActions(dialog)
+ data = dialog._selectedData()
+ if data is None:
+ # Maybe nothing is selected
+ self.assertTrue(True)
+ else:
+ # Maybe the cube is selected but not sliced
+ self.assertEqual(len(data.shape), 3)
+
+
+def suite():
+ test_suite = unittest.TestSuite()
+ loadTests = unittest.defaultTestLoader.loadTestsFromTestCase
+ test_suite.addTest(loadTests(TestDataFileDialogInteraction))
+ test_suite.addTest(loadTests(TestDataFileDialogApi))
+ test_suite.addTest(loadTests(TestDataFileDialog_FilterDataset))
+ test_suite.addTest(loadTests(TestDataFileDialog_FilterGroup))
+ test_suite.addTest(loadTests(TestDataFileDialog_FilterNXdata))
+ return test_suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
diff --git a/silx/gui/dialog/test/test_imagefiledialog.py b/silx/gui/dialog/test/test_imagefiledialog.py
new file mode 100644
index 0000000..7909f10
--- /dev/null
+++ b/silx/gui/dialog/test/test_imagefiledialog.py
@@ -0,0 +1,803 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Test for silx.gui.hdf5 module"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "12/02/2018"
+
+
+import unittest
+import tempfile
+import numpy
+import shutil
+import os
+import io
+import weakref
+
+try:
+ import fabio
+except ImportError:
+ fabio = None
+try:
+ import h5py
+except ImportError:
+ h5py = None
+
+import silx.io.url
+from silx.gui import qt
+from silx.gui.test import utils
+from ..ImageFileDialog import ImageFileDialog
+from silx.gui.plot.Colormap import Colormap
+from silx.gui.hdf5 import Hdf5TreeModel
+
+_tmpDirectory = None
+
+
+def setUpModule():
+ global _tmpDirectory
+ _tmpDirectory = tempfile.mkdtemp(prefix=__name__)
+
+ data = numpy.arange(100 * 100)
+ data.shape = 100, 100
+
+ if fabio is not None:
+ filename = _tmpDirectory + "/singleimage.edf"
+ image = fabio.edfimage.EdfImage(data=data)
+ image.write(filename)
+
+ filename = _tmpDirectory + "/multiframe.edf"
+ image = fabio.edfimage.EdfImage(data=data)
+ image.appendFrame(data=data + 1)
+ image.appendFrame(data=data + 2)
+ image.write(filename)
+
+ filename = _tmpDirectory + "/singleimage.msk"
+ image = fabio.fit2dmaskimage.Fit2dMaskImage(data=data % 2 == 1)
+ image.write(filename)
+
+ if h5py is not None:
+ filename = _tmpDirectory + "/data.h5"
+ f = h5py.File(filename, "w")
+ f["scalar"] = 10
+ f["image"] = data
+ f["cube"] = [data, data + 1, data + 2]
+ f["complex_image"] = data * 1j
+ f["group/image"] = data
+ f.close()
+
+ filename = _tmpDirectory + "/badformat.edf"
+ with io.open(filename, "wb") as f:
+ f.write(b"{\nHello Nurse!")
+
+
+def tearDownModule():
+ global _tmpDirectory
+ shutil.rmtree(_tmpDirectory)
+ _tmpDirectory = None
+
+
+class _UtilsMixin(object):
+
+ def createDialog(self):
+ self._deleteDialog()
+ self._dialog = self._createDialog()
+ return self._dialog
+
+ def _createDialog(self):
+ return ImageFileDialog()
+
+ def _deleteDialog(self):
+ if not hasattr(self, "_dialog"):
+ return
+ if self._dialog is not None:
+ ref = weakref.ref(self._dialog)
+ self._dialog = None
+ self.qWaitForDestroy(ref)
+
+ def qWaitForPendingActions(self, dialog):
+ for _ in range(20):
+ if not dialog.hasPendingEvents():
+ return
+ self.qWait(10)
+ raise RuntimeError("Still have pending actions")
+
+ def assertSamePath(self, path1, path2):
+ path1_ = os.path.normcase(path1)
+ path2_ = os.path.normcase(path2)
+ if path1_ != path2_:
+ # Use the unittest API to log and display error
+ self.assertEquals(path1, path2)
+
+ def assertNotSamePath(self, path1, path2):
+ path1_ = os.path.normcase(path1)
+ path2_ = os.path.normcase(path2)
+ if path1_ == path2_:
+ # Use the unittest API to log and display error
+ self.assertNotEquals(path1, path2)
+
+
+class TestImageFileDialogInteraction(utils.TestCaseQt, _UtilsMixin):
+
+ def tearDown(self):
+ self._deleteDialog()
+ utils.TestCaseQt.tearDown(self)
+
+ def testDisplayAndKeyEscape(self):
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+
+ self.keyClick(dialog, qt.Qt.Key_Escape)
+ self.assertFalse(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Rejected)
+
+ def testDisplayAndClickCancel(self):
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="cancel")[0]
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.assertFalse(dialog.isVisible())
+ self.assertFalse(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Rejected)
+
+ def testDisplayAndClickLockedOpen(self):
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.mouseClick(button, qt.Qt.LeftButton)
+ # open button locked, dialog is not closed
+ self.assertTrue(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Rejected)
+
+ def testDisplayAndClickOpen(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ self.assertTrue(dialog.isVisible())
+ filename = _tmpDirectory + "/singleimage.edf"
+ dialog.selectFile(filename)
+ self.qWaitForPendingActions(dialog)
+
+ button = utils.findChildren(dialog, qt.QPushButton, name="open")[0]
+ self.assertTrue(button.isEnabled())
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.assertFalse(dialog.isVisible())
+ self.assertEquals(dialog.result(), qt.QDialog.Accepted)
+
+ def testClickOnShortcut(self):
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ sidebar = utils.findChildren(dialog, qt.QListView, name="sidebar")[0]
+ url = utils.findChildren(dialog, qt.QLineEdit, name="url")[0]
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ dialog.setDirectory(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+
+ self.assertSamePath(url.text(), _tmpDirectory)
+
+ urls = sidebar.urls()
+ if len(urls) == 0:
+ self.skipTest("No sidebar path")
+ path = urls[0].path()
+ if path != "" and not os.path.exists(path):
+ self.skipTest("Sidebar path do not exists")
+
+ index = sidebar.model().index(0, 0)
+ # rect = sidebar.visualRect(index)
+ # self.mouseClick(sidebar, qt.Qt.LeftButton, pos=rect.center())
+ # Using mouse click is not working, let's use the selection API
+ sidebar.selectionModel().select(index, qt.QItemSelectionModel.ClearAndSelect)
+ self.qWaitForPendingActions(dialog)
+
+ index = browser.rootIndex()
+ if not index.isValid():
+ path = ""
+ else:
+ path = index.model().filePath(index)
+ self.assertNotSamePath(_tmpDirectory, path)
+ self.assertNotSamePath(url.text(), _tmpDirectory)
+
+ def testClickOnDetailView(self):
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ action = utils.findChildren(dialog, qt.QAction, name="detailModeAction")[0]
+ detailModeButton = utils.getQToolButtonFromAction(action)
+ self.mouseClick(detailModeButton, qt.Qt.LeftButton)
+ self.assertEqual(dialog.viewMode(), qt.QFileDialog.Detail)
+
+ action = utils.findChildren(dialog, qt.QAction, name="listModeAction")[0]
+ listModeButton = utils.getQToolButtonFromAction(action)
+ self.mouseClick(listModeButton, qt.Qt.LeftButton)
+ self.assertEqual(dialog.viewMode(), qt.QFileDialog.List)
+
+ def testClickOnBackToParentTool(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ url = utils.findChildren(dialog, qt.QLineEdit, name="url")[0]
+ action = utils.findChildren(dialog, qt.QAction, name="toParentAction")[0]
+ toParentButton = utils.getQToolButtonFromAction(action)
+ filename = _tmpDirectory + "/data.h5"
+
+ # init state
+ path = silx.io.url.DataUrl(file_path=filename, data_path="/group/image").path()
+ dialog.selectUrl(path)
+ self.qWaitForPendingActions(dialog)
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path()
+ self.assertSamePath(url.text(), path)
+ # test
+ self.mouseClick(toParentButton, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path()
+ self.assertSamePath(url.text(), path)
+
+ self.mouseClick(toParentButton, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ self.assertSamePath(url.text(), _tmpDirectory)
+
+ self.mouseClick(toParentButton, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ self.assertSamePath(url.text(), os.path.dirname(_tmpDirectory))
+
+ def testClickOnBackToRootTool(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ url = utils.findChildren(dialog, qt.QLineEdit, name="url")[0]
+ action = utils.findChildren(dialog, qt.QAction, name="toRootFileAction")[0]
+ button = utils.getQToolButtonFromAction(action)
+ filename = _tmpDirectory + "/data.h5"
+
+ # init state
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path()
+ dialog.selectUrl(path)
+ self.qWaitForPendingActions(dialog)
+ self.assertSamePath(url.text(), path)
+ self.assertTrue(button.isEnabled())
+ # test
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path()
+ self.assertSamePath(url.text(), path)
+ # self.assertFalse(button.isEnabled())
+
+ def testClickOnBackToDirectoryTool(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ url = utils.findChildren(dialog, qt.QLineEdit, name="url")[0]
+ action = utils.findChildren(dialog, qt.QAction, name="toDirectoryAction")[0]
+ button = utils.getQToolButtonFromAction(action)
+ filename = _tmpDirectory + "/data.h5"
+
+ # init state
+ path = silx.io.url.DataUrl(file_path=filename, data_path="/group/image").path()
+ dialog.selectUrl(path)
+ self.qWaitForPendingActions(dialog)
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path()
+ self.assertSamePath(url.text(), path)
+ self.assertTrue(button.isEnabled())
+ # test
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ self.assertSamePath(url.text(), _tmpDirectory)
+ self.assertFalse(button.isEnabled())
+
+ # FIXME: There is an unreleased qt.QWidget without nameObject
+ # No idea where it come from.
+ self.allowedLeakingWidgets = 1
+
+ def testClickOnHistoryTools(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ url = utils.findChildren(dialog, qt.QLineEdit, name="url")[0]
+ forwardAction = utils.findChildren(dialog, qt.QAction, name="forwardAction")[0]
+ backwardAction = utils.findChildren(dialog, qt.QAction, name="backwardAction")[0]
+ filename = _tmpDirectory + "/data.h5"
+
+ dialog.setDirectory(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ # No way to use QTest.mouseDClick with QListView, QListWidget
+ # Then we feed the history using selectPath
+ dialog.selectUrl(filename)
+ self.qWaitForPendingActions(dialog)
+ path2 = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path()
+ dialog.selectUrl(path2)
+ self.qWaitForPendingActions(dialog)
+ path3 = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group").path()
+ dialog.selectUrl(path3)
+ self.qWaitForPendingActions(dialog)
+ self.assertFalse(forwardAction.isEnabled())
+ self.assertTrue(backwardAction.isEnabled())
+
+ button = utils.getQToolButtonFromAction(backwardAction)
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ self.assertTrue(forwardAction.isEnabled())
+ self.assertTrue(backwardAction.isEnabled())
+ self.assertSamePath(url.text(), path2)
+
+ button = utils.getQToolButtonFromAction(forwardAction)
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.qWaitForPendingActions(dialog)
+ self.assertFalse(forwardAction.isEnabled())
+ self.assertTrue(backwardAction.isEnabled())
+ self.assertSamePath(url.text(), path3)
+
+ def testSelectImageFromEdf(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ filename = _tmpDirectory + "/singleimage.edf"
+ path = filename
+ dialog.selectUrl(path)
+ self.assertTrue(dialog.selectedImage().shape, (100, 100))
+ self.assertSamePath(dialog.selectedFile(), filename)
+ path = silx.io.url.DataUrl(scheme="fabio", file_path=filename).path()
+ self.assertSamePath(dialog.selectedUrl(), path)
+
+ def testSelectImageFromEdf_Activate(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ dialog.selectUrl(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ filename = _tmpDirectory + "/singleimage.edf"
+ path = silx.io.url.DataUrl(scheme="fabio", file_path=filename).path()
+ index = browser.rootIndex().model().index(filename)
+ # click
+ browser.selectIndex(index)
+ # double click
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+ # test
+ self.assertTrue(dialog.selectedImage().shape, (100, 100))
+ self.assertSamePath(dialog.selectedFile(), filename)
+ self.assertSamePath(dialog.selectedUrl(), path)
+
+ def testSelectFrameFromEdf(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ filename = _tmpDirectory + "/multiframe.edf"
+ path = silx.io.url.DataUrl(scheme="fabio", file_path=filename, data_slice=(1,)).path()
+ dialog.selectUrl(path)
+ # test
+ image = dialog.selectedImage()
+ self.assertTrue(image.shape, (100, 100))
+ self.assertTrue(image[0, 0], 1)
+ self.assertSamePath(dialog.selectedFile(), filename)
+ self.assertSamePath(dialog.selectedUrl(), path)
+
+ def testSelectImageFromMsk(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ filename = _tmpDirectory + "/singleimage.msk"
+ path = silx.io.url.DataUrl(scheme="fabio", file_path=filename).path()
+ dialog.selectUrl(path)
+ # test
+ self.assertTrue(dialog.selectedImage().shape, (100, 100))
+ self.assertSamePath(dialog.selectedFile(), filename)
+ self.assertSamePath(dialog.selectedUrl(), path)
+
+ def testSelectImageFromH5(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ filename = _tmpDirectory + "/data.h5"
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/image").path()
+ dialog.selectUrl(path)
+ # test
+ self.assertTrue(dialog.selectedImage().shape, (100, 100))
+ self.assertSamePath(dialog.selectedFile(), filename)
+ self.assertSamePath(dialog.selectedUrl(), path)
+
+ def testSelectH5_Activate(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ dialog.selectUrl(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ filename = _tmpDirectory + "/data.h5"
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path()
+ index = browser.rootIndex().model().index(filename)
+ # click
+ browser.selectIndex(index)
+ # double click
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+ # test
+ self.assertSamePath(dialog.selectedUrl(), path)
+
+ def testSelectFrameFromH5(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ filename = _tmpDirectory + "/data.h5"
+ path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/cube", data_slice=(1, )).path()
+ dialog.selectUrl(path)
+ # test
+ self.assertTrue(dialog.selectedImage().shape, (100, 100))
+ self.assertTrue(dialog.selectedImage()[0, 0], 1)
+ self.assertSamePath(dialog.selectedFile(), filename)
+ self.assertSamePath(dialog.selectedUrl(), path)
+
+ def testSelectBadFileFormat_Activate(self):
+ dialog = self.createDialog()
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+
+ # init state
+ dialog.selectUrl(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ filename = _tmpDirectory + "/badformat.edf"
+ index = browser.rootIndex().model().index(filename)
+ browser.activated.emit(index)
+ self.qWaitForPendingActions(dialog)
+ # test
+ self.assertTrue(dialog.selectedUrl(), filename)
+
+ def _countSelectableItems(self, model, rootIndex):
+ selectable = 0
+ for i in range(model.rowCount(rootIndex)):
+ index = model.index(i, 0, rootIndex)
+ flags = model.flags(index)
+ isEnabled = (int(flags) & qt.Qt.ItemIsEnabled) != 0
+ if isEnabled:
+ selectable += 1
+ return selectable
+
+ def testFilterExtensions(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ dialog = self.createDialog()
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+ filters = utils.findChildren(dialog, qt.QWidget, name="fileTypeCombo")[0]
+ dialog.show()
+ self.qWaitForWindowExposed(dialog)
+ dialog.selectUrl(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ self.assertEqual(self._countSelectableItems(browser.model(), browser.rootIndex()), 5)
+
+ codecName = fabio.edfimage.EdfImage.codec_name()
+ index = filters.indexFromCodec(codecName)
+ filters.setCurrentIndex(index)
+ filters.activated[int].emit(index)
+ self.qWait(50)
+ self.assertEqual(self._countSelectableItems(browser.model(), browser.rootIndex()), 3)
+
+ codecName = fabio.fit2dmaskimage.Fit2dMaskImage.codec_name()
+ index = filters.indexFromCodec(codecName)
+ filters.setCurrentIndex(index)
+ filters.activated[int].emit(index)
+ self.qWait(50)
+ self.assertEqual(self._countSelectableItems(browser.model(), browser.rootIndex()), 1)
+
+
+class TestImageFileDialogApi(utils.TestCaseQt, _UtilsMixin):
+
+ def tearDown(self):
+ self._deleteDialog()
+ utils.TestCaseQt.tearDown(self)
+
+ def testSaveRestoreState(self):
+ dialog = self.createDialog()
+ dialog.setDirectory(_tmpDirectory)
+ colormap = Colormap(normalization=Colormap.LOGARITHM)
+ dialog.setColormap(colormap)
+ self.qWaitForPendingActions(dialog)
+ state = dialog.saveState()
+ dialog = None
+
+ dialog2 = self.createDialog()
+ result = dialog2.restoreState(state)
+ self.qWaitForPendingActions(dialog2)
+ self.assertTrue(result)
+ self.assertTrue(dialog2.colormap().getNormalization(), "log")
+
+ def printState(self):
+ """
+ Print state of the ImageFileDialog.
+
+ Can be used to add or regenerate `STATE_VERSION1_QT4` or
+ `STATE_VERSION1_QT5`.
+
+ >>> ./run_tests.py -v silx.gui.dialog.test.test_imagefiledialog.TestImageFileDialogApi.printState
+ """
+ dialog = self.createDialog()
+ colormap = Colormap(normalization=Colormap.LOGARITHM)
+ dialog.setDirectory("")
+ dialog.setHistory([])
+ dialog.setColormap(colormap)
+ dialog.setSidebarUrls([])
+ state = dialog.saveState()
+ string = ""
+ strings = []
+ for i in range(state.size()):
+ d = state.data()[i]
+ if not isinstance(d, int):
+ d = ord(d)
+ if d > 0x20 and d < 0x7F:
+ string += chr(d)
+ else:
+ string += "\\x%02X" % d
+ if len(string) > 60:
+ strings.append(string)
+ string = ""
+ strings.append(string)
+ strings = ["b'%s'" % s for s in strings]
+ print()
+ print("\\\n".join(strings))
+
+ STATE_VERSION1_QT4 = b''\
+ b'\x00\x00\x00^\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00'\
+ b'd\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00a\x00g\x00e\x00F'\
+ b'\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00'\
+ b'a\x00g\x00e\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g'\
+ b'\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00"\x00\x00\x00'\
+ b'\xFF\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF'\
+ b'\xFF\xFF\xFF\xFF\xFF\x01\x00\x00\x00\x06\x01\x00\x00\x00\x01\x00'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00'\
+ b'\x00\x00\x00}\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s\x00e\x00'\
+ b'r\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00Z\x00\x00\x00'\
+ b'\xFF\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00'\
+ b'\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
+ b'\x00\x00\x00\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00\x00\x00\x00'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF\xFF\xFF\x00'\
+ b'\x00\x00\x81\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x01\x90\x00'\
+ b'\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00'\
+ b'\x00\x00\x0C\x00\x00\x00\x000\x00\x00\x00\x10\x00C\x00o\x00l\x00'\
+ b'o\x00r\x00m\x00a\x00p\x00\x00\x00\x01\x00\x00\x00\x08\x00g\x00'\
+ b'r\x00a\x00y\x01\x01\x00\x00\x00\x06\x00l\x00o\x00g'
+ """Serialized state on Qt4. Generated using :meth:`printState`"""
+
+ STATE_VERSION1_QT5 = b''\
+ b'\x00\x00\x00^\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00'\
+ b'd\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00a\x00g\x00e\x00F'\
+ b'\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00'\
+ b'a\x00g\x00e\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g'\
+ b'\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00#\x00\x00\x00'\
+ b'\xFF\x00\x00\x00\x01\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF'\
+ b'\xFF\xFF\xFF\xFF\xFF\x01\xFF\xFF\xFF\xFF\x01\x00\x00\x00\x01\x00'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C'\
+ b'\x00\x00\x00\x00\xAA\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s'\
+ b'\x00e\x00r\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00\x87'\
+ b'\x00\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00'\
+ b'\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00'\
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF'\
+ b'\xFF\xFF\x00\x00\x00\x81\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00'\
+ b'\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00'\
+ b'\x01\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00\x00'\
+ b'\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03'\
+ b'\xE8\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00'\
+ b'\x00\x0C\x00\x00\x00\x000\x00\x00\x00\x10\x00C\x00o\x00l\x00o'\
+ b'\x00r\x00m\x00a\x00p\x00\x00\x00\x01\x00\x00\x00\x08\x00g\x00'\
+ b'r\x00a\x00y\x01\x01\x00\x00\x00\x06\x00l\x00o\x00g'
+ """Serialized state on Qt5. Generated using :meth:`printState`"""
+
+ def testAvoidRestoreRegression_Version1(self):
+ version = qt.qVersion().split(".")[0]
+ if version == "4":
+ state = self.STATE_VERSION1_QT4
+ elif version == "5":
+ state = self.STATE_VERSION1_QT5
+ else:
+ self.skipTest("Resource not available")
+
+ state = qt.QByteArray(state)
+ dialog = self.createDialog()
+ result = dialog.restoreState(state)
+ self.assertTrue(result)
+ colormap = dialog.colormap()
+ self.assertTrue(colormap.getNormalization(), "log")
+
+ def testRestoreRobusness(self):
+ """What's happen if you try to open a config file with a different
+ binding."""
+ state = qt.QByteArray(self.STATE_VERSION1_QT4)
+ dialog = self.createDialog()
+ dialog.restoreState(state)
+ state = qt.QByteArray(self.STATE_VERSION1_QT5)
+ dialog = None
+ dialog = self.createDialog()
+ dialog.restoreState(state)
+
+ def testRestoreNonExistingDirectory(self):
+ directory = os.path.join(_tmpDirectory, "dir")
+ os.mkdir(directory)
+ dialog = self.createDialog()
+ dialog.setDirectory(directory)
+ self.qWaitForPendingActions(dialog)
+ state = dialog.saveState()
+ os.rmdir(directory)
+ dialog = None
+
+ dialog2 = self.createDialog()
+ result = dialog2.restoreState(state)
+ self.assertTrue(result)
+ self.assertNotEquals(dialog2.directory(), directory)
+
+ def testHistory(self):
+ dialog = self.createDialog()
+ history = dialog.history()
+ dialog.setHistory([])
+ self.assertEqual(dialog.history(), [])
+ dialog.setHistory(history)
+ self.assertEqual(dialog.history(), history)
+
+ def testSidebarUrls(self):
+ dialog = self.createDialog()
+ urls = dialog.sidebarUrls()
+ dialog.setSidebarUrls([])
+ self.assertEqual(dialog.sidebarUrls(), [])
+ dialog.setSidebarUrls(urls)
+ self.assertEqual(dialog.sidebarUrls(), urls)
+
+ def testColomap(self):
+ dialog = self.createDialog()
+ colormap = dialog.colormap()
+ self.assertEqual(colormap.getNormalization(), "linear")
+ colormap = Colormap(normalization=Colormap.LOGARITHM)
+ dialog.setColormap(colormap)
+ self.assertEqual(colormap.getNormalization(), "log")
+
+ def testDirectory(self):
+ dialog = self.createDialog()
+ self.qWaitForPendingActions(dialog)
+ dialog.selectUrl(_tmpDirectory)
+ self.qWaitForPendingActions(dialog)
+ self.assertSamePath(dialog.directory(), _tmpDirectory)
+
+ def testBadDataType(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.selectUrl(_tmpDirectory + "/data.h5::/complex_image")
+ self.qWaitForPendingActions(dialog)
+ self.assertIsNone(dialog._selectedData())
+
+ def testBadDataShape(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ dialog.selectUrl(_tmpDirectory + "/data.h5::/unknown")
+ self.qWaitForPendingActions(dialog)
+ self.assertIsNone(dialog._selectedData())
+
+ def testBadDataFormat(self):
+ dialog = self.createDialog()
+ dialog.selectUrl(_tmpDirectory + "/badformat.edf")
+ self.qWaitForPendingActions(dialog)
+ self.assertIsNone(dialog._selectedData())
+
+ def testBadPath(self):
+ dialog = self.createDialog()
+ dialog.selectUrl("#$%/#$%")
+ self.qWaitForPendingActions(dialog)
+ self.assertIsNone(dialog._selectedData())
+
+ def testBadSubpath(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ self.qWaitForPendingActions(dialog)
+
+ browser = utils.findChildren(dialog, qt.QWidget, name="browser")[0]
+
+ filename = _tmpDirectory + "/data.h5"
+ url = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/foobar")
+ dialog.selectUrl(url.path())
+ self.qWaitForPendingActions(dialog)
+ self.assertIsNone(dialog._selectedData())
+
+ # an existing node is browsed, but the wrong path is selected
+ index = browser.rootIndex()
+ obj = index.model().data(index, role=Hdf5TreeModel.H5PY_OBJECT_ROLE)
+ self.assertEqual(obj.name, "/group")
+ url = silx.io.url.DataUrl(dialog.selectedUrl())
+ self.assertEqual(url.data_path(), "/group")
+
+ def testBadSlicingPath(self):
+ if h5py is None:
+ self.skipTest("h5py is missing")
+ dialog = self.createDialog()
+ self.qWaitForPendingActions(dialog)
+ dialog.selectUrl(_tmpDirectory + "/data.h5::/cube[a;45,-90]")
+ self.qWaitForPendingActions(dialog)
+ self.assertIsNone(dialog._selectedData())
+
+
+def suite():
+ test_suite = unittest.TestSuite()
+ loadTests = unittest.defaultTestLoader.loadTestsFromTestCase
+ test_suite.addTest(loadTests(TestImageFileDialogInteraction))
+ test_suite.addTest(loadTests(TestImageFileDialogApi))
+ return test_suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
diff --git a/silx/gui/dialog/utils.py b/silx/gui/dialog/utils.py
new file mode 100644
index 0000000..1c16b44
--- /dev/null
+++ b/silx/gui/dialog/utils.py
@@ -0,0 +1,104 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This module contains utilitaries used by other dialog modules.
+"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "25/10/2017"
+
+import os
+import sys
+import types
+from silx.gui import qt
+from silx.third_party import six
+
+
+def samefile(path1, path2):
+ """Portable :func:`os.path.samepath` function.
+
+ :param str path1: A path to a file
+ :param str path2: Another path to a file
+ :rtype: bool
+ """
+ if six.PY2 and sys.platform == "win32":
+ path1 = os.path.normcase(path1)
+ path2 = os.path.normcase(path2)
+ return path1 == path2
+ if path1 == path2:
+ return True
+ if path1 == "":
+ return False
+ if path2 == "":
+ return False
+ return os.path.samefile(path1, path2)
+
+
+def findClosestSubPath(hdf5Object, path):
+ """Find the closest existing path from the hdf5Object using a subset of the
+ provided path.
+
+ Returns None if no path found. It is possible if the path is a relative
+ path.
+
+ :param h5py.Node hdf5Object: An HDF5 node
+ :param str path: A path
+ :rtype: str
+ """
+ if path in ["", "/"]:
+ return "/"
+ names = path.split("/")
+ if path[0] == "/":
+ names.pop(0)
+ for i in range(len(names)):
+ n = len(names) - i
+ path2 = "/".join(names[0:n])
+ if path2 == "":
+ return ""
+ if path2 in hdf5Object:
+ return path2
+
+ if path[0] == "/":
+ return "/"
+ return None
+
+
+def patchToConsumeReturnKey(widget):
+ """
+ Monkey-patch a widget to consume the return key instead of propagating it
+ to the dialog.
+ """
+ assert(not hasattr(widget, "_oldKeyPressEvent"))
+
+ def keyPressEvent(self, event):
+ k = event.key()
+ result = self._oldKeyPressEvent(event)
+ if k in [qt.Qt.Key_Return, qt.Qt.Key_Enter]:
+ event.accept()
+ return result
+
+ widget._oldKeyPressEvent = widget.keyPressEvent
+ widget.keyPressEvent = types.MethodType(keyPressEvent, widget)
diff --git a/silx/gui/hdf5/Hdf5Formatter.py b/silx/gui/hdf5/Hdf5Formatter.py
index 3a4c1c1..0e3697f 100644
--- a/silx/gui/hdf5/Hdf5Formatter.py
+++ b/silx/gui/hdf5/Hdf5Formatter.py
@@ -27,7 +27,7 @@ text."""
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "27/09/2017"
+__date__ = "23/01/2018"
import numpy
from silx.third_party import six
@@ -153,7 +153,8 @@ class Hdf5Formatter(qt.QObject):
if not full:
return "compound"
else:
- compound = [d[0] for d in dtype.fields.values()]
+ fields = sorted(dtype.fields.items(), key=lambda e: e[1][1])
+ compound = [d[1][0] for d in fields]
compound = [self.humanReadableDType(d) for d in compound]
return "compound(%s)" % ", ".join(compound)
elif numpy.issubdtype(dtype, numpy.integer):
diff --git a/silx/gui/hdf5/Hdf5Item.py b/silx/gui/hdf5/Hdf5Item.py
index f131f61..9804907 100644
--- a/silx/gui/hdf5/Hdf5Item.py
+++ b/silx/gui/hdf5/Hdf5Item.py
@@ -25,7 +25,7 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "26/09/2017"
+__date__ = "10/10/2017"
import logging
@@ -40,12 +40,6 @@ from ..hdf5.Hdf5Formatter import Hdf5Formatter
_logger = logging.getLogger(__name__)
-try:
- import h5py
-except ImportError as e:
- _logger.error("Module %s requires h5py", __name__)
- raise e
-
_formatter = TextFormatter()
_hdf5Formatter = Hdf5Formatter(textFormatter=_formatter)
# FIXME: The formatter should be an attribute of the Hdf5Model
@@ -57,15 +51,15 @@ class Hdf5Item(Hdf5Node):
tree structure.
"""
- def __init__(self, text, obj, parent, key=None, h5pyClass=None, linkClass=None, populateAll=False):
+ def __init__(self, text, obj, parent, key=None, h5Class=None, linkClass=None, populateAll=False):
"""
:param str text: text displayed
- :param object obj: Pointer to h5py data. See the `obj` attribute.
+ :param object obj: Pointer to a h5py-link object. See the `obj` attribute.
"""
self.__obj = obj
self.__key = key
- self.__h5pyClass = h5pyClass
- self.__isBroken = obj is None and h5pyClass is None
+ self.__h5Class = h5Class
+ self.__isBroken = obj is None and h5Class is None
self.__error = None
self.__text = text
self.__linkClass = linkClass
@@ -74,7 +68,7 @@ class Hdf5Item(Hdf5Node):
@property
def obj(self):
if self.__key:
- self.__initH5pyObject()
+ self.__initH5Object()
return self.__obj
@property
@@ -82,6 +76,20 @@ class Hdf5Item(Hdf5Node):
return self.__text
@property
+ def h5Class(self):
+ """Returns the class of the stored object.
+
+ When the object is in lazy loading, this method should be able to
+ return the type of the futrue loaded object. It allows to delay the
+ real load of the object.
+
+ :rtype: silx.io.utils.H5Type
+ """
+ if self.__h5Class is None and self.obj is not None:
+ self.__h5Class = silx.io.utils.get_h5_class(self.obj)
+ return self.__h5Class
+
+ @property
def h5pyClass(self):
"""Returns the class of the stored object.
@@ -91,15 +99,14 @@ class Hdf5Item(Hdf5Node):
:rtype: h5py.File or h5py.Dataset or h5py.Group
"""
- if self.__h5pyClass is None and self.obj is not None:
- self.__h5pyClass = silx.io.utils.get_h5py_class(self.obj)
- return self.__h5pyClass
+ type_ = self.h5Class
+ return silx.io.utils.h5type_to_h5py_class(type_)
@property
def linkClass(self):
"""Returns the link class object of this node
- :type: h5py.SoftLink or h5py.HardLink or h5py.ExternalLink or None
+ :rtype: H5Type
"""
return self.__linkClass
@@ -109,16 +116,16 @@ class Hdf5Item(Hdf5Node):
:rtype: bool
"""
- if self.h5pyClass is None:
+ if self.h5Class is None:
return False
- return issubclass(self.h5pyClass, h5py.Group)
+ return self.h5Class in [silx.io.utils.H5Type.GROUP, silx.io.utils.H5Type.FILE]
def isBrokenObj(self):
"""Returns true if the stored HDF5 object is broken.
- The stored object is then an h5py link (external or not) which point
- to nowhere (tbhe external file is not here, the expected dataset is
- still not on the file...)
+ The stored object is then an h5py-like link (external or not) which
+ point to nowhere (tbhe external file is not here, the expected
+ dataset is still not on the file...)
:rtype: bool
"""
@@ -137,7 +144,7 @@ class Hdf5Item(Hdf5Node):
return len(self.obj)
return 0
- def __initH5pyObject(self):
+ def __initH5Object(self):
"""Lazy load of the HDF5 node. It is reached from the parent node
with the key of the node."""
parent_obj = self.parent.obj
@@ -145,7 +152,9 @@ class Hdf5Item(Hdf5Node):
try:
obj = parent_obj.get(self.__key)
except Exception as e:
- _logger.debug("Internal h5py error", exc_info=True)
+ lib_name = self.obj.__class__.__module__.split(".")[0]
+ _logger.debug("Internal %s error", lib_name, exc_info=True)
+ _logger.debug("Backtrace", exc_info=True)
try:
self.__obj = parent_obj.get(self.__key, getlink=True)
except Exception:
@@ -168,9 +177,11 @@ class Hdf5Item(Hdf5Node):
if not hasattr(self.__obj, "file"):
self.__obj.file = parent_obj.file
- if isinstance(self.__obj, h5py.ExternalLink):
+ class_ = silx.io.utils.get_h5_class(self.__obj)
+
+ if class_ == silx.io.utils.H5Type.EXTERNAL_LINK:
message = "External link broken. Path %s::%s does not exist" % (self.__obj.filename, self.__obj.path)
- elif isinstance(self.__obj, h5py.SoftLink):
+ elif class_ == silx.io.utils.H5Type.SOFT_LINK:
message = "Soft link broken. Path %s does not exist" % (self.__obj.path)
else:
name = self.obj.__class__.__name__.split(".")[-1].capitalize()
@@ -204,14 +215,25 @@ class Hdf5Item(Hdf5Node):
try:
class_ = self.obj.get(name, getclass=True)
link = self.obj.get(name, getclass=True, getlink=True)
- except Exception as e:
- _logger.warn("Internal h5py error", exc_info=True)
+ link = silx.io.utils.get_h5_class(class_=link)
+ except Exception:
+ lib_name = self.obj.__class__.__module__.split(".")[0]
+ _logger.warning("Internal %s error", lib_name, exc_info=True)
+ _logger.debug("Backtrace", exc_info=True)
class_ = None
try:
link = self.obj.get(name, getclass=True, getlink=True)
- except Exception as e:
- link = h5py.HardLink
- item = Hdf5Item(text=name, obj=None, parent=self, key=name, h5pyClass=class_, linkClass=link)
+ link = silx.io.utils.get_h5_class(class_=link)
+ except Exception:
+ _logger.debug("Backtrace", exc_info=True)
+ link = silx.io.utils.H5Type.HARD_LINK
+
+ h5class = None
+ if class_ is not None:
+ h5class = silx.io.utils.get_h5_class(class_=class_)
+ if h5class is None:
+ _logger.error("Class %s unsupported", class_)
+ item = Hdf5Item(text=name, obj=None, parent=self, key=name, h5Class=h5class, linkClass=link)
self.appendChild(item)
def hasChildren(self):
@@ -234,16 +256,16 @@ class Hdf5Item(Hdf5Node):
if self.__isBroken:
icon = style.standardIcon(qt.QStyle.SP_MessageBoxCritical)
return icon
- class_ = self.h5pyClass
- if issubclass(class_, h5py.File):
+ class_ = self.h5Class
+ if class_ == silx.io.utils.H5Type.FILE:
return style.standardIcon(qt.QStyle.SP_FileIcon)
- elif issubclass(class_, h5py.Group):
+ elif class_ == silx.io.utils.H5Type.GROUP:
return style.standardIcon(qt.QStyle.SP_DirIcon)
- elif issubclass(class_, h5py.SoftLink):
+ elif class_ == silx.io.utils.H5Type.SOFT_LINK:
return style.standardIcon(qt.QStyle.SP_DirLinkIcon)
- elif issubclass(class_, h5py.ExternalLink):
+ elif class_ == silx.io.utils.H5Type.EXTERNAL_LINK:
return style.standardIcon(qt.QStyle.SP_FileLinkIcon)
- elif issubclass(class_, h5py.Dataset):
+ elif class_ == silx.io.utils.H5Type.DATASET:
if obj.shape is None:
name = "item-none"
elif len(obj.shape) < 4:
@@ -262,28 +284,28 @@ class Hdf5Item(Hdf5Node):
"""
attributeDict = collections.OrderedDict()
- if issubclass(self.h5pyClass, h5py.Dataset):
+ if self.h5Class == silx.io.utils.H5Type.DATASET:
attributeDict["#Title"] = "HDF5 Dataset"
attributeDict["Name"] = self.basename
attributeDict["Path"] = self.obj.name
attributeDict["Shape"] = self._getFormatter().humanReadableShape(self.obj)
attributeDict["Value"] = self._getFormatter().humanReadableValue(self.obj)
attributeDict["Data type"] = self._getFormatter().humanReadableType(self.obj, full=True)
- elif issubclass(self.h5pyClass, h5py.Group):
+ elif self.h5Class == silx.io.utils.H5Type.GROUP:
attributeDict["#Title"] = "HDF5 Group"
attributeDict["Name"] = self.basename
attributeDict["Path"] = self.obj.name
- elif issubclass(self.h5pyClass, h5py.File):
+ elif self.h5Class == silx.io.utils.H5Type.FILE:
attributeDict["#Title"] = "HDF5 File"
attributeDict["Name"] = self.basename
attributeDict["Path"] = "/"
- elif isinstance(self.obj, h5py.ExternalLink):
+ elif self.h5Class == silx.io.utils.H5Type.EXTERNAL_LINK:
attributeDict["#Title"] = "HDF5 External Link"
attributeDict["Name"] = self.basename
attributeDict["Path"] = self.obj.name
attributeDict["Linked path"] = self.obj.path
attributeDict["Linked file"] = self.obj.filename
- elif isinstance(self.obj, h5py.SoftLink):
+ elif self.h5Class == silx.io.utils.H5Type.SOFT_LINK:
attributeDict["#Title"] = "HDF5 Soft Link"
attributeDict["Name"] = self.basename
attributeDict["Path"] = self.obj.name
@@ -331,8 +353,8 @@ class Hdf5Item(Hdf5Node):
if role == qt.Qt.DisplayRole:
if self.__error is not None:
return ""
- class_ = self.h5pyClass
- if issubclass(class_, h5py.Dataset):
+ class_ = self.h5Class
+ if class_ == silx.io.utils.H5Type.DATASET:
text = self._getFormatter().humanReadableType(self.obj)
else:
text = ""
@@ -349,8 +371,8 @@ class Hdf5Item(Hdf5Node):
if role == qt.Qt.DisplayRole:
if self.__error is not None:
return ""
- class_ = self.h5pyClass
- if not issubclass(class_, h5py.Dataset):
+ class_ = self.h5Class
+ if class_ != silx.io.utils.H5Type.DATASET:
return ""
return self._getFormatter().humanReadableShape(self.obj)
return None
@@ -364,7 +386,7 @@ class Hdf5Item(Hdf5Node):
if role == qt.Qt.DisplayRole:
if self.__error is not None:
return ""
- if not issubclass(self.h5pyClass, h5py.Dataset):
+ if self.h5Class != silx.io.utils.H5Type.DATASET:
return ""
return self._getFormatter().humanReadableValue(self.obj)
return None
@@ -387,7 +409,7 @@ class Hdf5Item(Hdf5Node):
if role == qt.Qt.ToolTipRole:
if self.__error is not None:
self.obj # lazy loading of the object
- self.__initH5pyObject()
+ self.__initH5Object()
return self.__error
if "desc" in self.obj.attrs:
text = self.obj.attrs["desc"]
@@ -405,11 +427,11 @@ class Hdf5Item(Hdf5Node):
if role == qt.Qt.DisplayRole:
if self.isBrokenObj():
return ""
- class_ = self.h5pyClass
+ class_ = self.obj.__class__
text = class_.__name__.split(".")[-1]
return text
if role == qt.Qt.ToolTipRole:
- class_ = self.h5pyClass
+ class_ = self.obj.__class__
if class_ is None:
return ""
return "Class name: %s" % self.__class__
@@ -430,11 +452,11 @@ class Hdf5Item(Hdf5Node):
link = self.linkClass
if link is None:
return ""
- elif link is h5py.ExternalLink:
+ elif link == silx.io.utils.H5Type.EXTERNAL_LINK:
return "External"
- elif link is h5py.SoftLink:
+ elif link == silx.io.utils.H5Type.SOFT_LINK:
return "Soft"
- elif link is h5py.HardLink:
+ elif link == silx.io.utils.H5Type.HARD_LINK:
return ""
else:
return link.__name__
diff --git a/silx/gui/hdf5/Hdf5TreeModel.py b/silx/gui/hdf5/Hdf5TreeModel.py
index 41fa91c..2d62429 100644
--- a/silx/gui/hdf5/Hdf5TreeModel.py
+++ b/silx/gui/hdf5/Hdf5TreeModel.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -25,11 +25,12 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "22/09/2017"
+__date__ = "29/11/2017"
import os
import logging
+import functools
from .. import qt
from .. import icons
from .Hdf5Node import Hdf5Node
@@ -130,7 +131,6 @@ class LoadingItemRunnable(qt.QRunnable):
item = Hdf5Item(text=text, obj=h5obj, parent=oldItem.parent, populateAll=True)
return item
- @qt.Slot()
def run(self):
"""Process the file loading. The worker is used as holder
of the data and the signal. The result is sent as a signal.
@@ -237,25 +237,32 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
self.__openedFiles = []
"""Store the list of files opened by the model itself."""
- # FIXME: It should managed one by one by Hdf5Item itself
-
- def __del__(self):
- self._closeOpened()
- s = super(Hdf5TreeModel, self)
- if hasattr(s, "__del__"):
- # else it fail on Python 3
- s.__del__()
+ # FIXME: It should be managed one by one by Hdf5Item itself
+
+ # It is not possible to override the QObject destructor nor
+ # to access to the content of the Python object with the `destroyed`
+ # signal cause the Python method was already removed with the QWidget,
+ # while the QObject still exists.
+ # We use a static method plus explicit references to objects to
+ # release. The callback do not use any ref to self.
+ onDestroy = functools.partial(self._closeFileList, self.__openedFiles)
+ self.destroyed.connect(onDestroy)
+
+ @staticmethod
+ def _closeFileList(fileList):
+ """Static method to close explicit references to internal objects."""
+ _logger.debug("Clear Hdf5TreeModel")
+ for obj in fileList:
+ _logger.debug("Close file %s", obj.filename)
+ obj.close()
+ fileList[:] = []
def _closeOpened(self):
"""Close files which was opened by this model.
- This function may be removed in the future.
-
File are opened by the model when it was inserted using
`insertFileAsync`, `insertFile`, `appendFile`."""
- for h5file in self.__openedFiles:
- h5file.close()
- self.__openedFiles = []
+ self._closeFileList(self.__openedFiles)
def __updateLoadingItems(self, icon):
for i in range(self.__root.childCount()):
@@ -283,6 +290,7 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
self.__root.removeChildAtIndex(row)
self.endRemoveRows()
if newItem is not None:
+ rootIndex = qt.QModelIndex()
self.__openedFiles.append(newItem.obj)
self.beginInsertRows(rootIndex, row, row)
self.__root.insertChild(row, newItem)
@@ -325,7 +333,7 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
Returns an object that contains serialized items of data corresponding
to the list of indexes specified.
- :param list(qt.QModelIndex) indexes: List of indexes
+ :param List[qt.QModelIndex] indexes: List of indexes
:rtype: qt.QMimeData
"""
if not self.__fileMoveEnabled or len(indexes) == 0:
@@ -512,6 +520,16 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
def nodeFromIndex(self, index):
return index.internalPointer() if index.isValid() else self.__root
+ def _closeFileIfOwned(self, node):
+ """"Close the file if it was loaded from a filename or a
+ drag-and-drop"""
+ obj = node.obj
+ for f in self.__openedFiles:
+ if f in obj:
+ _logger.debug("Close file %s", obj.filename)
+ obj.close()
+ self.__openedFiles.remove(obj)
+
def synchronizeIndex(self, index):
"""
Synchronize a file a given its index.
@@ -524,9 +542,8 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
if node.parent is not self.__root:
return
- self.removeIndex(index)
filename = node.obj.filename
- node.obj.close()
+ self.removeIndex(index)
self.insertFileAsync(filename, index.row())
def synchronizeH5pyObject(self, h5pyObject):
@@ -555,6 +572,7 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
node = self.nodeFromIndex(index)
if node.parent is not self.__root:
return
+ self._closeFileIfOwned(node)
self.beginRemoveRows(qt.QModelIndex(), index.row(), index.row())
self.__root.removeChildAtIndex(index.row())
self.endRemoveRows()
@@ -587,6 +605,9 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
row = self.__root.childCount()
self.insertNode(row, Hdf5Item(text=text, obj=h5pyObject, parent=self.__root))
+ def hasPendingOperations(self):
+ return len(self.__runnerSet) > 0
+
def insertFileAsync(self, filename, row=-1):
if not os.path.isfile(filename):
raise IOError("Filename '%s' must be a file path" % filename)
@@ -599,9 +620,9 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
# start loading the real one
runnable = LoadingItemRunnable(filename, item)
runnable.itemReady.connect(self.__itemReady)
- self.__runnerSet.add(runnable)
runnable.runnerFinished.connect(self.__releaseRunner)
- qt.QThreadPool.globalInstance().start(runnable)
+ self.__runnerSet.add(runnable)
+ qt.silxGlobalThreadPool().start(runnable)
def __releaseRunner(self, runner):
self.__runnerSet.remove(runner)
@@ -621,3 +642,75 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
def appendFile(self, filename):
self.insertFile(filename, -1)
+
+ def indexFromH5Object(self, h5Object):
+ """Returns a model index from an h5py-like object.
+
+ :param object h5Object: An h5py-like object
+ :rtype: qt.QModelIndex
+ """
+ if h5Object is None:
+ return qt.QModelIndex()
+
+ filename = h5Object.file.filename
+
+ # Seach for the right roots
+ rootIndices = []
+ for index in range(self.rowCount(qt.QModelIndex())):
+ index = self.index(index, 0, qt.QModelIndex())
+ obj = self.data(index, Hdf5TreeModel.H5PY_OBJECT_ROLE)
+ if obj.file.filename == filename:
+ # We can have many roots with different subtree of the same
+ # root
+ rootIndices.append(index)
+
+ if len(rootIndices) == 0:
+ # No root found
+ return qt.QModelIndex()
+
+ path = h5Object.name + "/"
+ path = path.replace("//", "/")
+
+ # Search for the right node
+ found = False
+ foundIndices = []
+ for _ in range(1000 * len(rootIndices)):
+ # Avoid too much iterations, in case of recurssive links
+ if len(foundIndices) == 0:
+ if len(rootIndices) == 0:
+ # Nothing found
+ break
+ # Start fron a new root
+ foundIndices.append(rootIndices.pop(0))
+
+ obj = self.data(index, Hdf5TreeModel.H5PY_OBJECT_ROLE)
+ p = obj.name + "/"
+ p = p.replace("//", "/")
+ if path == p:
+ found = True
+ break
+
+ parentIndex = foundIndices[-1]
+ for index in range(self.rowCount(parentIndex)):
+ index = self.index(index, 0, parentIndex)
+ obj = self.data(index, Hdf5TreeModel.H5PY_OBJECT_ROLE)
+
+ p = obj.name + "/"
+ p = p.replace("//", "/")
+ if path == p:
+ foundIndices.append(index)
+ found = True
+ break
+ elif path.startswith(p):
+ foundIndices.append(index)
+ break
+ else:
+ # Nothing found, start again with another root
+ foundIndices = []
+
+ if found:
+ break
+
+ if found:
+ return foundIndices[-1]
+ return qt.QModelIndex()
diff --git a/silx/gui/hdf5/Hdf5TreeView.py b/silx/gui/hdf5/Hdf5TreeView.py
index 0a4198e..78b5c19 100644
--- a/silx/gui/hdf5/Hdf5TreeView.py
+++ b/silx/gui/hdf5/Hdf5TreeView.py
@@ -25,7 +25,7 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "20/09/2017"
+__date__ = "20/02/2018"
import logging
@@ -114,12 +114,12 @@ class Hdf5TreeView(qt.QTreeView):
callback(event)
except KeyboardInterrupt:
raise
- except:
+ except Exception:
# make sure no user callback crash the application
_logger.error("Error while calling callback", exc_info=True)
pass
- if len(menu.children()) > 0:
+ if not menu.isEmpty():
for action in actions:
menu.addAction(action)
menu.popup(self.viewport().mapToGlobal(pos))
@@ -194,6 +194,38 @@ class Hdf5TreeView(qt.QTreeView):
continue
yield _utils.H5Node(item)
+ def __intermediateModels(self, index):
+ """Returns intermediate models from the view model to the
+ model of the index."""
+ models = []
+ targetModel = index.model()
+ model = self.model()
+ while model is not None:
+ if model is targetModel:
+ # found
+ return models
+ models.append(model)
+ if isinstance(model, qt.QAbstractProxyModel):
+ model = model.sourceModel()
+ else:
+ break
+ raise RuntimeError("Model from the requested index is not reachable from this view")
+
+ def mapToModel(self, index):
+ """Map an index from any model reachable by the view to an index from
+ the very first model connected to the view.
+
+ :param qt.QModelIndex index: Index from the Hdf5Tree model
+ :rtype: qt.QModelIndex
+ :return: Index from the model connected to the view
+ """
+ if not index.isValid():
+ return index
+ models = self.__intermediateModels(index)
+ for model in reversed(models):
+ index = model.mapFromSource(index)
+ return index
+
def setSelectedH5Node(self, h5Object):
"""
Select the specified node of the tree using an h5py node.
@@ -203,77 +235,22 @@ class Hdf5TreeView(qt.QTreeView):
- If the item is not found, the selection do not change.
- A none argument allow to deselect everything
- :param h5py.Npde h5Object: The node to select
+ :param h5py.Node h5Object: The node to select
"""
if h5Object is None:
self.setCurrentIndex(qt.QModelIndex())
return
- filename = h5Object.file.filename
-
- # Seach for the right roots
- rootIndices = []
- model = self.model()
- for index in range(model.rowCount(qt.QModelIndex())):
- index = model.index(index, 0, qt.QModelIndex())
- obj = model.data(index, Hdf5TreeModel.H5PY_OBJECT_ROLE)
- if obj.file.filename == filename:
- # We can have many roots with different subtree of the same
- # root
- rootIndices.append(index)
-
- if len(rootIndices) == 0:
- # No root found
- return
-
- path = h5Object.name + "/"
- path = path.replace("//", "/")
-
- # Search for the right node
- found = False
- foundIndices = []
- for _ in range(1000 * len(rootIndices)):
- # Avoid too much iterations, in case of recurssive links
- if len(foundIndices) == 0:
- if len(rootIndices) == 0:
- # Nothing found
- break
- # Start fron a new root
- foundIndices.append(rootIndices.pop(0))
-
- obj = model.data(index, Hdf5TreeModel.H5PY_OBJECT_ROLE)
- p = obj.name + "/"
- p = p.replace("//", "/")
- if path == p:
- found = True
- break
-
- parentIndex = foundIndices[-1]
- for index in range(model.rowCount(parentIndex)):
- index = model.index(index, 0, parentIndex)
- obj = model.data(index, Hdf5TreeModel.H5PY_OBJECT_ROLE)
-
- p = obj.name + "/"
- p = p.replace("//", "/")
- if path == p:
- foundIndices.append(index)
- found = True
- break
- elif path.startswith(p):
- foundIndices.append(index)
- break
- else:
- # Nothing found, start again with another root
- foundIndices = []
-
- if found:
- break
-
- if found:
+ model = self.findHdf5TreeModel()
+ index = model.indexFromH5Object(h5Object)
+ index = self.mapToModel(index)
+ if index.isValid():
# Update the GUI
- for index in foundIndices[:-1]:
- self.expand(index)
- self.setCurrentIndex(foundIndices[-1])
+ i = index
+ while i.isValid():
+ self.expand(i)
+ i = i.parent()
+ self.setCurrentIndex(index)
def mousePressEvent(self, event):
"""Override mousePressEvent to provide a consistante compatible API
diff --git a/silx/gui/hdf5/NexusSortFilterProxyModel.py b/silx/gui/hdf5/NexusSortFilterProxyModel.py
index 49a22d3..9a27968 100644
--- a/silx/gui/hdf5/NexusSortFilterProxyModel.py
+++ b/silx/gui/hdf5/NexusSortFilterProxyModel.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +25,7 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "16/06/2017"
+__date__ = "10/10/2017"
import logging
@@ -33,14 +33,8 @@ import re
import numpy
from .. import qt
from .Hdf5TreeModel import Hdf5TreeModel
+import silx.io.utils
-_logger = logging.getLogger(__name__)
-
-try:
- import h5py
-except ImportError as e:
- _logger.error("Module %s requires h5py", __name__)
- raise e
_logger = logging.getLogger(__name__)
@@ -86,8 +80,8 @@ class NexusSortFilterProxyModel(qt.QSortFilterProxyModel):
def __isNXentry(self, node):
"""Returns true if the node is an NXentry"""
- class_ = node.h5pyClass
- if class_ is None or not issubclass(node.h5pyClass, h5py.Group):
+ class_ = node.h5Class
+ if class_ is None or class_ != silx.io.utils.H5Type.GROUP:
return False
nxClass = node.obj.attrs.get("NX_class", None)
return nxClass == "NXentry"
@@ -100,7 +94,7 @@ class NexusSortFilterProxyModel(qt.QSortFilterProxyModel):
`["aaa", 10, "bbb", 50, ".", 30]`.
:param str name: A name
- :rtype: list
+ :rtype: List
"""
words = self.__split.findall(name)
result = []
@@ -148,6 +142,6 @@ class NexusSortFilterProxyModel(qt.QSortFilterProxyModel):
return left_time < right_time
except KeyboardInterrupt:
raise
- except Exception as e:
+ except Exception:
_logger.debug("Exception occurred", exc_info=True)
return None
diff --git a/silx/gui/hdf5/_utils.py b/silx/gui/hdf5/_utils.py
index 048aa20..ddf4db5 100644
--- a/silx/gui/hdf5/_utils.py
+++ b/silx/gui/hdf5/_utils.py
@@ -28,7 +28,7 @@ package `silx.gui.hdf5` package.
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "29/09/2017"
+__date__ = "20/12/2017"
import logging
@@ -38,12 +38,6 @@ from silx.utils.html import escape
_logger = logging.getLogger(__name__)
-try:
- import h5py
-except ImportError as e:
- _logger.error("Module %s requires h5py", __name__)
- raise e
-
class Hdf5ContextMenuEvent(object):
"""Hold information provided to context menu callbacks."""
@@ -168,12 +162,13 @@ class H5Node(object):
e = elements.pop(0)
path = path + "/" + e
link = obj.parent.get(path, getlink=True)
+ classlink = silx.io.utils.get_h5_class(link)
- if isinstance(link, h5py.ExternalLink):
+ if classlink == silx.io.utils.H5Type.EXTERNAL_LINK:
subpath = "/".join(elements)
external_obj = obj.parent.get(self.basename + "/" + subpath)
return self.__get_target(external_obj)
- elif silx.io.utils.is_softlink(link):
+ elif classlink == silx.io.utils.H5Type.SOFT_LINK:
# Restart from this stat
path = ""
root_elements = link.path.split("/")
@@ -202,13 +197,22 @@ class H5Node(object):
return self.__h5py_object
@property
+ def h5type(self):
+ """Returns the node type, as an H5Type.
+
+ :rtype: H5Node
+ """
+ return silx.io.utils.get_h5_class(self.__h5py_object)
+
+ @property
def ntype(self):
"""Returns the node type, as an h5py class.
:rtype:
:class:`h5py.File`, :class:`h5py.Group` or :class:`h5py.Dataset`
"""
- return silx.io.utils.get_h5py_class(self.__h5py_object)
+ type_ = self.h5type
+ return silx.io.utils.h5type_to_h5py_class(type_)
@property
def basename(self):
@@ -269,13 +273,13 @@ class H5Node(object):
"""
item = self.__h5py_item
while item.parent.parent is not None:
- class_ = item.h5pyClass
- if class_ is not None and issubclass(class_, h5py.File):
+ class_ = silx.io.utils.get_h5_class(class_=item.h5pyClass)
+ if class_ == silx.io.utils.H5Type.FILE:
break
item = item.parent
- class_ = item.h5pyClass
- if class_ is not None and issubclass(class_, h5py.File):
+ class_ = silx.io.utils.get_h5_class(class_=item.h5pyClass)
+ if class_ == silx.io.utils.H5Type.FILE:
return item.obj
else:
return item.obj.file
@@ -313,8 +317,8 @@ class H5Node(object):
:rtype: str
"""
- class_ = self.__h5py_item.h5pyClass
- if class_ is not None and issubclass(class_, h5py.File):
+ class_ = self.__h5py_item.h5Class
+ if class_ is not None and class_ == silx.io.utils.H5Type.FILE:
return ""
return self.__h5py_item.basename
@@ -327,10 +331,11 @@ class H5Node(object):
:rtype: h5py.File
:raises RuntimeError: If no file are found
"""
- if isinstance(self.__h5py_object, h5py.ExternalLink):
+ class_ = silx.io.utils.get_h5_class(self.__h5py_object)
+ if class_ == silx.io.utils.H5Type.EXTERNAL_LINK:
# It means the link is broken
raise RuntimeError("No file node found")
- if isinstance(self.__h5py_object, h5py.SoftLink):
+ if class_ == silx.io.utils.H5Type.SOFT_LINK:
# It means the link is broken
return self.local_file
@@ -347,10 +352,11 @@ class H5Node(object):
:rtype: str
"""
- if isinstance(self.__h5py_object, h5py.ExternalLink):
+ class_ = silx.io.utils.get_h5_class(self.__h5py_object)
+ if class_ == silx.io.utils.H5Type.EXTERNAL_LINK:
# It means the link is broken
return self.__h5py_object.path
- if isinstance(self.__h5py_object, h5py.SoftLink):
+ if class_ == silx.io.utils.H5Type.SOFT_LINK:
# It means the link is broken
return self.__h5py_object.path
@@ -367,10 +373,11 @@ class H5Node(object):
:rtype: str
"""
- if isinstance(self.__h5py_object, h5py.ExternalLink):
+ class_ = silx.io.utils.get_h5_class(self.__h5py_object)
+ if class_ == silx.io.utils.H5Type.EXTERNAL_LINK:
# It means the link is broken
return self.__h5py_object.filename
- if isinstance(self.__h5py_object, h5py.SoftLink):
+ if class_ == silx.io.utils.H5Type.SOFT_LINK:
# It means the link is broken
return self.local_file.filename
diff --git a/silx/gui/hdf5/test/test_hdf5.py b/silx/gui/hdf5/test/test_hdf5.py
index 8e375f2..44c4456 100644
--- a/silx/gui/hdf5/test/test_hdf5.py
+++ b/silx/gui/hdf5/test/test_hdf5.py
@@ -26,7 +26,7 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "22/09/2017"
+__date__ = "20/02/2018"
import time
@@ -40,6 +40,7 @@ from silx.gui import qt
from silx.gui.test.utils import TestCaseQt
from silx.gui import hdf5
from silx.io import commonh5
+import weakref
try:
import h5py
@@ -69,6 +70,14 @@ class TestHdf5TreeModel(TestCaseQt):
if h5py is None:
self.skipTest("h5py is not available")
+ def waitForPendingOperations(self, model):
+ for i in range(10):
+ if not model.hasPendingOperations():
+ break
+ self.qWait(10)
+ else:
+ raise RuntimeError("Still waiting for a pending operation")
+
@contextmanager
def h5TempFile(self):
# create tmp file
@@ -96,7 +105,9 @@ class TestHdf5TreeModel(TestCaseQt):
# clean up
index = model.index(0, 0, qt.QModelIndex())
h5File = model.data(index, hdf5.Hdf5TreeModel.H5PY_OBJECT_ROLE)
- h5File.close()
+ ref = weakref.ref(model)
+ model = None
+ self.qWaitForDestroy(ref)
def testAppendBadFilename(self):
model = hdf5.Hdf5TreeModel()
@@ -104,32 +115,35 @@ class TestHdf5TreeModel(TestCaseQt):
def testInsertFilename(self):
with self.h5TempFile() as filename:
- model = hdf5.Hdf5TreeModel()
- self.assertEquals(model.rowCount(qt.QModelIndex()), 0)
- model.insertFile(filename)
- self.assertEquals(model.rowCount(qt.QModelIndex()), 1)
- # clean up
- index = model.index(0, 0, qt.QModelIndex())
- h5File = model.data(index, hdf5.Hdf5TreeModel.H5PY_OBJECT_ROLE)
- h5File.close()
+ try:
+ model = hdf5.Hdf5TreeModel()
+ self.assertEquals(model.rowCount(qt.QModelIndex()), 0)
+ model.insertFile(filename)
+ self.assertEquals(model.rowCount(qt.QModelIndex()), 1)
+ # clean up
+ index = model.index(0, 0, qt.QModelIndex())
+ h5File = model.data(index, hdf5.Hdf5TreeModel.H5PY_OBJECT_ROLE)
+ self.assertIsNotNone(h5File)
+ finally:
+ ref = weakref.ref(model)
+ model = None
+ self.qWaitForDestroy(ref)
def testInsertFilenameAsync(self):
with self.h5TempFile() as filename:
- model = hdf5.Hdf5TreeModel()
- self.assertEquals(model.rowCount(qt.QModelIndex()), 0)
- model.insertFileAsync(filename)
- index = model.index(0, 0, qt.QModelIndex())
- self.assertIsInstance(model.nodeFromIndex(index), hdf5.Hdf5LoadingItem.Hdf5LoadingItem)
- time.sleep(0.1)
- self.qapp.processEvents()
- time.sleep(0.1)
- index = model.index(0, 0, qt.QModelIndex())
- self.assertIsInstance(model.nodeFromIndex(index), hdf5.Hdf5Item.Hdf5Item)
- self.assertEquals(model.rowCount(qt.QModelIndex()), 1)
- # clean up
- index = model.index(0, 0, qt.QModelIndex())
- h5File = model.data(index, hdf5.Hdf5TreeModel.H5PY_OBJECT_ROLE)
- h5File.close()
+ try:
+ model = hdf5.Hdf5TreeModel()
+ self.assertEquals(model.rowCount(qt.QModelIndex()), 0)
+ model.insertFileAsync(filename)
+ index = model.index(0, 0, qt.QModelIndex())
+ self.assertIsInstance(model.nodeFromIndex(index), hdf5.Hdf5LoadingItem.Hdf5LoadingItem)
+ self.waitForPendingOperations(model)
+ index = model.index(0, 0, qt.QModelIndex())
+ self.assertIsInstance(model.nodeFromIndex(index), hdf5.Hdf5Item.Hdf5Item)
+ finally:
+ ref = weakref.ref(model)
+ model = None
+ self.qWaitForDestroy(ref)
def testInsertObject(self):
h5 = commonh5.File("/foo/bar/1.mock", "w")
@@ -156,6 +170,10 @@ class TestHdf5TreeModel(TestCaseQt):
index = model.index(0, 0, qt.QModelIndex())
node1 = model.nodeFromIndex(index)
model.synchronizeH5pyObject(h5)
+ # Now h5 was loaded from it's filename
+ # Another ref is owned by the model
+ h5.close()
+
index = model.index(0, 0, qt.QModelIndex())
node2 = model.nodeFromIndex(index)
self.assertIsNot(node1, node2)
@@ -168,7 +186,12 @@ class TestHdf5TreeModel(TestCaseQt):
# clean up
index = model.index(0, 0, qt.QModelIndex())
h5File = model.data(index, hdf5.Hdf5TreeModel.H5PY_OBJECT_ROLE)
- h5File.close()
+ self.assertIsNotNone(h5File)
+ h5File = None
+ # delete the model
+ ref = weakref.ref(model)
+ model = None
+ self.qWaitForDestroy(ref)
def testFileMoveState(self):
model = hdf5.Hdf5TreeModel()
@@ -206,15 +229,17 @@ class TestHdf5TreeModel(TestCaseQt):
model.dropMimeData(mimeData, qt.Qt.CopyAction, 0, 0, qt.QModelIndex())
self.assertEquals(model.rowCount(qt.QModelIndex()), 1)
# after sync
- time.sleep(0.1)
- self.qapp.processEvents()
- time.sleep(0.1)
+ self.waitForPendingOperations(model)
index = model.index(0, 0, qt.QModelIndex())
self.assertIsInstance(model.nodeFromIndex(index), hdf5.Hdf5Item.Hdf5Item)
# clean up
index = model.index(0, 0, qt.QModelIndex())
h5File = model.data(index, role=hdf5.Hdf5TreeModel.H5PY_OBJECT_ROLE)
- h5File.close()
+ self.assertIsNotNone(h5File)
+ h5File = None
+ ref = weakref.ref(model)
+ model = None
+ self.qWaitForDestroy(ref)
def getRowDataAsDict(self, model, row):
displayed = {}
@@ -503,7 +528,9 @@ class TestH5Node(TestCaseQt):
@classmethod
def tearDownClass(cls):
+ ref = weakref.ref(cls.model)
cls.model = None
+ cls.qWaitForDestroy(ref)
cls.h5File.close()
shutil.rmtree(cls.tmpDirectory)
super(TestH5Node, cls).tearDownClass()
@@ -696,6 +723,18 @@ class TestHdf5TreeView(TestCaseQt):
view = hdf5.Hdf5TreeView()
view._createContextMenu(qt.QPoint(0, 0))
+ def testSelection_OriginalModel(self):
+ tree = commonh5.File("/foo/bar/1.mock", "w")
+ item = tree.create_group("a/b/c/d")
+ item.create_group("e").create_group("f")
+
+ view = hdf5.Hdf5TreeView()
+ view.findHdf5TreeModel().insertH5pyObject(tree)
+ view.setSelectedH5Node(item)
+
+ selected = list(view.selectedH5Nodes())[0]
+ self.assertIs(item, selected.h5py_object)
+
def testSelection_Simple(self):
tree = commonh5.File("/foo/bar/1.mock", "w")
item = tree.create_group("a/b/c/d")
diff --git a/silx/gui/icons.py b/silx/gui/icons.py
index 07654c1..0108b3a 100644
--- a/silx/gui/icons.py
+++ b/silx/gui/icons.py
@@ -328,7 +328,8 @@ def getQIcon(name):
"""
if name not in _cached_icons:
qfile = getQFile(name)
- icon = qt.QIcon(qfile.fileName())
+ pixmap = qt.QPixmap(qfile.fileName())
+ icon = qt.QIcon(pixmap)
_cached_icons[name] = icon
else:
icon = _cached_icons[name]
diff --git a/silx/gui/plot/ColorBar.py b/silx/gui/plot/ColorBar.py
index 8f4bde2..2db7b79 100644
--- a/silx/gui/plot/ColorBar.py
+++ b/silx/gui/plot/ColorBar.py
@@ -27,7 +27,7 @@
__authors__ = ["H. Payno", "T. Vincent"]
__license__ = "MIT"
-__date__ = "11/04/2017"
+__date__ = "15/02/2018"
import logging
@@ -65,11 +65,12 @@ class ColorBarWidget(qt.QWidget):
:param plot: PlotWidget the colorbar is attached to (optional)
:param str legend: the label to set to the colorbar
"""
+ sigVisibleChanged = qt.Signal(bool)
+ """Emitted when the property `visible` have changed."""
def __init__(self, parent=None, plot=None, legend=None):
self._isConnected = False
self._plot = None
- self._viewAction = None
self._colormap = None
self._data = None
@@ -127,15 +128,18 @@ class ColorBarWidget(qt.QWidget):
self._plot.sigPlotSignal.connect(self._defaultColormapChanged)
self._isConnected = True
+ def setVisible(self, isVisible):
+ # isHidden looks to be always synchronized, while isVisible is not
+ wasHidden = self.isHidden()
+ qt.QWidget.setVisible(self, isVisible)
+ if wasHidden != self.isHidden():
+ self.sigVisibleChanged.emit(not self.isHidden())
+
def showEvent(self, event):
self._connectPlot()
- if self._viewAction is not None:
- self._viewAction.setChecked(True)
def hideEvent(self, event):
self._disconnectPlot()
- if self._viewAction is not None:
- self._viewAction.setChecked(False)
def getColormap(self):
"""
@@ -230,21 +234,6 @@ class ColorBarWidget(qt.QWidget):
and ticks"""
return self._colorScale
- def getToggleViewAction(self):
- """Returns a checkable action controlling this widget's visibility.
-
- :rtype: QAction
- """
- if self._viewAction is None:
- self._viewAction = qt.QAction(self)
- self._viewAction.setText('Colorbar')
- self._viewAction.setIcon(icons.getQIcon('colorbar'))
- self._viewAction.setToolTip('Show/Hide the colorbar')
- self._viewAction.setCheckable(True)
- self._viewAction.setChecked(self.isVisible())
- self._viewAction.toggled[bool].connect(self.setVisible)
- return self._viewAction
-
class _VerticalLegend(qt.QLabel):
"""Display vertically the given text
@@ -405,8 +394,8 @@ class ColorScaleBar(qt.QWidget):
:param val: if True, set the labels visible, otherwise set it not visible
"""
- self._maxLabel.show() if val is True else self._maxLabel.hide()
- self._minLabel.show() if val is True else self._minLabel.hide()
+ self._minLabel.setVisible(val)
+ self._maxLabel.setVisible(val)
def _updateMinMax(self):
"""Update the min and max label if we are in the case of the
@@ -533,12 +522,7 @@ class _ColorScale(qt.QWidget):
return
indices = numpy.linspace(0., 1., self._NB_CONTROL_POINTS)
- colormapDisp = Colormap.Colormap(name=colormap.getName(),
- normalization=Colormap.Colormap.LINEAR,
- vmin=None,
- vmax=None,
- colors=colormap.getColormapLUT())
- colors = colormapDisp.applyToData(indices)
+ colors = colormap.getNColors(nbColors=self._NB_CONTROL_POINTS)
self._gradient = qt.QLinearGradient(0, 1, 0, 0)
self._gradient.setCoordinateMode(qt.QGradient.StretchToDeviceMode)
self._gradient.setStops(
@@ -784,7 +768,7 @@ class _TickBar(qt.QWidget):
if self._norm == Colormap.Colormap.LINEAR:
return 1 - (val - self._vmin) / (self._vmax - self._vmin)
elif self._norm == Colormap.Colormap.LOGARITHM:
- return 1 - (numpy.log10(val) - numpy.log10(self._vmin))/(numpy.log10(self._vmax) - numpy.log(self._vmin))
+ return 1 - (numpy.log10(val) - numpy.log10(self._vmin)) / (numpy.log10(self._vmax) - numpy.log(self._vmin))
else:
raise ValueError('Norm is not recognized')
diff --git a/silx/gui/plot/Colormap.py b/silx/gui/plot/Colormap.py
index abe8546..9adf0d4 100644
--- a/silx/gui/plot/Colormap.py
+++ b/silx/gui/plot/Colormap.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -29,7 +29,7 @@ from __future__ import absolute_import
__authors__ = ["T. Vincent", "H.Payno"]
__license__ = "MIT"
-__date__ = "05/12/2016"
+__date__ = "08/01/2018"
from silx.gui import qt
import copy as copy_mdl
@@ -37,6 +37,7 @@ import numpy
from .matplotlib import Colormap as MPLColormap
import logging
from silx.math.combo import min_max
+from silx.utils.exceptions import NotEditableError
_logger = logging.getLogger(__file__)
@@ -62,7 +63,7 @@ class Colormap(qt.QObject):
Nx3 or Nx4 numpy array of RGB(A) colors,
either uint8 or float in [0, 1].
If 'name' is None, then this array is used as the colormap.
- :param str norm: Normalization: 'linear' (default) or 'log'
+ :param str normalization: Normalization: 'linear' (default) or 'log'
:param float vmin:
Lower bound of the colormap or None for autoscale (default)
:param float vmax:
@@ -79,6 +80,7 @@ class Colormap(qt.QObject):
"""Tuple of managed normalizations"""
sigChanged = qt.Signal()
+ """Signal emitted when the colormap has changed."""
def __init__(self, name='gray', colors=None, normalization=LINEAR, vmin=None, vmax=None):
qt.QObject.__init__(self)
@@ -98,10 +100,11 @@ class Colormap(qt.QObject):
self._normalization = str(normalization)
self._vmin = float(vmin) if vmin is not None else None
self._vmax = float(vmax) if vmax is not None else None
+ self._editable = True
def isAutoscale(self):
"""Return True if both min and max are in autoscale mode"""
- return self._vmin is None or self._vmax is None
+ return self._vmin is None and self._vmax is None
def getName(self):
"""Return the name of the colormap
@@ -115,35 +118,69 @@ class Colormap(qt.QObject):
else:
self._colors = numpy.array(colors, copy=True)
+ def getNColors(self, nbColors=None):
+ """Returns N colors computed by sampling the colormap regularly.
+
+ :param nbColors:
+ The number of colors in the returned array or None for the default value.
+ The default value is 256 for colormap with a name (see :meth:`setName`) and
+ it is the size of the LUT for colormap defined with :meth:`setColormapLUT`.
+ :type nbColors: int or None
+ :return: 2D array of uint8 of shape (nbColors, 4)
+ :rtype: numpy.ndarray
+ """
+ # Handle default value for nbColors
+ if nbColors is None:
+ lut = self.getColormapLUT()
+ if lut is not None: # In this case uses LUT length
+ nbColors = len(lut)
+ else: # Default to 256
+ nbColors = 256
+
+ nbColors = int(nbColors)
+
+ colormap = self.copy()
+ colormap.setNormalization(Colormap.LINEAR)
+ colormap.setVRange(vmin=None, vmax=None)
+ colors = colormap.applyToData(
+ numpy.arange(nbColors, dtype=numpy.int))
+ return colors
+
def setName(self, name):
- """Set the name of the colormap and load the colors corresponding to
- the name
+ """Set the name of the colormap to use.
- :param str name: the name of the colormap (should be in ['gray',
+ :param str name: The name of the colormap.
+ At least the following names are supported: 'gray',
'reversed gray', 'temperature', 'red', 'green', 'blue', 'jet',
- 'viridis', 'magma', 'inferno', 'plasma']
+ 'viridis', 'magma', 'inferno', 'plasma'.
"""
+ if self.isEditable() is False:
+ raise NotEditableError('Colormap is not editable')
assert name in self.getSupportedColormaps()
self._name = str(name)
self._colors = None
self.sigChanged.emit()
def getColormapLUT(self):
- """Return the list of colors for the colormap. None if not setted
-
- :return: the list of colors for the colormap. None if not setted
- :rtype: numpy.ndarray
+ """Return the list of colors for the colormap or None if not set
+
+ :return: the list of colors for the colormap or None if not set
+ :rtype: numpy.ndarray or None
"""
- return self._colors
+ if self._colors is None:
+ return None
+ else:
+ return numpy.array(self._colors, copy=True)
def setColormapLUT(self, colors):
- """
- Set the colors of the colormap.
+ """Set the colors of the colormap.
:param numpy.ndarray colors: the colors of the LUT
- .. warning: this will set the value of name to an empty string
+ .. warning: this will set the value of name to None
"""
+ if self.isEditable() is False:
+ raise NotEditableError('Colormap is not editable')
self._setColors(colors)
if len(colors) is 0:
self._colors = None
@@ -153,7 +190,7 @@ class Colormap(qt.QObject):
def getNormalization(self):
"""Return the normalization of the colormap ('log' or 'linear')
-
+
:return: the normalization of the colormap
:rtype: str
"""
@@ -164,12 +201,14 @@ class Colormap(qt.QObject):
:param str norm: the norm to set
"""
+ if self.isEditable() is False:
+ raise NotEditableError('Colormap is not editable')
self._normalization = str(norm)
self.sigChanged.emit()
def getVMin(self):
"""Return the lower bound of the colormap
-
+
:return: the lower bound of the colormap
:rtype: float or None
"""
@@ -182,10 +221,12 @@ class Colormap(qt.QObject):
(default)
value)
"""
+ if self.isEditable() is False:
+ raise NotEditableError('Colormap is not editable')
if vmin is not None:
- if self._vmax is not None and vmin >= self._vmax:
- err = "Can't set vmin because vmin >= vmax."
- err += "vmin = %s, vmax = %s" %(vmin, self._vmax)
+ if self._vmax is not None and vmin > self._vmax:
+ err = "Can't set vmin because vmin >= vmax. " \
+ "vmin = %s, vmax = %s" % (vmin, self._vmax)
raise ValueError(err)
self._vmin = vmin
@@ -193,7 +234,7 @@ class Colormap(qt.QObject):
def getVMax(self):
"""Return the upper bounds of the colormap or None
-
+
:return: the upper bounds of the colormap or None
:rtype: float or None
"""
@@ -205,15 +246,35 @@ class Colormap(qt.QObject):
:param float vmax: Upper bounds of the colormap or None for autoscale
(default)
"""
+ if self.isEditable() is False:
+ raise NotEditableError('Colormap is not editable')
if vmax is not None:
- if self._vmin is not None and vmax <= self._vmin:
- err = "Can't set vmax because vmax <= vmin."
- err += "vmin = %s, vmax = %s" %(self._vmin, vmax)
+ if self._vmin is not None and vmax < self._vmin:
+ err = "Can't set vmax because vmax <= vmin. " \
+ "vmin = %s, vmax = %s" % (self._vmin, vmax)
raise ValueError(err)
self._vmax = vmax
self.sigChanged.emit()
+ def isEditable(self):
+ """ Return if the colormap is editable or not
+
+ :return: editable state of the colormap
+ :rtype: bool
+ """
+ return self._editable
+
+ def setEditable(self, editable):
+ """
+ Set the editable state of the colormap
+
+ :param bool editable: is the colormap editable
+ """
+ assert type(editable) is bool
+ self._editable = editable
+ self.sigChanged.emit()
+
def getColormapRange(self, data=None):
"""Return (vmin, vmax)
@@ -267,20 +328,24 @@ class Colormap(qt.QObject):
return vmin, vmax
def setVRange(self, vmin, vmax):
- """
- Set bounds to the colormap
+ """Set the bounds of the colormap
:param vmin: Lower bound of the colormap or None for autoscale
(default)
:param vmax: Upper bounds of the colormap or None for autoscale
(default)
"""
+ if self.isEditable() is False:
+ raise NotEditableError('Colormap is not editable')
if vmin is not None and vmax is not None:
- if vmin >= vmax:
- err = "Can't set vmin and vmax because vmin >= vmax"
- err += "vmin = %s, vmax = %s" %(vmin, self._vmax)
+ if vmin > vmax:
+ err = "Can't set vmin and vmax because vmin >= vmax " \
+ "vmin = %s, vmax = %s" % (vmin, vmax)
raise ValueError(err)
+ if self._vmin == vmin and self._vmax == vmax:
+ return
+
self._vmin = vmin
self._vmax = vmax
self.sigChanged.emit()
@@ -322,6 +387,8 @@ class Colormap(qt.QObject):
:param dict dic: the colormap as a dictionary
"""
+ if self.isEditable() is False:
+ raise NotEditableError('Colormap is not editable')
name = dic['name'] if 'name' in dic else None
colors = dic['colors'] if 'colors' in dic else None
vmin = dic['vmin'] if 'vmin' in dic else None
@@ -361,9 +428,9 @@ class Colormap(qt.QObject):
return colormap
def copy(self):
- """
+ """Return a copy of the Colormap.
- :return: a copy of the Colormap object
+ :rtype: silx.gui.plot.Colormap.Colormap
"""
return Colormap(name=self._name,
colors=copy_mdl.copy(self._colors),
@@ -408,3 +475,115 @@ class Colormap(qt.QObject):
numpy.array_equal(self.getColormapLUT(), other.getColormapLUT())
)
+ _SERIAL_VERSION = 1
+
+ def restoreState(self, byteArray):
+ """
+ Read the colormap state from a QByteArray.
+
+ :param qt.QByteArray byteArray: Stream containing the state
+ :return: True if the restoration sussseed
+ :rtype: bool
+ """
+ if self.isEditable() is False:
+ raise NotEditableError('Colormap is not editable')
+ stream = qt.QDataStream(byteArray, qt.QIODevice.ReadOnly)
+
+ className = stream.readQString()
+ if className != self.__class__.__name__:
+ _logger.warning("Classname mismatch. Found %s." % className)
+ return False
+
+ version = stream.readUInt32()
+ if version != self._SERIAL_VERSION:
+ _logger.warning("Serial version mismatch. Found %d." % version)
+ return False
+
+ name = stream.readQString()
+ isNull = stream.readBool()
+ if not isNull:
+ vmin = stream.readQVariant()
+ else:
+ vmin = None
+ isNull = stream.readBool()
+ if not isNull:
+ vmax = stream.readQVariant()
+ else:
+ vmax = None
+ normalization = stream.readQString()
+
+ # emit change event only once
+ old = self.blockSignals(True)
+ try:
+ self.setName(name)
+ self.setNormalization(normalization)
+ self.setVRange(vmin, vmax)
+ finally:
+ self.blockSignals(old)
+ self.sigChanged.emit()
+ return True
+
+ def saveState(self):
+ """
+ Save state of the colomap into a QDataStream.
+
+ :rtype: qt.QByteArray
+ """
+ data = qt.QByteArray()
+ stream = qt.QDataStream(data, qt.QIODevice.WriteOnly)
+
+ stream.writeQString(self.__class__.__name__)
+ stream.writeUInt32(self._SERIAL_VERSION)
+ stream.writeQString(self.getName())
+ stream.writeBool(self.getVMin() is None)
+ if self.getVMin() is not None:
+ stream.writeQVariant(self.getVMin())
+ stream.writeBool(self.getVMax() is None)
+ if self.getVMax() is not None:
+ stream.writeQVariant(self.getVMax())
+ stream.writeQString(self.getNormalization())
+ return data
+
+
+_PREFERRED_COLORMAPS = DEFAULT_COLORMAPS
+"""
+Tuple of preferred colormap names accessed with :meth:`preferredColormaps`.
+"""
+
+
+def preferredColormaps():
+ """Returns the name of the preferred colormaps.
+
+ This list is used by widgets allowing to change the colormap
+ like the :class:`ColormapDialog` as a subset of colormap choices.
+
+ :rtype: tuple of str
+ """
+ return _PREFERRED_COLORMAPS
+
+
+def setPreferredColormaps(colormaps):
+ """Set the list of preferred colormap names.
+
+ Warning: If a colormap name is not available
+ it will be removed from the list.
+
+ :param colormaps: Not empty list of colormap names
+ :type colormaps: iterable of str
+ :raise ValueError: if the list of available preferred colormaps is empty.
+ """
+ supportedColormaps = Colormap.getSupportedColormaps()
+ colormaps = tuple(
+ cmap for cmap in colormaps if cmap in supportedColormaps)
+ if len(colormaps) == 0:
+ raise ValueError("Cannot set preferred colormaps to an empty list")
+
+ global _PREFERRED_COLORMAPS
+ _PREFERRED_COLORMAPS = colormaps
+
+
+# Initialize preferred colormaps
+setPreferredColormaps(('gray', 'reversed gray',
+ 'temperature', 'red', 'green', 'blue', 'jet',
+ 'viridis', 'magma', 'inferno', 'plasma',
+ 'hsv'))
diff --git a/silx/gui/plot/ColormapDialog.py b/silx/gui/plot/ColormapDialog.py
index 748dd72..4aefab6 100644
--- a/silx/gui/plot/ColormapDialog.py
+++ b/silx/gui/plot/ColormapDialog.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -31,12 +31,14 @@ To run the following sample code, a QApplication must be initialized.
Create the colormap dialog and set the colormap description and data range:
>>> from silx.gui.plot.ColormapDialog import ColormapDialog
+>>> from silx.gui.plot.Colormap import Colormap
>>> dialog = ColormapDialog()
+>>> colormap = Colormap(name='red', normalization='log',
+... vmin=1., vmax=2.)
->>> dialog.setColormap(name='red', normalization='log',
-... autoscale=False, vmin=1., vmax=2.)
->>> dialog.setDataRange(1., 100.) # This scale the width of the plot area
+>>> dialog.setColormap(colormap)
+>>> colormap.setVRange(1., 100.) # This scale the width of the plot area
>>> dialog.show()
Get the colormap description (compatible with :class:`Plot`) from the dialog:
@@ -59,9 +61,9 @@ The updates of the colormap description are also available through the signal:
from __future__ import division
-__authors__ = ["V.A. Sole", "T. Vincent"]
+__authors__ = ["V.A. Sole", "T. Vincent", "H. Payno"]
__license__ = "MIT"
-__date__ = "02/10/2017"
+__date__ = "09/02/2018"
import logging
@@ -69,13 +71,162 @@ import logging
import numpy
from .. import qt
-from .Colormap import Colormap
+from .Colormap import Colormap, preferredColormaps
from . import PlotWidget
from silx.gui.widgets.FloatEdit import FloatEdit
+import weakref
+from silx.math.combo import min_max
+from silx.third_party import enum
+from silx.gui import icons
+from silx.math.histogram import Histogramnd
_logger = logging.getLogger(__name__)
+_colormapIconPreview = {}
+
+
+class _BoundaryWidget(qt.QWidget):
+ """Widget to edit a boundary of the colormap (vmin, vmax)"""
+ sigValueChanged = qt.Signal(object)
+ """Signal emitted when value is changed"""
+
+ def __init__(self, parent=None, value=0.0):
+ qt.QWidget.__init__(self, parent=None)
+ self.setLayout(qt.QHBoxLayout())
+ self.layout().setContentsMargins(0, 0, 0, 0)
+ self._numVal = FloatEdit(parent=self, value=value)
+ self.layout().addWidget(self._numVal)
+ self._autoCB = qt.QCheckBox('auto', parent=self)
+ self.layout().addWidget(self._autoCB)
+ self._autoCB.setChecked(False)
+
+ self._autoCB.toggled.connect(self._autoToggled)
+ self.sigValueChanged = self._autoCB.toggled
+ self.textEdited = self._numVal.textEdited
+ self.editingFinished = self._numVal.editingFinished
+ self._dataValue = None
+
+ def isAutoChecked(self):
+ return self._autoCB.isChecked()
+
+ def getValue(self):
+ return None if self._autoCB.isChecked() else self._numVal.value()
+
+ def getFiniteValue(self):
+ if not self._autoCB.isChecked():
+ return self._numVal.value()
+ elif self._dataValue is None:
+ return self._numVal.value()
+ else:
+ return self._dataValue
+
+ def _autoToggled(self, enabled):
+ self._numVal.setEnabled(not enabled)
+ self._updateDisplayedText()
+
+ def _updateDisplayedText(self):
+ # if dataValue is finite
+ if self._autoCB.isChecked() and self._dataValue is not None:
+ old = self._numVal.blockSignals(True)
+ self._numVal.setValue(self._dataValue)
+ self._numVal.blockSignals(old)
+
+ def setDataValue(self, dataValue):
+ self._dataValue = dataValue
+ self._updateDisplayedText()
+
+ def setFiniteValue(self, value):
+ assert(value is not None)
+ old = self._numVal.blockSignals(True)
+ self._numVal.setValue(value)
+ self._numVal.blockSignals(old)
+
+ def setValue(self, value, isAuto=False):
+ self._autoCB.setChecked(isAuto or value is None)
+ if value is not None:
+ self._numVal.setValue(value)
+ self._updateDisplayedText()
+
+
+class _ColormapNameCombox(qt.QComboBox):
+ def __init__(self, parent=None):
+ qt.QComboBox.__init__(self, parent)
+ self.__initItems()
+
+ ORIGINAL_NAME = qt.Qt.UserRole + 1
+
+ def __initItems(self):
+ for colormapName in preferredColormaps():
+ index = self.count()
+ self.addItem(str.title(colormapName))
+ self.setItemIcon(index, self.getIconPreview(colormapName))
+ self.setItemData(index, colormapName, role=self.ORIGINAL_NAME)
+
+ def getIconPreview(self, colormapName):
+ """Return an icon preview from a LUT name.
+
+ This icons are cached into a global structure.
+
+ :param str colormapName: str
+ :rtype: qt.QIcon
+ """
+ if colormapName not in _colormapIconPreview:
+ icon = self.createIconPreview(colormapName)
+ _colormapIconPreview[colormapName] = icon
+ return _colormapIconPreview[colormapName]
+
+ def createIconPreview(self, colormapName):
+ """Create and return an icon preview from a LUT name.
+
+ This icons are cached into a global structure.
+
+ :param str colormapName: Name of the LUT
+ :rtype: qt.QIcon
+ """
+ colormap = Colormap(colormapName)
+ size = 32
+ lut = colormap.getNColors(size)
+ if lut is None or len(lut) == 0:
+ return qt.QIcon()
+
+ pixmap = qt.QPixmap(size, size)
+ painter = qt.QPainter(pixmap)
+ for i in range(size):
+ rgb = lut[i]
+ r, g, b = rgb[0], rgb[1], rgb[2]
+ painter.setPen(qt.QColor(r, g, b))
+ painter.drawPoint(qt.QPoint(i, 0))
+
+ painter.drawPixmap(0, 1, size, size - 1, pixmap, 0, 0, size, 1)
+ painter.end()
+
+ return qt.QIcon(pixmap)
+
+ def getCurrentName(self):
+ return self.itemData(self.currentIndex(), self.ORIGINAL_NAME)
+
+ def findColormap(self, name):
+ return self.findData(name, role=self.ORIGINAL_NAME)
+
+ def setCurrentName(self, name):
+ index = self.findColormap(name)
+ if index < 0:
+ index = self.count()
+ self.addItem(str.title(name))
+ self.setItemIcon(index, self.getIconPreview(name))
+ self.setItemData(index, name, role=self.ORIGINAL_NAME)
+ self.setCurrentIndex(index)
+
+
+@enum.unique
+class _DataInPlotMode(enum.Enum):
+ """Enum for each mode of display of the data in the plot."""
+ NONE = 'none'
+ RANGE = 'range'
+ HISTOGRAM = 'histogram'
+
+
class ColormapDialog(qt.QDialog):
"""A QDialog widget to set the colormap.
@@ -83,57 +234,62 @@ class ColormapDialog(qt.QDialog):
:param str title: The QDialog title
"""
- sigColormapChanged = qt.Signal(Colormap)
- """Signal triggered when the colormap is changed.
-
- It provides a dict describing the colormap to the slot.
- This dict can be used with :class:`Plot`.
- """
+ visibleChanged = qt.Signal(bool)
+ """This event is sent when the dialog visibility change"""
def __init__(self, parent=None, title="Colormap Dialog"):
qt.QDialog.__init__(self, parent)
self.setWindowTitle(title)
+ self._colormap = None
+ self._data = None
+ self._dataInPlotMode = _DataInPlotMode.RANGE
+
+ self._ignoreColormapChange = False
+ """Used as a semaphore to avoid editing the colormap object when we are
+ only attempt to display it.
+ Used instead of n connect and disconnect of the sigChanged. The
+ disconnection to sigChanged was also limiting when this colormapdialog
+ is used in the colormapaction and associated to the activeImageChanged.
+ (because the activeImageChanged is send when the colormap changed and
+ the self.setcolormap is a callback)
+ """
+
self._histogramData = None
- self._dataRange = None
self._minMaxWasEdited = False
+ self._initialRange = None
+
+ self._dataRange = None
+ """If defined 3-tuple containing information from a data:
+ minimum, positive minimum, maximum"""
- colormaps = [
- 'gray', 'reversed gray',
- 'temperature', 'red', 'green', 'blue', 'jet',
- 'viridis', 'magma', 'inferno', 'plasma']
- if 'hsv' in Colormap.getSupportedColormaps():
- colormaps.append('hsv')
- self._colormapList = tuple(colormaps)
+ self._colormapStoredState = None
# Make the GUI
vLayout = qt.QVBoxLayout(self)
- formWidget = qt.QWidget()
+ formWidget = qt.QWidget(parent=self)
vLayout.addWidget(formWidget)
formLayout = qt.QFormLayout(formWidget)
formLayout.setContentsMargins(10, 10, 10, 10)
formLayout.setSpacing(0)
# Colormap row
- self._comboBoxColormap = qt.QComboBox()
- for cmap in self._colormapList:
- # Capitalize first letters
- cmap = ' '.join(w[0].upper() + w[1:] for w in cmap.split())
- self._comboBoxColormap.addItem(cmap)
- self._comboBoxColormap.activated[int].connect(self._notify)
+ self._comboBoxColormap = _ColormapNameCombox(parent=formWidget)
+ self._comboBoxColormap.currentIndexChanged[int].connect(self._updateName)
formLayout.addRow('Colormap:', self._comboBoxColormap)
# Normalization row
self._normButtonLinear = qt.QRadioButton('Linear')
self._normButtonLinear.setChecked(True)
self._normButtonLog = qt.QRadioButton('Log')
+ self._normButtonLog.toggled.connect(self._activeLogNorm)
normButtonGroup = qt.QButtonGroup(self)
normButtonGroup.setExclusive(True)
normButtonGroup.addButton(self._normButtonLinear)
normButtonGroup.addButton(self._normButtonLog)
- normButtonGroup.buttonClicked[int].connect(self._notify)
+ self._normButtonLinear.toggled[bool].connect(self._updateLinearNorm)
normLayout = qt.QHBoxLayout()
normLayout.setContentsMargins(0, 0, 0, 0)
@@ -143,51 +299,124 @@ class ColormapDialog(qt.QDialog):
formLayout.addRow('Normalization:', normLayout)
- # Range row
- self._rangeAutoscaleButton = qt.QCheckBox('Autoscale')
- self._rangeAutoscaleButton.setChecked(True)
- self._rangeAutoscaleButton.toggled.connect(self._autoscaleToggled)
- self._rangeAutoscaleButton.clicked.connect(self._notify)
- formLayout.addRow('Range:', self._rangeAutoscaleButton)
-
# Min row
- self._minValue = FloatEdit(parent=self, value=1.)
- self._minValue.setEnabled(False)
+ self._minValue = _BoundaryWidget(parent=self, value=1.0)
self._minValue.textEdited.connect(self._minMaxTextEdited)
self._minValue.editingFinished.connect(self._minEditingFinished)
+ self._minValue.sigValueChanged.connect(self._updateMinMax)
formLayout.addRow('\tMin:', self._minValue)
# Max row
- self._maxValue = FloatEdit(parent=self, value=10.)
- self._maxValue.setEnabled(False)
+ self._maxValue = _BoundaryWidget(parent=self, value=10.0)
self._maxValue.textEdited.connect(self._minMaxTextEdited)
+ self._maxValue.sigValueChanged.connect(self._updateMinMax)
self._maxValue.editingFinished.connect(self._maxEditingFinished)
formLayout.addRow('\tMax:', self._maxValue)
# Add plot for histogram
+ self._plotToolbar = qt.QToolBar(self)
+ self._plotToolbar.setFloatable(False)
+ self._plotToolbar.setMovable(False)
+ self._plotToolbar.setIconSize(qt.QSize(8, 8))
+ self._plotToolbar.setStyleSheet("QToolBar { border: 0px }")
+ self._plotToolbar.setOrientation(qt.Qt.Vertical)
+
+ group = qt.QActionGroup(self._plotToolbar)
+ group.setExclusive(True)
+
+ action = qt.QAction("Nothing", self)
+ action.setToolTip("No range nor histogram are displayed. No extra computation have to be done.")
+ action.setIcon(icons.getQIcon('colormap-none'))
+ action.setCheckable(True)
+ action.setData(_DataInPlotMode.NONE)
+ action.setChecked(action.data() == self._dataInPlotMode)
+ self._plotToolbar.addAction(action)
+ group.addAction(action)
+ action = qt.QAction("Data range", self)
+ action.setToolTip("Display the data range within the colormap range. A fast data processing have to be done.")
+ action.setIcon(icons.getQIcon('colormap-range'))
+ action.setCheckable(True)
+ action.setData(_DataInPlotMode.RANGE)
+ action.setChecked(action.data() == self._dataInPlotMode)
+ self._plotToolbar.addAction(action)
+ group.addAction(action)
+ action = qt.QAction("Histogram", self)
+ action.setToolTip("Display the data histogram within the colormap range. A slow data processing have to be done. ")
+ action.setIcon(icons.getQIcon('colormap-histogram'))
+ action.setCheckable(True)
+ action.setData(_DataInPlotMode.HISTOGRAM)
+ action.setChecked(action.data() == self._dataInPlotMode)
+ self._plotToolbar.addAction(action)
+ group.addAction(action)
+ group.triggered.connect(self._displayDataInPlotModeChanged)
+
+ self._plotBox = qt.QWidget(self)
self._plotInit()
- vLayout.addWidget(self._plot)
- # Close button
- buttonsWidget = qt.QWidget()
- vLayout.addWidget(buttonsWidget)
+ plotBoxLayout = qt.QHBoxLayout()
+ plotBoxLayout.setContentsMargins(0, 0, 0, 0)
+ plotBoxLayout.setSpacing(2)
+ plotBoxLayout.addWidget(self._plotToolbar)
+ plotBoxLayout.addWidget(self._plot)
+ plotBoxLayout.setSizeConstraint(qt.QLayout.SetMinimumSize)
+ self._plotBox.setLayout(plotBoxLayout)
+ vLayout.addWidget(self._plotBox)
+
+ # define modal buttons
+ types = qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel
+ self._buttonsModal = qt.QDialogButtonBox(parent=self)
+ self._buttonsModal.setStandardButtons(types)
+ self.layout().addWidget(self._buttonsModal)
+ self._buttonsModal.accepted.connect(self.accept)
+ self._buttonsModal.rejected.connect(self.reject)
+
+ # define non modal buttons
+ types = qt.QDialogButtonBox.Close | qt.QDialogButtonBox.Reset
+ self._buttonsNonModal = qt.QDialogButtonBox(parent=self)
+ self._buttonsNonModal.setStandardButtons(types)
+ self.layout().addWidget(self._buttonsNonModal)
+ self._buttonsNonModal.button(qt.QDialogButtonBox.Close).clicked.connect(self.accept)
+ self._buttonsNonModal.button(qt.QDialogButtonBox.Reset).clicked.connect(self.resetColormap)
+
+ # Set the colormap to default values
+ self.setColormap(Colormap(name='gray', normalization='linear',
+ vmin=None, vmax=None))
- buttonsLayout = qt.QHBoxLayout(buttonsWidget)
+ self.setModal(self.isModal())
- okButton = qt.QPushButton('OK')
- okButton.clicked.connect(self.accept)
- buttonsLayout.addWidget(okButton)
+ vLayout.setSizeConstraint(qt.QLayout.SetMinimumSize)
+ self.setFixedSize(self.sizeHint())
+ self._applyColormap()
- cancelButton = qt.QPushButton('Cancel')
- cancelButton.clicked.connect(self.reject)
- buttonsLayout.addWidget(cancelButton)
+ def showEvent(self, event):
+ self.visibleChanged.emit(True)
+ super(ColormapDialog, self).showEvent(event)
- # colormap window can not be resized
- self.setFixedSize(vLayout.minimumSize())
+ def closeEvent(self, event):
+ if not self.isModal():
+ self.accept()
+ super(ColormapDialog, self).closeEvent(event)
- # Set the colormap to default values
- self.setColormap(name='gray', normalization='linear',
- autoscale=True, vmin=1., vmax=10.)
+ def hideEvent(self, event):
+ self.visibleChanged.emit(False)
+ super(ColormapDialog, self).hideEvent(event)
+
+ def close(self):
+ self.accept()
+ qt.QDialog.close(self)
+
+ def setModal(self, modal):
+ assert type(modal) is bool
+ self._buttonsNonModal.setVisible(not modal)
+ self._buttonsModal.setVisible(modal)
+ qt.QDialog.setModal(self, modal)
+
+ def exec_(self):
+ wasModal = self.isModal()
+ self.setModal(True)
+ result = super(ColormapDialog, self).exec_()
+ self.setModal(wasModal)
+ return result
def _plotInit(self):
"""Init the plot to display the range and the values"""
@@ -199,51 +428,63 @@ class ColormapDialog(qt.QDialog):
self._plot.setActiveCurveHandling(False)
self._plot.setMinimumSize(qt.QSize(250, 200))
self._plot.sigPlotSignal.connect(self._plotSlot)
- self._plot.hide()
self._plotUpdate()
+ def sizeHint(self):
+ return self.layout().minimumSize()
+
def _plotUpdate(self, updateMarkers=True):
"""Update the plot content
:param bool updateMarkers: True to update markers, False otherwith
"""
- dataRange = self.getDataRange()
-
- if dataRange is None:
- if self._plot.isVisibleTo(self):
- self._plot.setVisible(False)
- self.setFixedSize(self.layout().minimumSize())
+ colormap = self.getColormap()
+ if colormap is None:
+ if self._plotBox.isVisibleTo(self):
+ self._plotBox.setVisible(False)
+ self.setFixedSize(self.sizeHint())
return
- if not self._plot.isVisibleTo(self):
- self._plot.setVisible(True)
- self.setFixedSize(self.layout().minimumSize())
+ if not self._plotBox.isVisibleTo(self):
+ self._plotBox.setVisible(True)
+ self.setFixedSize(self.sizeHint())
- dataMin, dataMax = dataRange
- marge = (abs(dataMax) + abs(dataMin)) / 6.0
- minmd = dataMin - marge
- maxpd = dataMax + marge
+ minData, maxData = self._minValue.getFiniteValue(), self._maxValue.getFiniteValue()
+ if minData > maxData:
+ # avoid a full collapse
+ minData, maxData = maxData, minData
+ minimum = minData
+ maximum = maxData
- start, end = self._minValue.value(), self._maxValue.value()
+ if self._dataRange is not None:
+ minRange = self._dataRange[0]
+ maxRange = self._dataRange[2]
+ minimum = min(minimum, minRange)
+ maximum = max(maximum, maxRange)
- if start <= end:
- x = [minmd, start, end, maxpd]
- y = [0, 0, 1, 1]
+ if self._histogramData is not None:
+ minHisto = self._histogramData[1][0]
+ maxHisto = self._histogramData[1][-1]
+ minimum = min(minimum, minHisto)
+ maximum = max(maximum, maxHisto)
- else:
- x = [minmd, end, start, maxpd]
- y = [1, 1, 0, 0]
-
- # Display the colormap on the side
- # colormap = {'name': self.getColormap()['name'],
- # 'normalization': self.getColormap()['normalization'],
- # 'autoscale': True, 'vmin': 1., 'vmax': 256.}
- # self._plot.addImage((1 + numpy.arange(256)).reshape(256, -1),
- # xScale=(minmd - marge, marge),
- # yScale=(1., 2./256.),
- # legend='colormap',
- # colormap=colormap)
+ marge = abs(maximum - minimum) / 6.0
+ if marge < 0.0001:
+ # Smaller that the QLineEdit precision
+ marge = 0.0001
+
+ minView, maxView = minimum - marge, maximum + marge
+
+ if updateMarkers:
+ # Save the state in we are not moving the markers
+ self._initialRange = minView, maxView
+ elif self._initialRange is not None:
+ minView = min(minView, self._initialRange[0])
+ maxView = max(maxView, self._initialRange[1])
+
+ x = [minView, minData, maxData, maxView]
+ y = [0, 0, 1, 1]
self._plot.addCurve(x, y,
legend="ConstrainedCurve",
@@ -252,22 +493,24 @@ class ColormapDialog(qt.QDialog):
linestyle='-',
resetzoom=False)
- draggable = not self._rangeAutoscaleButton.isChecked()
-
if updateMarkers:
+ minDraggable = (self._colormap().isEditable() and
+ not self._minValue.isAutoChecked())
self._plot.addXMarker(
- self._minValue.value(),
+ self._minValue.getFiniteValue(),
legend='Min',
text='Min',
- draggable=draggable,
+ draggable=minDraggable,
color='blue',
constraint=self._plotMinMarkerConstraint)
+ maxDraggable = (self._colormap().isEditable() and
+ not self._maxValue.isAutoChecked())
self._plot.addXMarker(
- self._maxValue.value(),
+ self._maxValue.getFiniteValue(),
legend='Max',
text='Max',
- draggable=draggable,
+ draggable=maxDraggable,
color='blue',
constraint=self._plotMaxMarkerConstraint)
@@ -275,11 +518,11 @@ class ColormapDialog(qt.QDialog):
def _plotMinMarkerConstraint(self, x, y):
"""Constraint of the min marker"""
- return min(x, self._maxValue.value()), y
+ return min(x, self._maxValue.getFiniteValue()), y
def _plotMaxMarkerConstraint(self, x, y):
"""Constraint of the max marker"""
- return max(x, self._minValue.value()), y
+ return max(x, self._minValue.getFiniteValue()), y
def _plotSlot(self, event):
"""Handle events from the plot"""
@@ -293,10 +536,139 @@ class ColormapDialog(qt.QDialog):
# This will recreate the markers while interacting...
# It might break if marker interaction is changed
if event['event'] == 'markerMoved':
- self._notify()
+ self._initialRange = None
+ self._updateMinMax()
else:
self._plotUpdate(updateMarkers=False)
+ @staticmethod
+ def computeDataRange(data):
+ """Compute the data range as used by :meth:`setDataRange`.
+
+ :param data: The data to process
+ :rtype: Tuple(float, float, float)
+ """
+ if data is None or len(data) == 0:
+ return None, None, None
+
+ dataRange = min_max(data, min_positive=True, finite=True)
+ if dataRange.minimum is None:
+ # Only non-finite data
+ dataRange = None
+
+ if dataRange is not None:
+ min_positive = dataRange.min_positive
+ if min_positive is None:
+ min_positive = float('nan')
+ dataRange = dataRange.minimum, min_positive, dataRange.maximum
+
+ if dataRange is None or len(dataRange) != 3:
+ qt.QMessageBox.warning(
+ None, "No Data",
+ "Image data does not contain any real value")
+ dataRange = 1., 1., 10.
+
+ return dataRange
+
+ @staticmethod
+ def computeHistogram(data):
+ """Compute the data histogram as used by :meth:`setHistogram`.
+
+ :param data: The data to process
+ :rtype: Tuple(List(float),List(float)
+ """
+ _data = data
+ if _data.ndim == 3: # RGB(A) images
+ _logger.info('Converting current image from RGB(A) to grayscale\
+ in order to compute the intensity distribution')
+ _data = (_data[:, :, 0] * 0.299 +
+ _data[:, :, 1] * 0.587 +
+ _data[:, :, 2] * 0.114)
+
+ if len(_data) == 0:
+ return None, None
+
+ xmin, xmax = min_max(_data, min_positive=False, finite=True)
+ nbins = min(256, int(numpy.sqrt(_data.size)))
+ data_range = xmin, xmax
+
+ # bad hack: get 256 bins in the case we have a B&W
+ if numpy.issubdtype(_data.dtype, numpy.integer):
+ if nbins > xmax - xmin:
+ nbins = xmax - xmin
+
+ nbins = max(2, nbins)
+ _data = _data.ravel().astype(numpy.float32)
+
+ histogram = Histogramnd(_data, n_bins=nbins, histo_range=data_range)
+ return histogram.histo, histogram.edges[0]
+
+ def _getData(self):
+ if self._data is None:
+ return None
+ return self._data()
+
+ def setData(self, data):
+ """Store the data as a weakref.
+
+ According to the state of the dialog, the data will be used to display
+ the data range or the histogram of the data using :meth:`setDataRange`
+ and :meth:`setHistogram`
+ """
+ oldData = self._getData()
+ if oldData is data:
+ return
+
+ if data is None:
+ self.setDataRange()
+ self.setHistogram()
+ self._data = None
+ return
+
+ self._data = weakref.ref(data, self._dataAboutToFinalize)
+
+ self._updateDataInPlot()
+
+ def _setDataInPlotMode(self, mode):
+ if self._dataInPlotMode == mode:
+ return
+ self._dataInPlotMode = mode
+ self._updateDataInPlot()
+
+ def _displayDataInPlotModeChanged(self, action):
+ mode = action.data()
+ self._setDataInPlotMode(mode)
+
+ def _updateDataInPlot(self):
+ data = self._getData()
+ if data is None:
+ return
+
+ mode = self._dataInPlotMode
+
+ if mode == _DataInPlotMode.NONE:
+ self.setHistogram()
+ self.setDataRange()
+ elif mode == _DataInPlotMode.RANGE:
+ result = self.computeDataRange(data)
+ self.setHistogram()
+ self.setDataRange(*result)
+ elif mode == _DataInPlotMode.HISTOGRAM:
+ # The histogram should be done in a worker thread
+ result = self.computeHistogram(data)
+ self.setHistogram(*result)
+ self.setDataRange()
+
+ def _colormapAboutToFinalize(self, weakrefColormap):
+ """Callback when the data weakref is about to be finalized."""
+ if self._colormap is weakrefColormap:
+ self.setColormap(None)
+
+ def _dataAboutToFinalize(self, weakrefData):
+ """Callback when the data weakref is about to be finalized."""
+ if self._data is weakrefData:
+ self.setData(None)
+
def getHistogram(self):
"""Returns the counts and bin edges of the displayed histogram.
@@ -312,136 +684,243 @@ class ColormapDialog(qt.QDialog):
"""Set the histogram to display.
This update the data range with the bounds of the bins.
- See :meth:`setDataRange`.
:param hist: array-like of counts or None to hide histogram
:param bin_edges: array-like of bins edges or None to hide histogram
"""
if hist is None or bin_edges is None:
self._histogramData = None
- self._plot.remove(legend='Histogram', kind='curve')
- self.setDataRange() # Remove data range
-
+ self._plot.remove(legend='Histogram', kind='histogram')
else:
hist = numpy.array(hist, copy=True)
bin_edges = numpy.array(bin_edges, copy=True)
self._histogramData = hist, bin_edges
-
- # For now, draw the histogram as a curve
- # using bin centers and normalised counts
- bins_center = 0.5 * (bin_edges[:-1] + bin_edges[1:])
norm_hist = hist / max(hist)
- self._plot.addCurve(bins_center, norm_hist,
- legend="Histogram",
- color='gray',
- symbol='',
- linestyle='-',
- fill=True)
+ self._plot.addHistogram(norm_hist,
+ bin_edges,
+ legend="Histogram",
+ color='gray',
+ align='center',
+ fill=True)
+ self._updateMinMaxData()
- # Update the data range
- self.setDataRange(bin_edges[0], bin_edges[-1])
+ def getColormap(self):
+ """Return the colormap description as a :class:`.Colormap`.
- def getDataRange(self):
- """Returns the data range used for the histogram area.
+ """
+ if self._colormap is None:
+ return None
+ return self._colormap()
- :return: (dataMin, dataMax) or None if no data range is set
- :rtype: 2-tuple of float
+ def resetColormap(self):
"""
- return self._dataRange
+ Reset the colormap state before modification.
- def setDataRange(self, min_=None, max_=None):
+ ..note :: the colormap reference state is the state when set or the
+ state when validated
+ """
+ colormap = self.getColormap()
+ if colormap is not None and self._colormapStoredState is not None:
+ if self._colormap()._toDict() != self._colormapStoredState:
+ self._ignoreColormapChange = True
+ colormap._setFromDict(self._colormapStoredState)
+ self._ignoreColormapChange = False
+ self._applyColormap()
+
+ def setDataRange(self, minimum=None, positiveMin=None, maximum=None):
"""Set the range of data to use for the range of the histogram area.
- :param float min_: The min of the data or None to disable range.
- :param float max_: The max of the data or None to disable range.
+ :param float minimum: The minimum of the data
+ :param float positiveMin: The positive minimum of the data
+ :param float maximum: The maximum of the data
"""
- if min_ is None or max_ is None:
+ if minimum is None or positiveMin is None or maximum is None:
self._dataRange = None
- self._plotUpdate()
-
+ self._plot.remove(legend='Range', kind='histogram')
else:
- min_, max_ = float(min_), float(max_)
- assert min_ <= max_
- self._dataRange = min_, max_
- if self._rangeAutoscaleButton.isChecked():
- self._minValue.setValue(min_)
- self._maxValue.setValue(max_)
- self._notify()
- else:
- self._plotUpdate()
+ hist = numpy.array([1])
+ bin_edges = numpy.array([minimum, maximum])
+ self._plot.addHistogram(hist,
+ bin_edges,
+ legend="Range",
+ color='gray',
+ align='center',
+ fill=True)
+ self._dataRange = minimum, positiveMin, maximum
+ self._updateMinMaxData()
+
+ def _updateMinMaxData(self):
+ """Update the min and max of the data according to the data range and
+ the histogram preset."""
+ colormap = self.getColormap()
+
+ minimum = float("+inf")
+ maximum = float("-inf")
+
+ if colormap is not None and colormap.getNormalization() == colormap.LOGARITHM:
+ # find a range in the positive part of the data
+ if self._dataRange is not None:
+ minimum = min(minimum, self._dataRange[1])
+ maximum = max(maximum, self._dataRange[2])
+ if self._histogramData is not None:
+ positives = list(filter(lambda x: x > 0, self._histogramData[1]))
+ if len(positives) > 0:
+ minimum = min(minimum, positives[0])
+ maximum = max(maximum, positives[-1])
+ else:
+ if self._dataRange is not None:
+ minimum = min(minimum, self._dataRange[0])
+ maximum = max(maximum, self._dataRange[2])
+ if self._histogramData is not None:
+ minimum = min(minimum, self._histogramData[1][0])
+ maximum = max(maximum, self._histogramData[1][-1])
+
+ if not numpy.isfinite(minimum):
+ minimum = None
+ if not numpy.isfinite(maximum):
+ maximum = None
+
+ self._minValue.setDataValue(minimum)
+ self._maxValue.setDataValue(maximum)
+ self._plotUpdate()
- def getColormap(self):
- """Return the colormap description as a :class:`.Colormap`.
+ def accept(self):
+ self.storeCurrentState()
+ qt.QDialog.accept(self)
+ def storeCurrentState(self):
+ """
+ save the current value sof the colormap if the user want to undo is
+ modifications
"""
- isNormLinear = self._normButtonLinear.isChecked()
- if self._rangeAutoscaleButton.isChecked():
- vmin = None
- vmax = None
+ colormap = self.getColormap()
+ if colormap is not None:
+ self._colormapStoredState = colormap._toDict()
else:
- vmin = self._minValue.value()
- vmax = self._maxValue.value()
- norm = Colormap.LINEAR if isNormLinear else Colormap.LOGARITHM
- colormap = Colormap(
- name=str(self._comboBoxColormap.currentText()).lower(),
- normalization=norm,
- vmin=vmin,
- vmax=vmax)
- return colormap
-
- def setColormap(self, name=None, normalization=None,
- autoscale=None, vmin=None, vmax=None, colors=None):
- """Set the colormap description
+ self._colormapStoredState = None
- If some arguments are not provided, the current values are used.
+ def reject(self):
+ self.resetColormap()
+ qt.QDialog.reject(self)
- :param str name: The name of the colormap
- :param str normalization: 'linear' or 'log'
- :param bool autoscale: Toggle colormap range autoscale
- :param float vmin: The min value, ignored if autoscale is True
- :param float vmax: The max value, ignored if autoscale is True
+ def setColormap(self, colormap):
+ """Set the colormap description
+
+ :param :class:`Colormap` colormap: the colormap to edit
"""
- if name is not None:
- assert name in self._colormapList
- index = self._colormapList.index(name)
- self._comboBoxColormap.setCurrentIndex(index)
-
- if normalization is not None:
- assert normalization in Colormap.NORMALIZATIONS
- self._normButtonLinear.setChecked(normalization == Colormap.LINEAR)
- self._normButtonLog.setChecked(normalization == Colormap.LOGARITHM)
-
- if vmin is not None:
- self._minValue.setValue(vmin)
-
- if vmax is not None:
- self._maxValue.setValue(vmax)
-
- if autoscale is not None:
- self._rangeAutoscaleButton.setChecked(autoscale)
- if autoscale:
- dataRange = self.getDataRange()
- if dataRange is not None:
- self._minValue.setValue(dataRange[0])
- self._maxValue.setValue(dataRange[1])
-
- # Do it once for all the changes
- self._notify()
-
- def _notify(self, *args, **kwargs):
- """Emit the signal for colormap change"""
+ assert colormap is None or isinstance(colormap, Colormap)
+ if self._ignoreColormapChange is True:
+ return
+
+ oldColormap = self.getColormap()
+ if oldColormap is colormap:
+ return
+ if oldColormap is not None:
+ oldColormap.sigChanged.disconnect(self._applyColormap)
+
+ if colormap is not None:
+ colormap.sigChanged.connect(self._applyColormap)
+ colormap = weakref.ref(colormap, self._colormapAboutToFinalize)
+
+ self._colormap = colormap
+ self.storeCurrentState()
+ self._updateResetButton()
+ self._applyColormap()
+
+ def _updateResetButton(self):
+ resetButton = self._buttonsNonModal.button(qt.QDialogButtonBox.Reset)
+ rStateEnabled = False
+ colormap = self.getColormap()
+ if colormap is not None and colormap.isEditable():
+ # can reset only in the case the colormap changed
+ rStateEnabled = colormap._toDict() != self._colormapStoredState
+ resetButton.setEnabled(rStateEnabled)
+
+ def _applyColormap(self):
+ self._updateResetButton()
+ if self._ignoreColormapChange is True:
+ return
+
+ colormap = self.getColormap()
+ if colormap is None:
+ self._comboBoxColormap.setEnabled(False)
+ self._normButtonLinear.setEnabled(False)
+ self._normButtonLog.setEnabled(False)
+ self._minValue.setEnabled(False)
+ self._maxValue.setEnabled(False)
+ else:
+ self._ignoreColormapChange = True
+
+ if colormap.getName() is not None:
+ name = colormap.getName()
+ self._comboBoxColormap.setCurrentName(name)
+ self._comboBoxColormap.setEnabled(self._colormap().isEditable())
+
+ assert colormap.getNormalization() in Colormap.NORMALIZATIONS
+ self._normButtonLinear.setChecked(
+ colormap.getNormalization() == Colormap.LINEAR)
+ self._normButtonLog.setChecked(
+ colormap.getNormalization() == Colormap.LOGARITHM)
+ vmin = colormap.getVMin()
+ vmax = colormap.getVMax()
+ dataRange = colormap.getColormapRange()
+ self._normButtonLinear.setEnabled(self._colormap().isEditable())
+ self._normButtonLog.setEnabled(self._colormap().isEditable())
+ self._minValue.setValue(vmin or dataRange[0], isAuto=vmin is None)
+ self._maxValue.setValue(vmax or dataRange[1], isAuto=vmax is None)
+ self._minValue.setEnabled(self._colormap().isEditable())
+ self._maxValue.setEnabled(self._colormap().isEditable())
+ self._ignoreColormapChange = False
+
self._plotUpdate()
- self.sigColormapChanged.emit(self.getColormap())
-
- def _autoscaleToggled(self, checked):
- """Handle autoscale changes by enabling/disabling min/max fields"""
- self._minValue.setEnabled(not checked)
- self._maxValue.setEnabled(not checked)
- if checked:
- dataRange = self.getDataRange()
- if dataRange is not None:
- self._minValue.setValue(dataRange[0])
- self._maxValue.setValue(dataRange[1])
+
+ def _updateMinMax(self):
+ if self._ignoreColormapChange is True:
+ return
+
+ vmin = self._minValue.getFiniteValue()
+ vmax = self._maxValue.getFiniteValue()
+ if vmax is not None and vmin is not None and vmax < vmin:
+ # If only one autoscale is checked constraints are too strong
+ # We have to edit a user value anyway it is not requested
+ # TODO: It would be better IMO to disable the auto checkbox before
+ # this case occur (valls)
+ cmin = self._minValue.isAutoChecked()
+ cmax = self._maxValue.isAutoChecked()
+ if cmin is False:
+ self._minValue.setFiniteValue(vmax)
+ if cmax is False:
+ self._maxValue.setFiniteValue(vmin)
+
+ vmin = self._minValue.getValue()
+ vmax = self._maxValue.getValue()
+ self._ignoreColormapChange = True
+ colormap = self._colormap()
+ if colormap is not None:
+ colormap.setVRange(vmin, vmax)
+ self._ignoreColormapChange = False
+ self._plotUpdate()
+ self._updateResetButton()
+
+ def _updateName(self):
+ if self._ignoreColormapChange is True:
+ return
+
+ if self._colormap():
+ self._ignoreColormapChange = True
+ self._colormap().setName(
+ self._comboBoxColormap.getCurrentName())
+ self._ignoreColormapChange = False
+
+ def _updateLinearNorm(self, isNormLinear):
+ if self._ignoreColormapChange is True:
+ return
+
+ if self._colormap():
+ self._ignoreColormapChange = True
+ norm = Colormap.LINEAR if isNormLinear else Colormap.LOGARITHM
+ self._colormap().setNormalization(norm)
+ self._ignoreColormapChange = False
def _minMaxTextEdited(self, text):
"""Handle _minValue and _maxValue textEdited signal"""
@@ -457,9 +936,10 @@ class ColormapDialog(qt.QDialog):
self._minMaxWasEdited = False
# Fix start value
- if self._minValue.value() > self._maxValue.value():
- self._minValue.setValue(self._maxValue.value())
- self._notify()
+ if (self._maxValue.getValue() is not None and
+ self._minValue.getValue() > self._maxValue.getValue()):
+ self._minValue.setValue(self._maxValue.getValue())
+ self._updateMinMax()
def _maxEditingFinished(self):
"""Handle _maxValue editingFinished signal
@@ -471,9 +951,10 @@ class ColormapDialog(qt.QDialog):
self._minMaxWasEdited = False
# Fix end value
- if self._minValue.value() > self._maxValue.value():
- self._maxValue.setValue(self._minValue.value())
- self._notify()
+ if (self._minValue.getValue() is not None and
+ self._minValue.getValue() > self._maxValue.getValue()):
+ self._maxValue.setValue(self._minValue.getValue())
+ self._updateMinMax()
def keyPressEvent(self, event):
"""Override key handling.
@@ -488,3 +969,13 @@ class ColormapDialog(qt.QDialog):
else:
# Use QDialog keyPressEvent
super(ColormapDialog, self).keyPressEvent(event)
+
+ def _activeLogNorm(self, isLog):
+ if self._ignoreColormapChange is True:
+ return
+ if self._colormap():
+ self._ignoreColormapChange = True
+ norm = Colormap.LOGARITHM if isLog is True else Colormap.LINEAR
+ self._colormap().setNormalization(norm)
+ self._ignoreColormapChange = False
+ self._updateMinMaxData()
diff --git a/silx/gui/plot/ComplexImageView.py b/silx/gui/plot/ComplexImageView.py
index 1463293..ebff175 100644
--- a/silx/gui/plot/ComplexImageView.py
+++ b/silx/gui/plot/ComplexImageView.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -32,144 +32,22 @@ from __future__ import absolute_import
__authors__ = ["Vincent Favre-Nicolin", "T. Vincent"]
__license__ = "MIT"
-__date__ = "02/10/2017"
+__date__ = "19/01/2018"
import logging
+import collections
import numpy
from .. import qt, icons
from .PlotWindow import Plot2D
-from .Colormap import Colormap
from . import items
+from .items import ImageComplexData
from silx.gui.widgets.FloatEdit import FloatEdit
_logger = logging.getLogger(__name__)
-_PHASE_COLORMAP = Colormap(
- name='hsv',
- vmin=-numpy.pi,
- vmax=numpy.pi)
-"""Colormap to use for phase"""
-
-# Complex colormap functions
-
-def _phase2rgb(data):
- """Creates RGBA image with colour-coded phase.
-
- :param numpy.ndarray data: The data to convert
- :return: Array of RGBA colors
- :rtype: numpy.ndarray
- """
- if data.size == 0:
- return numpy.zeros((0, 0, 4), dtype=numpy.uint8)
-
- phase = numpy.angle(data)
- return _PHASE_COLORMAP.applyToData(phase)
-
-
-def _complex2rgbalog(data, amin=0., dlogs=2, smax=None):
- """Returns RGBA colors: colour-coded phases and log10(amplitude) in alpha.
-
- :param numpy.ndarray data: the complex data array to convert to RGBA
- :param float amin: the minimum value for the alpha channel
- :param float dlogs: amplitude range displayed, in log10 units
- :param float smax:
- if specified, all values above max will be displayed with an alpha=1
- """
- if data.size == 0:
- return numpy.zeros((0, 0, 4), dtype=numpy.uint8)
-
- rgba = _phase2rgb(data)
- sabs = numpy.absolute(data)
- if smax is not None:
- sabs[sabs > smax] = smax
- a = numpy.log10(sabs + 1e-20)
- a -= a.max() - dlogs # display dlogs orders of magnitude
- rgba[..., 3] = 255 * (amin + a / dlogs * (1 - amin) * (a > 0))
- return rgba
-
-
-def _complex2rgbalin(data, gamma=1.0, smax=None):
- """Returns RGBA colors: colour-coded phase and linear amplitude in alpha.
-
- :param numpy.ndarray data:
- :param float gamma: Optional exponent gamma applied to the amplitude
- :param float smax:
- """
- if data.size == 0:
- return numpy.zeros((0, 0, 4), dtype=numpy.uint8)
-
- rgba = _phase2rgb(data)
- a = numpy.absolute(data)
- if smax is not None:
- a[a > smax] = smax
- a /= a.max()
- rgba[..., 3] = 255 * a**gamma
- return rgba
-
-
-# Dedicated plot item
-
-class _ImageComplexData(items.ImageData):
- """Specific plot item to force colormap when using complex colormap.
-
- This is returning the specific colormap when displaying
- colored phase + amplitude.
- """
-
- def __init__(self):
- super(_ImageComplexData, self).__init__()
- self._readOnlyColormap = False
- self._mode = 'absolute'
- self._colormaps = { # Default colormaps for all modes
- 'absolute': Colormap(),
- 'phase': _PHASE_COLORMAP.copy(),
- 'real': Colormap(),
- 'imaginary': Colormap(),
- 'amplitude_phase': _PHASE_COLORMAP.copy(),
- 'log10_amplitude_phase': _PHASE_COLORMAP.copy(),
- }
-
- _READ_ONLY_MODES = 'amplitude_phase', 'log10_amplitude_phase'
- """Modes that requires a read-only colormap."""
-
- def setVisualizationMode(self, mode):
- """Set the visualization mode to use.
-
- :param str mode:
- """
- mode = str(mode)
- assert mode in self._colormaps
-
- if mode != self._mode:
- # Save current colormap
- self._colormaps[self._mode] = self.getColormap()
- self._mode = mode
-
- # Set colormap for new mode
- self.setColormap(self._colormaps[mode])
-
- def getVisualizationMode(self):
- """Returns the visualization mode in use."""
- return self._mode
-
- def _isReadOnlyColormap(self):
- """Returns True if colormap should not be modified."""
- return self.getVisualizationMode() in self._READ_ONLY_MODES
-
- def setColormap(self, colormap):
- if not self._isReadOnlyColormap():
- super(_ImageComplexData, self).setColormap(colormap)
-
- def getColormap(self):
- if self._isReadOnlyColormap():
- return _PHASE_COLORMAP.copy()
- else:
- return super(_ImageComplexData, self).getColormap()
-
-
# Widgets
class _AmplitudeRangeDialog(qt.QDialog):
@@ -291,13 +169,19 @@ class _ComplexDataToolButton(qt.QToolButton):
:param plot: The :class:`ComplexImageView` to control
"""
- _MODES = [
- ('absolute', 'math-amplitude', 'Amplitude'),
- ('phase', 'math-phase', 'Phase'),
- ('real', 'math-real', 'Real part'),
- ('imaginary', 'math-imaginary', 'Imaginary part'),
- ('amplitude_phase', 'math-phase-color', 'Amplitude and Phase'),
- ('log10_amplitude_phase', 'math-phase-color-log', 'Log10(Amp.) and Phase')]
+ _MODES = collections.OrderedDict([
+ (ImageComplexData.Mode.ABSOLUTE, ('math-amplitude', 'Amplitude')),
+ (ImageComplexData.Mode.SQUARE_AMPLITUDE,
+ ('math-square-amplitude', 'Square amplitude')),
+ (ImageComplexData.Mode.PHASE, ('math-phase', 'Phase')),
+ (ImageComplexData.Mode.REAL, ('math-real', 'Real part')),
+ (ImageComplexData.Mode.IMAGINARY,
+ ('math-imaginary', 'Imaginary part')),
+ (ImageComplexData.Mode.AMPLITUDE_PHASE,
+ ('math-phase-color', 'Amplitude and Phase')),
+ (ImageComplexData.Mode.LOG10_AMPLITUDE_PHASE,
+ ('math-phase-color-log', 'Log10(Amp.) and Phase'))
+ ])
_RANGE_DIALOG_TEXT = 'Set Amplitude Range...'
@@ -311,8 +195,10 @@ class _ComplexDataToolButton(qt.QToolButton):
menu.triggered.connect(self._triggered)
self.setMenu(menu)
- for _, icon, text in self._MODES:
+ for mode, info in self._MODES.items():
+ icon, text = info
action = qt.QAction(icons.getQIcon(icon), text, self)
+ action.setData(mode)
action.setIconVisibleInMenu(True)
menu.addAction(action)
@@ -328,13 +214,10 @@ class _ComplexDataToolButton(qt.QToolButton):
def _modeChanged(self, mode):
"""Handle change of visualization modes"""
- for actionMode, icon, text in self._MODES:
- if actionMode == mode:
- self.setIcon(icons.getQIcon(icon))
- self.setToolTip('Display the ' + text.lower())
- break
-
- self._rangeDialogAction.setEnabled(mode == 'log10_amplitude_phase')
+ icon, text = self._MODES[mode]
+ self.setIcon(icons.getQIcon(icon))
+ self.setToolTip('Display the ' + text.lower())
+ self._rangeDialogAction.setEnabled(mode == ImageComplexData.Mode.LOG10_AMPLITUDE_PHASE)
def _triggered(self, action):
"""Handle triggering of menu actions"""
@@ -360,9 +243,9 @@ class _ComplexDataToolButton(qt.QToolButton):
dialog.sigRangeChanged.disconnect(self._rangeChanged)
else: # update mode
- for mode, _, text in self._MODES:
- if actionText == text:
- self._plot2DComplex.setVisualizationMode(mode)
+ mode = action.data()
+ if isinstance(mode, ImageComplexData.Mode):
+ self._plot2DComplex.setVisualizationMode(mode)
def _rangeChanged(self, range_):
"""Handle updates of range in the dialog"""
@@ -375,10 +258,13 @@ class ComplexImageView(qt.QWidget):
:param parent: See :class:`QMainWindow`
"""
+ Mode = ImageComplexData.Mode
+ """Also expose the modes inside the class"""
+
sigDataChanged = qt.Signal()
"""Signal emitted when data has changed."""
- sigVisualizationModeChanged = qt.Signal(str)
+ sigVisualizationModeChanged = qt.Signal(object)
"""Signal emitted when the visualization mode has changed.
It provides the new visualization mode.
@@ -389,11 +275,6 @@ class ComplexImageView(qt.QWidget):
if parent is None:
self.setWindowTitle('ComplexImageView')
- self._mode = 'absolute'
- self._amplitudeRangeInfo = None, 2
- self._data = numpy.zeros((0, 0), dtype=numpy.complex)
- self._displayedData = numpy.zeros((0, 0), dtype=numpy.float)
-
self._plot2D = Plot2D(self)
layout = qt.QHBoxLayout(self)
@@ -403,10 +284,9 @@ class ComplexImageView(qt.QWidget):
self.setLayout(layout)
# Create and add image to the plot
- self._plotImage = _ImageComplexData()
+ self._plotImage = ImageComplexData()
self._plotImage._setLegend('__ComplexImageView__complex_image__')
- self._plotImage.setData(self._displayedData)
- self._plotImage.setVisualizationMode(self._mode)
+ self._plotImage.sigItemChanged.connect(self._itemChanged)
self._plot2D._add(self._plotImage)
self._plot2D.setActiveImage(self._plotImage.getLegend())
@@ -416,57 +296,18 @@ class ComplexImageView(qt.QWidget):
self._plot2D.insertToolBar(self._plot2D.getProfileToolbar(), toolBar)
+ def _itemChanged(self, event):
+ """Handle item changed signal"""
+ if event is items.ItemChangedType.DATA:
+ self.sigDataChanged.emit()
+ elif event is items.ItemChangedType.VISUALIZATION_MODE:
+ mode = self.getVisualizationMode()
+ self.sigVisualizationModeChanged.emit(mode)
+
def getPlot(self):
"""Return the PlotWidget displaying the data"""
return self._plot2D
- def _convertData(self, data, mode):
- """Convert complex data according to provided mode.
-
- :param numpy.ndarray data: The complex data to convert
- :param str mode: The visualization mode
- :return: The data corresponding to the mode
- :rtype: 2D numpy.ndarray of float or RGBA image
- """
- if mode == 'absolute':
- return numpy.absolute(data)
- elif mode == 'phase':
- return numpy.angle(data)
- elif mode == 'real':
- return numpy.real(data)
- elif mode == 'imaginary':
- return numpy.imag(data)
- elif mode == 'amplitude_phase':
- return _complex2rgbalin(data)
- elif mode == 'log10_amplitude_phase':
- max_, delta = self._getAmplitudeRangeInfo()
- return _complex2rgbalog(data, dlogs=delta, smax=max_)
- else:
- _logger.error(
- 'Unsupported conversion mode: %s, fallback to absolute',
- str(mode))
- return numpy.absolute(data)
-
- def _updatePlot(self):
- """Update the image in the plot"""
-
- mode = self.getVisualizationMode()
-
- self.getPlot().getColormapAction().setDisabled(
- mode in ('amplitude_phase', 'log10_amplitude_phase'))
-
- self._plotImage.setVisualizationMode(mode)
-
- image = self.getDisplayedData(copy=False)
- if mode in ('amplitude_phase', 'log10_amplitude_phase'):
- # Combined view
- absolute = numpy.absolute(self.getData(copy=False))
- self._plotImage.setData(
- absolute, alternative=image, copy=False)
- else:
- self._plotImage.setData(
- image, alternative=None, copy=False)
-
def setData(self, data=None, copy=True):
"""Set the complex data to display.
@@ -476,22 +317,13 @@ class ComplexImageView(qt.QWidget):
"""
if data is None:
data = numpy.zeros((0, 0), dtype=numpy.complex)
- else:
- data = numpy.array(data, copy=copy)
-
- assert data.ndim == 2
- if data.dtype.kind != 'c': # Convert to complex
- data = numpy.array(data, dtype=numpy.complex)
- shape_changed = (self._data.shape != data.shape)
- self._data = data
- self._displayedData = self._convertData(
- data, self.getVisualizationMode())
-
- self._updatePlot()
- if shape_changed:
- self.getPlot().resetZoom()
- self.sigDataChanged.emit()
+ previousData = self._plotImage.getComplexData(copy=False)
+
+ self._plotImage.setData(data, copy=copy)
+
+ if previousData.shape != data.shape:
+ self.getPlot().resetZoom()
def getData(self, copy=True):
"""Get the currently displayed complex data.
@@ -501,7 +333,7 @@ class ComplexImageView(qt.QWidget):
:return: The complex data array.
:rtype: numpy.ndarray of complex with 2 dimensions
"""
- return numpy.array(self._data, copy=copy)
+ return self._plotImage.getComplexData(copy=copy)
def getDisplayedData(self, copy=True):
"""Returns the displayed data depending on the visualization mode
@@ -512,7 +344,12 @@ class ComplexImageView(qt.QWidget):
False to return internal data (do not modify!)
:rtype: numpy.ndarray of float with 2 dims or RGBA image (uint8).
"""
- return numpy.array(self._displayedData, copy=copy)
+ mode = self.getVisualizationMode()
+ if mode in (self.Mode.AMPLITUDE_PHASE,
+ self.Mode.LOG10_AMPLITUDE_PHASE):
+ return self._plotImage.getRgbaImageData(copy=copy)
+ else:
+ return self._plotImage.getData(copy=copy)
@staticmethod
def getSupportedVisualizationModes():
@@ -530,12 +367,7 @@ class ComplexImageView(qt.QWidget):
:rtype: tuple of str
"""
- return ('absolute',
- 'phase',
- 'real',
- 'imaginary',
- 'amplitude_phase',
- 'log10_amplitude_phase')
+ return tuple(ImageComplexData.Mode)
def setVisualizationMode(self, mode):
"""Set the mode of visualization of the complex data.
@@ -545,20 +377,14 @@ class ComplexImageView(qt.QWidget):
:param str mode: The mode to use.
"""
- assert mode in self.getSupportedVisualizationModes()
- if mode != self._mode:
- self._mode = mode
- self._displayedData = self._convertData(
- self.getData(copy=False), mode)
- self._updatePlot()
- self.sigVisualizationModeChanged.emit(mode)
+ self._plotImage.setVisualizationMode(mode)
def getVisualizationMode(self):
"""Get the current visualization mode of the complex data.
- :rtype: str
+ :rtype: Mode
"""
- return self._mode
+ return self._plotImage.getVisualizationMode()
def _setAmplitudeRangeInfo(self, max_=None, delta=2):
"""Set the amplitude range to display for 'log10_amplitude_phase' mode.
@@ -567,39 +393,35 @@ class ComplexImageView(qt.QWidget):
If None it autoscales to data max.
:param float delta: Delta range in log10 to display
"""
- self._amplitudeRangeInfo = max_, float(delta)
- mode = self.getVisualizationMode()
- if mode == 'log10_amplitude_phase':
- self._displayedData = self._convertData(
- self.getData(copy=False), mode)
- self._updatePlot()
+ self._plotImage._setAmplitudeRangeInfo(max_, delta)
def _getAmplitudeRangeInfo(self):
"""Returns the amplitude range to use for 'log10_amplitude_phase' mode.
:return: (max, delta), if max is None, then it autoscales to data max
:rtype: 2-tuple"""
- return self._amplitudeRangeInfo
+ return self._plotImage._getAmplitudeRangeInfo()
# Image item proxy
- def setColormap(self, colormap):
+ def setColormap(self, colormap, mode=None):
"""Set the colormap to use for amplitude, phase, real or imaginary.
WARNING: This colormap is not used when displaying both
amplitude and phase.
- :param Colormap colormap: The colormap
+ :param ~silx.gui.plot.Colormap.Colormap colormap: The colormap
+ :param Mode mode: If specified, set the colormap of this specific mode
"""
- self._plotImage.setColormap(colormap)
+ self._plotImage.setColormap(colormap, mode)
- def getColormap(self):
+ def getColormap(self, mode=None):
"""Returns the colormap used to display the data.
- :rtype: Colormap
+ :param Mode mode: If specified, set the colormap of this specific mode
+ :rtype: ~silx.gui.plot.Colormap.Colormap
"""
- # Returns internal colormap and bypass forcing colormap
- return items.ImageData.getColormap(self._plotImage)
+ return self._plotImage.getColormap(mode=mode)
def getOrigin(self):
"""Returns the offset from origin at which to display the image.
diff --git a/silx/gui/plot/CurvesROIWidget.py b/silx/gui/plot/CurvesROIWidget.py
index 4b10cd6..ccb6866 100644
--- a/silx/gui/plot/CurvesROIWidget.py
+++ b/silx/gui/plot/CurvesROIWidget.py
@@ -46,7 +46,7 @@ ROI are defined by :
__authors__ = ["V.A. Sole", "T. Vincent"]
__license__ = "MIT"
-__date__ = "27/06/2017"
+__date__ = "13/11/2017"
from collections import OrderedDict
@@ -57,6 +57,8 @@ import sys
import numpy
from silx.io import dictdump
+from silx.utils import deprecation
+
from .. import icons, qt
@@ -84,10 +86,14 @@ class CurvesROIWidget(qt.QWidget):
'rowheader'
"""
- def __init__(self, parent=None, name=None):
+ sigROISignal = qt.Signal(object)
+
+ def __init__(self, parent=None, name=None, plot=None):
super(CurvesROIWidget, self).__init__(parent)
if name is not None:
self.setWindowTitle(name)
+ assert plot is not None
+ self.plot = plot
layout = qt.QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
@@ -151,6 +157,19 @@ class CurvesROIWidget(qt.QWidget):
self.saveButton.clicked.connect(self._save)
self.roiTable.sigROITableSignal.connect(self._forward)
+ self.currentROI = None
+ self._middleROIMarkerFlag = False
+ self._isConnected = False # True if connected to plot signals
+ self._isInit = False
+
+ def showEvent(self, event):
+ self._visibilityChangedHandler(visible=True)
+ qt.QWidget.showEvent(self, event)
+
+ def hideEvent(self, event):
+ self._visibilityChangedHandler(visible=False)
+ qt.QWidget.hideEvent(self, event)
+
@property
def roiFileDir(self):
"""The directory from which to load/save ROI from/to files."""
@@ -214,6 +233,19 @@ class CurvesROIWidget(qt.QWidget):
return OrderedDict([(name, roidict[name]) for name in ordered_roilist])
+ def setMiddleROIMarkerFlag(self, flag=True):
+ """Activate or deactivate middle marker.
+
+ This allows shifting both min and max limits at once, by dragging
+ a marker located in the middle.
+
+ :param bool flag: True to activate middle ROI marker
+ """
+ if flag:
+ self._middleROIMarkerFlag = True
+ else:
+ self._middleROIMarkerFlag = False
+
def _add(self):
"""Add button clicked handler"""
ddict = {}
@@ -365,6 +397,322 @@ class CurvesROIWidget(qt.QWidget):
"""Set the header text of this widget"""
self.headerLabel.setText("<b>%s<\b>" % text)
+ def _roiSignal(self, ddict):
+ """Handle ROI widget signal"""
+ _logger.debug("CurvesROIWidget._roiSignal %s", str(ddict))
+ if ddict['event'] == "AddROI":
+ xmin, xmax = self.plot.getXAxis().getLimits()
+ fromdata = xmin + 0.25 * (xmax - xmin)
+ todata = xmin + 0.75 * (xmax - xmin)
+ self.plot.remove('ROI min', kind='marker')
+ self.plot.remove('ROI max', kind='marker')
+ if self._middleROIMarkerFlag:
+ self.plot.remove('ROI middle', kind='marker')
+ roiList, roiDict = self.roiTable.getROIListAndDict()
+ nrois = len(roiList)
+ if nrois == 0:
+ newroi = "ICR"
+ fromdata, dummy0, todata, dummy1 = self._getAllLimits()
+ draggable = False
+ color = 'black'
+ else:
+ for i in range(nrois):
+ i += 1
+ newroi = "newroi %d" % i
+ if newroi not in roiList:
+ break
+ color = 'blue'
+ draggable = True
+ self.plot.addXMarker(fromdata,
+ legend='ROI min',
+ text='ROI min',
+ color=color,
+ draggable=draggable)
+ self.plot.addXMarker(todata,
+ legend='ROI max',
+ text='ROI max',
+ color=color,
+ draggable=draggable)
+ if draggable and self._middleROIMarkerFlag:
+ pos = 0.5 * (fromdata + todata)
+ self.plot.addXMarker(pos,
+ legend='ROI middle',
+ text="",
+ color='yellow',
+ draggable=draggable)
+ roiList.append(newroi)
+ roiDict[newroi] = {}
+ if newroi == "ICR":
+ roiDict[newroi]['type'] = "Default"
+ else:
+ roiDict[newroi]['type'] = self.plot.getXAxis().getLabel()
+ roiDict[newroi]['from'] = fromdata
+ roiDict[newroi]['to'] = todata
+ self.roiTable.fillFromROIDict(roilist=roiList,
+ roidict=roiDict,
+ currentroi=newroi)
+ self.currentROI = newroi
+ self.calculateRois()
+ elif ddict['event'] in ['DelROI', "ResetROI"]:
+ self.plot.remove('ROI min', kind='marker')
+ self.plot.remove('ROI max', kind='marker')
+ if self._middleROIMarkerFlag:
+ self.plot.remove('ROI middle', kind='marker')
+ roiList, roiDict = self.roiTable.getROIListAndDict()
+ roiDictKeys = list(roiDict.keys())
+ if len(roiDictKeys):
+ currentroi = roiDictKeys[0]
+ else:
+ # create again the ICR
+ ddict = {"event": "AddROI"}
+ return self._roiSignal(ddict)
+
+ self.roiTable.fillFromROIDict(roilist=roiList,
+ roidict=roiDict,
+ currentroi=currentroi)
+ self.currentROI = currentroi
+
+ elif ddict['event'] == 'LoadROI':
+ self.calculateRois()
+
+ elif ddict['event'] == 'selectionChanged':
+ _logger.debug("Selection changed")
+ self.roilist, self.roidict = self.roiTable.getROIListAndDict()
+ fromdata = ddict['roi']['from']
+ todata = ddict['roi']['to']
+ self.plot.remove('ROI min', kind='marker')
+ self.plot.remove('ROI max', kind='marker')
+ if ddict['key'] == 'ICR':
+ draggable = False
+ color = 'black'
+ else:
+ draggable = True
+ color = 'blue'
+ self.plot.addXMarker(fromdata,
+ legend='ROI min',
+ text='ROI min',
+ color=color,
+ draggable=draggable)
+ self.plot.addXMarker(todata,
+ legend='ROI max',
+ text='ROI max',
+ color=color,
+ draggable=draggable)
+ if draggable and self._middleROIMarkerFlag:
+ pos = 0.5 * (fromdata + todata)
+ self.plot.addXMarker(pos,
+ legend='ROI middle',
+ text="",
+ color='yellow',
+ draggable=True)
+ self.currentROI = ddict['key']
+ if ddict['colheader'] in ['From', 'To']:
+ dict0 = {}
+ dict0['event'] = "SetActiveCurveEvent"
+ dict0['legend'] = self.plot.getActiveCurve(just_legend=1)
+ self.plot.setActiveCurve(dict0['legend'])
+ elif ddict['colheader'] == 'Raw Counts':
+ pass
+ elif ddict['colheader'] == 'Net Counts':
+ pass
+ else:
+ self._emitCurrentROISignal()
+
+ else:
+ _logger.debug("Unknown or ignored event %s", ddict['event'])
+
+ def _getAllLimits(self):
+ """Retrieve the limits based on the curves."""
+ curves = self.plot.getAllCurves()
+ if not curves:
+ return 1.0, 1.0, 100., 100.
+
+ xmin, ymin = None, None
+ xmax, ymax = None, None
+
+ for curve in curves:
+ x = curve.getXData(copy=False)
+ y = curve.getYData(copy=False)
+ if xmin is None:
+ xmin = x.min()
+ else:
+ xmin = min(xmin, x.min())
+ if xmax is None:
+ xmax = x.max()
+ else:
+ xmax = max(xmax, x.max())
+ if ymin is None:
+ ymin = y.min()
+ else:
+ ymin = min(ymin, y.min())
+ if ymax is None:
+ ymax = y.max()
+ else:
+ ymax = max(ymax, y.max())
+
+ return xmin, ymin, xmax, ymax
+
+ @deprecation.deprecated(replacement="calculateRois",
+ reason="CamelCase convention")
+ def calculateROIs(self, *args, **kw):
+ self.calculateRois(*args, **kw)
+
+ def calculateRois(self, roiList=None, roiDict=None):
+ """Compute ROI information"""
+ if roiList is None or roiDict is None:
+ roiList, roiDict = self.roiTable.getROIListAndDict()
+
+ activeCurve = self.plot.getActiveCurve(just_legend=False)
+ if activeCurve is None:
+ xproc = None
+ yproc = None
+ self.setHeader()
+ else:
+ x = activeCurve.getXData(copy=False)
+ y = activeCurve.getYData(copy=False)
+ legend = activeCurve.getLegend()
+ idx = numpy.argsort(x, kind='mergesort')
+ xproc = numpy.take(x, idx)
+ yproc = numpy.take(y, idx)
+ self.setHeader('ROIs of %s' % legend)
+
+ for key in roiList:
+ if key == 'ICR':
+ if xproc is not None:
+ roiDict[key]['from'] = xproc.min()
+ roiDict[key]['to'] = xproc.max()
+ else:
+ roiDict[key]['from'] = 0
+ roiDict[key]['to'] = -1
+ fromData = roiDict[key]['from']
+ toData = roiDict[key]['to']
+ if xproc is not None:
+ idx = numpy.nonzero((fromData <= xproc) &
+ (xproc <= toData))[0]
+ if len(idx):
+ xw = xproc[idx]
+ yw = yproc[idx]
+ rawCounts = yw.sum(dtype=numpy.float)
+ deltaX = xw[-1] - xw[0]
+ deltaY = yw[-1] - yw[0]
+ if deltaX > 0.0:
+ slope = (deltaY / deltaX)
+ background = yw[0] + slope * (xw - xw[0])
+ netCounts = (rawCounts -
+ background.sum(dtype=numpy.float))
+ else:
+ netCounts = 0.0
+ else:
+ rawCounts = 0.0
+ netCounts = 0.0
+ roiDict[key]['rawcounts'] = rawCounts
+ roiDict[key]['netcounts'] = netCounts
+ else:
+ roiDict[key].pop('rawcounts', None)
+ roiDict[key].pop('netcounts', None)
+
+ self.roiTable.fillFromROIDict(
+ roilist=roiList,
+ roidict=roiDict,
+ currentroi=self.currentROI if self.currentROI in roiList else None)
+
+ def _emitCurrentROISignal(self):
+ ddict = {}
+ ddict['event'] = "currentROISignal"
+ _roiList, roiDict = self.roiTable.getROIListAndDict()
+ if self.currentROI in roiDict:
+ ddict['ROI'] = roiDict[self.currentROI]
+ else:
+ self.currentROI = None
+ ddict['current'] = self.currentROI
+ self.sigROISignal.emit(ddict)
+
+ def _handleROIMarkerEvent(self, ddict):
+ """Handle plot signals related to marker events."""
+ if ddict['event'] == 'markerMoved':
+
+ label = ddict['label']
+ if label not in ['ROI min', 'ROI max', 'ROI middle']:
+ return
+
+ roiList, roiDict = self.roiTable.getROIListAndDict()
+ if self.currentROI is None:
+ return
+ if self.currentROI not in roiDict:
+ return
+ x = ddict['x']
+
+ if label == 'ROI min':
+ roiDict[self.currentROI]['from'] = x
+ if self._middleROIMarkerFlag:
+ pos = 0.5 * (roiDict[self.currentROI]['to'] +
+ roiDict[self.currentROI]['from'])
+ self.plot.addXMarker(pos,
+ legend='ROI middle',
+ text='',
+ color='yellow',
+ draggable=True)
+ elif label == 'ROI max':
+ roiDict[self.currentROI]['to'] = x
+ if self._middleROIMarkerFlag:
+ pos = 0.5 * (roiDict[self.currentROI]['to'] +
+ roiDict[self.currentROI]['from'])
+ self.plot.addXMarker(pos,
+ legend='ROI middle',
+ text='',
+ color='yellow',
+ draggable=True)
+ elif label == 'ROI middle':
+ delta = x - 0.5 * (roiDict[self.currentROI]['from'] +
+ roiDict[self.currentROI]['to'])
+ roiDict[self.currentROI]['from'] += delta
+ roiDict[self.currentROI]['to'] += delta
+ self.plot.addXMarker(roiDict[self.currentROI]['from'],
+ legend='ROI min',
+ text='ROI min',
+ color='blue',
+ draggable=True)
+ self.plot.addXMarker(roiDict[self.currentROI]['to'],
+ legend='ROI max',
+ text='ROI max',
+ color='blue',
+ draggable=True)
+ else:
+ return
+ self.calculateRois(roiList, roiDict)
+ self._emitCurrentROISignal()
+
+ def _visibilityChangedHandler(self, visible):
+ """Handle widget's visibility updates.
+
+ It is connected to plot signals only when visible.
+ """
+ if visible:
+ if not self._isInit:
+ # Deferred ROI widget init finalization
+ self._isInit = True
+ self.sigROIWidgetSignal.connect(self._roiSignal)
+ # initialize with the ICR
+ self._roiSignal({'event': "AddROI"})
+
+ if not self._isConnected:
+ self.plot.sigPlotSignal.connect(self._handleROIMarkerEvent)
+ self.plot.sigActiveCurveChanged.connect(
+ self._activeCurveChanged)
+ self._isConnected = True
+
+ self.calculateRois()
+ else:
+ if self._isConnected:
+ self.plot.sigPlotSignal.disconnect(self._handleROIMarkerEvent)
+ self.plot.sigActiveCurveChanged.disconnect(
+ self._activeCurveChanged)
+ self._isConnected = False
+
+ def _activeCurveChanged(self, *args):
+ """Recompute ROIs when active curve changed."""
+ self.calculateRois()
+
class ROITable(qt.QTableWidget):
"""Table widget displaying ROI information.
@@ -622,6 +970,9 @@ class CurvesROIDockWidget(qt.QDockWidget):
:param name: See :class:`QDockWidget`
"""
sigROISignal = qt.Signal(object)
+ """Deprecated signal for backward compatibility with silx < 0.7.
+ Prefer connecting directly to :attr:`CurvesRoiWidget.sigRoiSignal`
+ """
def __init__(self, parent=None, plot=None, name=None):
super(CurvesROIDockWidget, self).__init__(name, parent)
@@ -629,25 +980,24 @@ class CurvesROIDockWidget(qt.QDockWidget):
assert plot is not None
self.plot = plot
- self.currentROI = None
- self._middleROIMarkerFlag = False
-
- self._isConnected = False # True if connected to plot signals
- self._isInit = False
-
- self.roiWidget = CurvesROIWidget(self, name)
+ self.roiWidget = CurvesROIWidget(self, name, plot=plot)
"""Main widget of type :class:`CurvesROIWidget`"""
# convenience methods to offer a simpler API allowing to ignore
# the details of the underlying implementation
- self.calculateROIs = self.calculateRois
+ # (ALL DEPRECATED)
+ self.calculateROIs = self.calculateRois = self.roiWidget.calculateRois
self.setRois = self.roiWidget.setRois
self.getRois = self.roiWidget.getRois
+ self.roiWidget.sigROISignal.connect(self._forwardSigROISignal)
+ self.currentROI = self.roiWidget.currentROI
self.layout().setContentsMargins(0, 0, 0, 0)
self.setWidget(self.roiWidget)
- self.visibilityChanged.connect(self._visibilityChangedHandler)
+ def _forwardSigROISignal(self, ddict):
+ # emit deprecated signal for backward compatibility (silx < 0.7)
+ self.sigROISignal.emit(ddict)
def toggleViewAction(self):
"""Returns a checkable action that shows or closes this widget.
@@ -658,320 +1008,10 @@ class CurvesROIDockWidget(qt.QDockWidget):
action.setIcon(icons.getQIcon('plot-roi'))
return action
- def _visibilityChangedHandler(self, visible):
- """Handle widget's visibilty updates.
-
- It is connected to plot signals only when visible.
- """
- if visible:
- if not self._isInit:
- # Deferred ROI widget init finalization
- self._isInit = True
- self.roiWidget.sigROIWidgetSignal.connect(self._roiSignal)
- # initialize with the ICR
- self._roiSignal({'event': "AddROI"})
-
- if not self._isConnected:
- self.plot.sigPlotSignal.connect(self._handleROIMarkerEvent)
- self.plot.sigActiveCurveChanged.connect(
- self._activeCurveChanged)
- self._isConnected = True
-
- self.calculateROIs()
- else:
- if self._isConnected:
- self.plot.sigPlotSignal.disconnect(self._handleROIMarkerEvent)
- self.plot.sigActiveCurveChanged.disconnect(
- self._activeCurveChanged)
- self._isConnected = False
-
- def _handleROIMarkerEvent(self, ddict):
- """Handle plot signals related to marker events."""
- if ddict['event'] == 'markerMoved':
-
- label = ddict['label']
- if label not in ['ROI min', 'ROI max', 'ROI middle']:
- return
-
- roiList, roiDict = self.roiWidget.getROIListAndDict()
- if self.currentROI is None:
- return
- if self.currentROI not in roiDict:
- return
- x = ddict['x']
-
- if label == 'ROI min':
- roiDict[self.currentROI]['from'] = x
- if self._middleROIMarkerFlag:
- pos = 0.5 * (roiDict[self.currentROI]['to'] +
- roiDict[self.currentROI]['from'])
- self.plot.addXMarker(pos,
- legend='ROI middle',
- text='',
- color='yellow',
- draggable=True)
- elif label == 'ROI max':
- roiDict[self.currentROI]['to'] = x
- if self._middleROIMarkerFlag:
- pos = 0.5 * (roiDict[self.currentROI]['to'] +
- roiDict[self.currentROI]['from'])
- self.plot.addXMarker(pos,
- legend='ROI middle',
- text='',
- color='yellow',
- draggable=True)
- elif label == 'ROI middle':
- delta = x - 0.5 * (roiDict[self.currentROI]['from'] +
- roiDict[self.currentROI]['to'])
- roiDict[self.currentROI]['from'] += delta
- roiDict[self.currentROI]['to'] += delta
- self.plot.addXMarker(roiDict[self.currentROI]['from'],
- legend='ROI min',
- text='ROI min',
- color='blue',
- draggable=True)
- self.plot.addXMarker(roiDict[self.currentROI]['to'],
- legend='ROI max',
- text='ROI max',
- color='blue',
- draggable=True)
- else:
- return
- self.calculateROIs(roiList, roiDict)
- self._emitCurrentROISignal()
-
- def _roiSignal(self, ddict):
- """Handle ROI widget signal"""
- _logger.debug("PlotWindow._roiSignal %s", str(ddict))
- if ddict['event'] == "AddROI":
- xmin, xmax = self.plot.getXAxis().getLimits()
- fromdata = xmin + 0.25 * (xmax - xmin)
- todata = xmin + 0.75 * (xmax - xmin)
- self.plot.remove('ROI min', kind='marker')
- self.plot.remove('ROI max', kind='marker')
- if self._middleROIMarkerFlag:
- self.remove('ROI middle', kind='marker')
- roiList, roiDict = self.roiWidget.getROIListAndDict()
- nrois = len(roiList)
- if nrois == 0:
- newroi = "ICR"
- fromdata, dummy0, todata, dummy1 = self._getAllLimits()
- draggable = False
- color = 'black'
- else:
- for i in range(nrois):
- i += 1
- newroi = "newroi %d" % i
- if newroi not in roiList:
- break
- color = 'blue'
- draggable = True
- self.plot.addXMarker(fromdata,
- legend='ROI min',
- text='ROI min',
- color=color,
- draggable=draggable)
- self.plot.addXMarker(todata,
- legend='ROI max',
- text='ROI max',
- color=color,
- draggable=draggable)
- if draggable and self._middleROIMarkerFlag:
- pos = 0.5 * (fromdata + todata)
- self.plot.addXMarker(pos,
- legend='ROI middle',
- text="",
- color='yellow',
- draggable=draggable)
- roiList.append(newroi)
- roiDict[newroi] = {}
- if newroi == "ICR":
- roiDict[newroi]['type'] = "Default"
- else:
- roiDict[newroi]['type'] = self.plot.getXAxis().getLabel()
- roiDict[newroi]['from'] = fromdata
- roiDict[newroi]['to'] = todata
- self.roiWidget.fillFromROIDict(roilist=roiList,
- roidict=roiDict,
- currentroi=newroi)
- self.currentROI = newroi
- self.calculateROIs()
- elif ddict['event'] in ['DelROI', "ResetROI"]:
- self.plot.remove('ROI min', kind='marker')
- self.plot.remove('ROI max', kind='marker')
- if self._middleROIMarkerFlag:
- self.plot.remove('ROI middle', kind='marker')
- roiList, roiDict = self.roiWidget.getROIListAndDict()
- roiDictKeys = list(roiDict.keys())
- if len(roiDictKeys):
- currentroi = roiDictKeys[0]
- else:
- # create again the ICR
- ddict = {"event": "AddROI"}
- return self._roiSignal(ddict)
-
- self.roiWidget.fillFromROIDict(roilist=roiList,
- roidict=roiDict,
- currentroi=currentroi)
- self.currentROI = currentroi
-
- elif ddict['event'] == 'LoadROI':
- self.calculateROIs()
-
- elif ddict['event'] == 'selectionChanged':
- _logger.debug("Selection changed")
- self.roilist, self.roidict = self.roiWidget.getROIListAndDict()
- fromdata = ddict['roi']['from']
- todata = ddict['roi']['to']
- self.plot.remove('ROI min', kind='marker')
- self.plot.remove('ROI max', kind='marker')
- if ddict['key'] == 'ICR':
- draggable = False
- color = 'black'
- else:
- draggable = True
- color = 'blue'
- self.plot.addXMarker(fromdata,
- legend='ROI min',
- text='ROI min',
- color=color,
- draggable=draggable)
- self.plot.addXMarker(todata,
- legend='ROI max',
- text='ROI max',
- color=color,
- draggable=draggable)
- if draggable and self._middleROIMarkerFlag:
- pos = 0.5 * (fromdata + todata)
- self.plot.addXMarker(pos,
- legend='ROI middle',
- text="",
- color='yellow',
- draggable=True)
- self.currentROI = ddict['key']
- if ddict['colheader'] in ['From', 'To']:
- dict0 = {}
- dict0['event'] = "SetActiveCurveEvent"
- dict0['legend'] = self.plot.getActiveCurve(just_legend=1)
- self.plot.setActiveCurve(dict0['legend'])
- elif ddict['colheader'] == 'Raw Counts':
- pass
- elif ddict['colheader'] == 'Net Counts':
- pass
- else:
- self._emitCurrentROISignal()
-
- else:
- _logger.debug("Unknown or ignored event %s", ddict['event'])
-
- def _activeCurveChanged(self, *args):
- """Recompute ROIs when active curve changed."""
- self.calculateROIs()
-
- def calculateRois(self, roiList=None, roiDict=None):
- """Compute ROI information"""
- if roiList is None or roiDict is None:
- roiList, roiDict = self.roiWidget.getROIListAndDict()
-
- activeCurve = self.plot.getActiveCurve(just_legend=False)
- if activeCurve is None:
- xproc = None
- yproc = None
- self.roiWidget.setHeader()
- else:
- x = activeCurve.getXData(copy=False)
- y = activeCurve.getYData(copy=False)
- legend = activeCurve.getLegend()
- idx = numpy.argsort(x, kind='mergesort')
- xproc = numpy.take(x, idx)
- yproc = numpy.take(y, idx)
- self.roiWidget.setHeader('ROIs of %s' % legend)
-
- for key in roiList:
- if key == 'ICR':
- if xproc is not None:
- roiDict[key]['from'] = xproc.min()
- roiDict[key]['to'] = xproc.max()
- else:
- roiDict[key]['from'] = 0
- roiDict[key]['to'] = -1
- fromData = roiDict[key]['from']
- toData = roiDict[key]['to']
- if xproc is not None:
- idx = numpy.nonzero((fromData <= xproc) &
- (xproc <= toData))[0]
- if len(idx):
- xw = xproc[idx]
- yw = yproc[idx]
- rawCounts = yw.sum(dtype=numpy.float)
- deltaX = xw[-1] - xw[0]
- deltaY = yw[-1] - yw[0]
- if deltaX > 0.0:
- slope = (deltaY / deltaX)
- background = yw[0] + slope * (xw - xw[0])
- netCounts = (rawCounts -
- background.sum(dtype=numpy.float))
- else:
- netCounts = 0.0
- else:
- rawCounts = 0.0
- netCounts = 0.0
- roiDict[key]['rawcounts'] = rawCounts
- roiDict[key]['netcounts'] = netCounts
- else:
- roiDict[key].pop('rawcounts', None)
- roiDict[key].pop('netcounts', None)
-
- self.roiWidget.fillFromROIDict(
- roilist=roiList,
- roidict=roiDict,
- currentroi=self.currentROI if self.currentROI in roiList else None)
-
- def _emitCurrentROISignal(self):
- ddict = {}
- ddict['event'] = "currentROISignal"
- _roiList, roiDict = self.roiWidget.getROIListAndDict()
- if self.currentROI in roiDict:
- ddict['ROI'] = roiDict[self.currentROI]
- else:
- self.currentROI = None
- ddict['current'] = self.currentROI
- self.sigROISignal.emit(ddict)
-
- def _getAllLimits(self):
- """Retrieve the limits based on the curves."""
- curves = self.plot.getAllCurves()
- if not curves:
- return 1.0, 1.0, 100., 100.
-
- xmin, ymin = None, None
- xmax, ymax = None, None
-
- for curve in curves:
- x = curve.getXData(copy=False)
- y = curve.getYData(copy=False)
- if xmin is None:
- xmin = x.min()
- else:
- xmin = min(xmin, x.min())
- if xmax is None:
- xmax = x.max()
- else:
- xmax = max(xmax, x.max())
- if ymin is None:
- ymin = y.min()
- else:
- ymin = min(ymin, y.min())
- if ymax is None:
- ymax = y.max()
- else:
- ymax = max(ymax, y.max())
-
- return xmin, ymin, xmax, ymax
-
def showEvent(self, event):
"""Make sure this widget is raised when it is shown
(when it is first created as a tab in PlotWindow or when it is shown
again after hiding).
"""
self.raise_()
+ qt.QDockWidget.showEvent(self, event)
diff --git a/silx/gui/plot/Interaction.py b/silx/gui/plot/Interaction.py
index f09b9bc..358af74 100644
--- a/silx/gui/plot/Interaction.py
+++ b/silx/gui/plot/Interaction.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2014-2016 European Synchrotron Radiation Facility
+# Copyright (c) 2014-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
diff --git a/silx/gui/plot/PlotToolButtons.py b/silx/gui/plot/PlotToolButtons.py
index 430489d..fc5fcf4 100644
--- a/silx/gui/plot/PlotToolButtons.py
+++ b/silx/gui/plot/PlotToolButtons.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -22,13 +22,14 @@
# THE SOFTWARE.
#
# ###########################################################################*/
-"""This module provides a set of QToolButton to use with :class:`.PlotWidget`.
+"""This module provides a set of QToolButton to use with
+:class:`~silx.gui.plot.PlotWidget`.
The following QToolButton are available:
-- :class:`AspectToolButton`
-- :class:`YAxisOriginToolButton`
-- :class:`ProfileToolButton`
+- :class:`.AspectToolButton`
+- :class:`.YAxisOriginToolButton`
+- :class:`.ProfileToolButton`
"""
@@ -46,7 +47,7 @@ _logger = logging.getLogger(__name__)
class PlotToolButton(qt.QToolButton):
- """A QToolButton connected to a :class:`.PlotWidget`.
+ """A QToolButton connected to a :class:`~silx.gui.plot.PlotWidget`.
"""
def __init__(self, parent=None, plot=None):
@@ -93,6 +94,7 @@ class PlotToolButton(qt.QToolButton):
class AspectToolButton(PlotToolButton):
+ """Tool button to switch keep aspect ratio of a plot"""
STATE = None
"""Lazy loaded states used to feed AspectToolButton"""
@@ -159,6 +161,7 @@ class AspectToolButton(PlotToolButton):
class YAxisOriginToolButton(PlotToolButton):
+ """Tool button to switch the Y axis orientation of a plot."""
STATE = None
"""Lazy loaded states used to feed YAxisOriginToolButton"""
diff --git a/silx/gui/plot/PlotTools.py b/silx/gui/plot/PlotTools.py
index ed62d48..7fadfd2 100644
--- a/silx/gui/plot/PlotTools.py
+++ b/silx/gui/plot/PlotTools.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -83,10 +83,10 @@ class PositionInfo(qt.QWidget):
>>> plot.show() # To display the PlotWindow with the position widget
:param plot: The PlotWidget this widget is displaying data coords from.
- :param converters: List of name to display and conversion function from
- (x, y) in data coords to displayed value.
- If None, the default, it displays X and Y.
- :type converters: Iterable of 2-tuple (str, function)
+ :param converters:
+ List of 2-tuple: name to display and conversion function from (x, y)
+ in data coords to displayed value.
+ If None, the default, it displays X and Y.
:param parent: Parent widget
"""
diff --git a/silx/gui/plot/PlotWidget.py b/silx/gui/plot/PlotWidget.py
index 5bf2b59..3641b8c 100644
--- a/silx/gui/plot/PlotWidget.py
+++ b/silx/gui/plot/PlotWidget.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,151 +23,7 @@
# ###########################################################################*/
"""Qt widget providing plot API for 1D and 2D data.
-Widget with plot API for 1D and 2D data.
-
The :class:`PlotWidget` implements the plot API initially provided in PyMca.
-
-Plot Events
------------
-
-The :class:`PlotWidget` sends some event to the registered callback
-(See :meth:`PlotWidget.setCallback`).
-Those events are sent as a dictionary with a key 'event' describing the kind
-of event.
-
-Drawing events
-..............
-
-'drawingProgress' and 'drawingFinished' events are sent during drawing
-interaction (See :meth:`PlotWidget.setInteractiveMode`).
-
-- 'event': 'drawingProgress' or 'drawingFinished'
-- 'parameters': dict of parameters used by the drawing mode.
- It has the following keys: 'shape', 'label', 'color'.
- See :meth:`PlotWidget.setInteractiveMode`.
-- 'points': Points (x, y) in data coordinates of the drawn shape.
- For 'hline' and 'vline', it is the 2 points defining the line.
- For 'line' and 'rectangle', it is the coordinates of the start
- drawing point and the latest drawing point.
- For 'polygon', it is the coordinates of all points of the shape.
-- 'type': The type of drawing in 'line', 'hline', 'polygon', 'rectangle',
- 'vline'.
-- 'xdata' and 'ydata': X coords and Y coords of shape points in data
- coordinates (as in 'points').
-
-When the type is 'rectangle', the following additional keys are provided:
-
-- 'x' and 'y': The origin of the rectangle in data coordinates
-- 'widht' and 'height': The size of the rectangle in data coordinates
-
-
-Mouse events
-............
-
-'mouseMoved', 'mouseClicked' and 'mouseDoubleClicked' events are sent for
-mouse events.
-
-They provide the following keys:
-
-- 'event': 'mouseMoved', 'mouseClicked' or 'mouseDoubleClicked'
-- 'button': the mouse button that was pressed in 'left', 'middle', 'right'
-- 'x' and 'y': The mouse position in data coordinates
-- 'xpixel' and 'ypixel': The mouse position in pixels
-
-
-Marker events
-.............
-
-'hover', 'markerClicked', 'markerMoving' and 'markerMoved' events are
-sent during interaction with markers.
-
-'hover' is sent when the mouse cursor is over a marker.
-'markerClicker' is sent when the user click on a selectable marker.
-'markerMoving' and 'markerMoved' are sent when a draggable marker is moved.
-
-They provide the following keys:
-
-- 'event': 'hover', 'markerClicked', 'markerMoving' or 'markerMoved'
-- 'button': the mouse button that is pressed in 'left', 'middle', 'right'
-- 'draggable': True if the marker is draggable, False otherwise
-- 'label': The legend associated with the clicked image or curve
-- 'selectable': True if the marker is selectable, False otherwise
-- 'type': 'marker'
-- 'x' and 'y': The mouse position in data coordinates
-- 'xdata' and 'ydata': The marker position in data coordinates
-
-'markerClicked' and 'markerMoving' events have a 'xpixel' and a 'ypixel'
-additional keys, that provide the mouse position in pixels.
-
-
-Image and curve events
-......................
-
-'curveClicked' and 'imageClicked' events are sent when a selectable curve
-or image is clicked.
-
-Both share the following keys:
-
-- 'event': 'curveClicked' or 'imageClicked'
-- 'button': the mouse button that was pressed in 'left', 'middle', 'right'
-- 'label': The legend associated with the clicked image or curve
-- 'type': The type of item in 'curve', 'image'
-- 'x' and 'y': The clicked position in data coordinates
-- 'xpixel' and 'ypixel': The clicked position in pixels
-
-'curveClicked' events have a 'xdata' and a 'ydata' additional keys, that
-provide the coordinates of the picked points of the curve.
-There can be more than one point of the curve being picked, and if a line of
-the curve is picked, only the first point of the line is included in the list.
-
-'imageClicked' have a 'col' and a 'row' additional keys, that provide
-the column and row index in the image array that was clicked.
-
-
-Limits changed events
-.....................
-
-'limitsChanged' events are sent when the limits of the plot are changed.
-This can results from user interaction or API calls.
-
-It provides the following keys:
-
-- 'event': 'limitsChanged'
-- 'source': id of the widget that emitted this event.
-- 'xdata': Range of X in graph coordinates: (xMin, xMax).
-- 'ydata': Range of Y in graph coordinates: (yMin, yMax).
-- 'y2data': Range of right axis in graph coordinates (y2Min, y2Max) or None.
-
-Plot state change events
-........................
-
-The following events are emitted when the plot is modified.
-They provide the new state:
-
-- 'setGraphCursor' event with a 'state' key (bool)
-- 'setGraphGrid' event with a 'which' key (str), see :meth:`setGraphGrid`
-- 'setKeepDataAspectRatio' event with a 'state' key (bool)
-
-A 'contentChanged' event is triggered when the content of the plot is updated.
-It provides the following keys:
-
-- 'action': The change of the plot: 'add' or 'remove'
-- 'kind': The kind of primitive changed: 'curve', 'image', 'item' or 'marker'
-- 'legend': The legend of the primitive changed.
-
-'activeCurveChanged' and 'activeImageChanged' events with the following keys:
-
-- 'legend': Name (str) of the current active item or None if no active item.
-- 'previous': Name (str) of the previous active item or None if no item was
- active. It is the same as 'legend' if 'updated' == True
-- 'updated': (bool) True if active item name did not changed,
- but active item data or style was updated.
-
-'interactiveModeChanged' event with a 'source' key identifying the object
-setting the interactive mode.
-
-'defaultColormapChanged' event is triggered when the default colormap of
-the plot is updated.
"""
from __future__ import division
@@ -264,7 +120,8 @@ class PlotWidget(qt.QMainWindow):
"""Signal for all events of the plot.
The signal information is provided as a dict.
- See :class:`PlotWidget` for documentation of the content of the dict.
+ See the :ref:`plot signal documentation page <plot_signal>` for
+ information about the content of the dict
"""
sigSetKeepDataAspectRatio = qt.Signal(bool)
@@ -574,7 +431,7 @@ class PlotWidget(qt.QMainWindow):
item._setPlot(self)
if item.isVisible():
self._itemRequiresUpdate(item)
- if isinstance(item, (items.Curve, items.ImageBase)):
+ if isinstance(item, items.DATA_ITEMS):
self._invalidateDataRange() # TODO handle this automatically
self._notifyContentChanged(item)
@@ -964,7 +821,7 @@ class PlotWidget(qt.QMainWindow):
:param colormap: Description of the :class:`.Colormap` to use
(or None).
This is ignored if data is a RGB(A) image.
- :type colormap: Colormap or dict (old API )
+ :type colormap: Union[silx.gui.plot.Colormap.Colormap, dict]
:param pixmap: Pixmap representation of the data (if any)
:type pixmap: (nrows, ncolumns, RGBA) ubyte array or None (default)
:param str xlabel: X axis label to show when this curve is active,
@@ -1107,8 +964,8 @@ class PlotWidget(qt.QMainWindow):
:param numpy.ndarray y: The data corresponding to the y coordinates
:param numpy.ndarray value: The data value associated with each point
:param str legend: The legend to be associated to the scatter (or None)
- :param Colormap colormap: The :class:`.Colormap`. to be used for the
- scatter (or None)
+ :param silx.gui.plot.Colormap.Colormap colormap:
+ The :class:`.Colormap`. to be used for the scatter (or None)
:param info: User-defined information associated to the curve
:param str symbol: Symbol to be drawn at each (x, y) position::
@@ -2407,9 +2264,10 @@ class PlotWidget(qt.QMainWindow):
It only affects future calls to :meth:`addImage` without the colormap
parameter.
- :param Colormap colormap: The description of the default colormap, or
- None to set the :class:`.Colormap` to a linear
- autoscale gray colormap.
+ :param silx.gui.plot.Colormap.Colormap colormap:
+ The description of the default colormap, or
+ None to set the :class:`.Colormap` to a linear
+ autoscale gray colormap.
"""
if colormap is None:
colormap = Colormap(name='gray',
@@ -2533,6 +2391,7 @@ class PlotWidget(qt.QMainWindow):
if ddict['event'] in ["legendClicked", "curveClicked"]:
if ddict['button'] == "left":
self.setActiveCurve(ddict['label'])
+ qt.QToolTip.showText(self.cursor().pos(), ddict['label'])
def saveGraph(self, filename, fileFormat=None, dpi=None, **kw):
"""Save a snapshot of the plot.
@@ -2817,7 +2676,7 @@ class PlotWidget(qt.QMainWindow):
def test(mark):
return True
- markers = self._backend.pickItems(x, y)
+ markers = self._backend.pickItems(x, y, kinds=('marker',))
legends = [m['legend'] for m in markers if m['kind'] == 'marker']
for legend in reversed(legends):
@@ -2852,7 +2711,8 @@ class PlotWidget(qt.QMainWindow):
To use for interaction implementation.
- :param float x: X position in pixelsparam float y: Y position in pixels
+ :param float x: X position in pixels
+ :param float y: Y position in pixels
:param test: A callable to call for each picked item to filter
picked items. If None (default), do not filter items.
"""
@@ -2860,7 +2720,7 @@ class PlotWidget(qt.QMainWindow):
def test(i):
return True
- allItems = self._backend.pickItems(x, y)
+ allItems = self._backend.pickItems(x, y, kinds=('curve', 'image'))
allItems = [item for item in allItems
if item['kind'] in ['curve', 'image']]
diff --git a/silx/gui/plot/PlotWindow.py b/silx/gui/plot/PlotWindow.py
index a23db04..5c7e661 100644
--- a/silx/gui/plot/PlotWindow.py
+++ b/silx/gui/plot/PlotWindow.py
@@ -29,7 +29,7 @@ The :class:`PlotWindow` is a subclass of :class:`.PlotWidget`.
__authors__ = ["V.A. Sole", "T. Vincent"]
__license__ = "MIT"
-__date__ = "17/08/2017"
+__date__ = "15/02/2018"
import collections
import logging
@@ -41,6 +41,7 @@ from . import actions
from . import items
from .actions import medfilt as actions_medfilt
from .actions import fit as actions_fit
+from .actions import control as actions_control
from .actions import histogram as actions_histogram
from . import PlotToolButtons
from .PlotTools import PositionInfo
@@ -112,6 +113,10 @@ class PlotWindow(PlotWidget):
self._legendsDockWidget = None
self._curvesROIDockWidget = None
self._maskToolsDockWidget = None
+ self._consoleDockWidget = None
+
+ # Create color bar, hidden by default for backward compatibility
+ self._colorbar = ColorBarWidget(parent=self, plot=self)
# Init actions
self.group = qt.QActionGroup(self)
@@ -168,6 +173,12 @@ class PlotWindow(PlotWidget):
self.colormapAction.setVisible(colormap)
self.addAction(self.colormapAction)
+ self.colorbarAction = self.group.addAction(
+ actions_control.ColorBarAction(self, self))
+ self.colorbarAction.setVisible(False)
+ self.addAction(self.colorbarAction)
+ self._colorbar.setVisible(False)
+
self.keepDataAspectRatioButton = PlotToolButtons.AspectToolButton(
parent=self, plot=self)
self.keepDataAspectRatioButton.setVisible(aspectRatio)
@@ -219,10 +230,6 @@ class PlotWindow(PlotWidget):
self._panWithArrowKeysAction = None
self._crosshairAction = None
- # Create color bar, hidden by default for backward compatibility
- self._colorbar = ColorBarWidget(parent=self, plot=self)
- self._colorbar.setVisible(False)
-
# Make colorbar background white
self._colorbar.setAutoFillBackground(True)
palette = self._colorbar.palette()
@@ -301,11 +308,11 @@ class PlotWindow(PlotWidget):
"""
return bool(self.getMaskToolsDockWidget().setSelectionMask(mask))
- def _toggleConsoleVisibility(self, is_checked=False):
+ def _toggleConsoleVisibility(self, isChecked=False):
"""Create IPythonDockWidget if needed,
show it or hide it."""
# create widget if needed (first call)
- if not hasattr(self, '_consoleDockWidget'):
+ if self._consoleDockWidget is None:
available_vars = {"plt": self}
banner = "The variable 'plt' is available. Use the 'whos' "
banner += "and 'help(plt)' commands for more information.\n\n"
@@ -314,10 +321,11 @@ class PlotWindow(PlotWidget):
custom_banner=banner,
parent=self)
self.addTabbedDockWidget(self._consoleDockWidget)
- self._consoleDockWidget.visibilityChanged.connect(
+ # self._consoleDockWidget.setVisible(True)
+ self._consoleDockWidget.toggleViewAction().toggled.connect(
self.getConsoleAction().setChecked)
- self._consoleDockWidget.setVisible(is_checked)
+ self._consoleDockWidget.setVisible(isChecked)
def _createToolBar(self, title, parent):
"""Create a QToolBar from the QAction of the PlotWindow.
@@ -427,16 +435,22 @@ class PlotWindow(PlotWidget):
return self._legendsDockWidget
@property
- @deprecated(replacement="getCurvesRoiDockWidget()", since_version="0.4.0")
+ @deprecated(replacement="getCurvesRoiWidget()", since_version="0.4.0")
def curvesROIDockWidget(self):
return self.getCurvesRoiDockWidget()
def getCurvesRoiDockWidget(self):
- """DockWidget with curves' ROI panel (lazy-loaded).
+ # Undocumented for a "soft deprecation" in version 0.7.0
+ # (still used internally for lazy loading)
+ if self._curvesROIDockWidget is None:
+ self._curvesROIDockWidget = CurvesROIDockWidget(
+ plot=self, name='Regions Of Interest')
+ self._curvesROIDockWidget.hide()
+ self.addTabbedDockWidget(self._curvesROIDockWidget)
+ return self._curvesROIDockWidget
- The widget returned is a :class:`CurvesROIDockWidget`.
- Its central widget is a :class:`CurvesROIWidget`
- accessible as :attr:`CurvesROIDockWidget.roiWidget`.
+ def getCurvesRoiWidget(self):
+ """Return the :class:`CurvesROIWidget`.
:class:`silx.gui.plot.CurvesROIWidget.CurvesROIWidget` offers a getter
and a setter for the ROI data:
@@ -444,12 +458,7 @@ class PlotWindow(PlotWidget):
- :meth:`CurvesROIWidget.getRois`
- :meth:`CurvesROIWidget.setRois`
"""
- if self._curvesROIDockWidget is None:
- self._curvesROIDockWidget = CurvesROIDockWidget(
- plot=self, name='Regions Of Interest')
- self._curvesROIDockWidget.hide()
- self.addTabbedDockWidget(self._curvesROIDockWidget)
- return self._curvesROIDockWidget
+ return self.getCurvesRoiDockWidget().roiWidget
@property
@deprecated(replacement="getMaskToolsDockWidget()", since_version="0.4.0")
@@ -695,6 +704,16 @@ class PlotWindow(PlotWidget):
"""
return self._medianFilter2DAction
+ def getColorBarAction(self):
+ """Action toggling the colorbar show/hide action
+
+ .. warning:: to show/hide the plot colorbar call directly the ColorBar
+ widget using getColorBarWidget()
+
+ :rtype: actions.PlotAction
+ """
+ return self.colorbarAction
+
class Plot1D(PlotWindow):
"""PlotWindow with tools specific for curves.
@@ -756,6 +775,7 @@ class Plot2D(PlotWindow):
self.profile = ProfileToolBar(plot=self)
self.addToolBar(self.profile)
+ self.colorbarAction.setVisible(True)
self.getColorBarWidget().setVisible(True)
# Put colorbar action after colormap action
@@ -763,9 +783,6 @@ class Plot2D(PlotWindow):
for index, action in enumerate(actions):
if action is self.getColormapAction():
break
- self.toolBar().insertAction(
- actions[index + 1],
- self.getColorBarWidget().getToggleViewAction())
def _getImageValue(self, x, y):
"""Get status bar value of top most image at position (x, y)
diff --git a/silx/gui/plot/Profile.py b/silx/gui/plot/Profile.py
index 4a74fa7..f61412d 100644
--- a/silx/gui/plot/Profile.py
+++ b/silx/gui/plot/Profile.py
@@ -660,23 +660,23 @@ class ProfileToolBar(qt.QToolBar):
winGeom = self.window().frameGeometry()
qapp = qt.QApplication.instance()
screenGeom = qapp.desktop().availableGeometry(self)
-
spaceOnLeftSide = winGeom.left()
spaceOnRightSide = screenGeom.width() - winGeom.right()
profileWindowWidth = profileMainWindow.frameGeometry().width()
- if (profileWindowWidth < spaceOnRightSide or
- spaceOnRightSide > spaceOnLeftSide):
+ if (profileWindowWidth < spaceOnRightSide):
# Place profile on the right
profileMainWindow.move(winGeom.right(), winGeom.top())
- else:
- # Not enough place on the right, place profile on the left
+ elif(profileWindowWidth < spaceOnLeftSide):
+ # Place profile on the left
profileMainWindow.move(
- max(0, winGeom.left() - profileWindowWidth), winGeom.top())
+ max(0, winGeom.left() - profileWindowWidth), winGeom.top())
profileMainWindow.show()
+ profileMainWindow.raise_()
else:
self.getProfilePlot().show()
+ self.getProfilePlot().raise_()
def hideProfileWindow(self):
"""Hide profile window.
diff --git a/silx/gui/plot/StackView.py b/silx/gui/plot/StackView.py
index 938447b..1fb188c 100644
--- a/silx/gui/plot/StackView.py
+++ b/silx/gui/plot/StackView.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -69,7 +69,7 @@ Example::
__authors__ = ["P. Knobel", "H. Payno"]
__license__ = "MIT"
-__date__ = "11/09/2017"
+__date__ = "15/02/2018"
import numpy
@@ -82,6 +82,7 @@ from .PlotTools import LimitsToolBar
from .Profile import Profile3DToolBar
from ..widgets.FrameBrowser import HorizontalSliderWithBrowser
+from silx.gui.plot.actions import control as actions_control
from silx.utils.array_like import DatasetView, ListOfImages
from silx.math import calibration
from silx.utils.deprecation import deprecated_warning
@@ -245,9 +246,8 @@ class StackView(qt.QMainWindow):
for index, action in enumerate(actions):
if action is self._plot.getColormapAction():
break
- self._plot.toolBar().insertAction(
- actions[index + 1],
- self._plot.getColorBarWidget().getToggleViewAction())
+ self._colorbarAction = actions_control.ColorBarAction(self._plot, self._plot)
+ self._plot.toolBar().insertAction(actions[index + 1], self._colorbarAction)
def _plotCallback(self, eventDict):
"""Callback for plot events.
@@ -652,7 +652,7 @@ class StackView(qt.QMainWindow):
when the volume is rotated (when different axes are selected as the
X and Y axes).
- :param list(str) labels: 3 labels corresponding to the 3 dimensions
+ :param List[str] labels: 3 labels corresponding to the 3 dimensions
of the data volumes.
"""
@@ -972,6 +972,16 @@ class StackView(qt.QMainWindow):
"""
return self._plot.getActiveImage(just_legend=just_legend)
+ def getColorBarAction(self):
+ """Returns the action managing the visibility of the colorbar.
+
+ .. warning:: to show/hide the plot colorbar call directly the ColorBar
+ widget using getColorBarWidget()
+
+ :rtype: QAction
+ """
+ return self._colorbarAction
+
def remove(self, legend=None,
kind=('curve', 'image', 'item', 'marker')):
"""See :meth:`Plot.Plot.remove`"""
@@ -1102,7 +1112,7 @@ class StackViewMainWindow(StackView):
menu.addSeparator()
menu.addAction(self._plot.resetZoomAction)
menu.addAction(self._plot.colormapAction)
- menu.addAction(self._plot.getColorBarWidget().getToggleViewAction())
+ menu.addAction(self.getColorBarAction())
menu.addAction(actions.control.KeepAspectRatioAction(self._plot, self))
menu.addAction(actions.control.YAxisInvertedAction(self._plot, self))
diff --git a/silx/gui/plot/_utils/test/test_ticklayout.py b/silx/gui/plot/_utils/test/test_ticklayout.py
index 8c67620..927ffb6 100644
--- a/silx/gui/plot/_utils/test/test_ticklayout.py
+++ b/silx/gui/plot/_utils/test/test_ticklayout.py
@@ -27,12 +27,13 @@ from __future__ import absolute_import, division, unicode_literals
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "18/10/2016"
+__date__ = "17/01/2018"
import unittest
+import numpy
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
from silx.gui.plot._utils import ticklayout
@@ -40,6 +41,19 @@ from silx.gui.plot._utils import ticklayout
class TestTickLayout(ParametricTestCase):
"""Test ticks layout algorithms"""
+ def testTicks(self):
+ """Test of :func:`ticks`"""
+ tests = { # (vmin, vmax): ref_ticks
+ (1., 1.): (1.,),
+ (0.5, 10.5): (2.0, 4.0, 6.0, 8.0, 10.0),
+ (0.001, 0.005): (0.001, 0.002, 0.003, 0.004, 0.005)
+ }
+
+ for (vmin, vmax), ref_ticks in tests.items():
+ with self.subTest(vmin=vmin, vmax=vmax):
+ ticks, labels = ticklayout.ticks(vmin, vmax)
+ self.assertTrue(numpy.allclose(ticks, ref_ticks))
+
def testNiceNumbers(self):
"""Minimalistic tests of :func:`niceNumbers`"""
tests = { # (vmin, vmax): ref_ticks
diff --git a/silx/gui/plot/_utils/ticklayout.py b/silx/gui/plot/_utils/ticklayout.py
index 5f4b636..6e9f654 100644
--- a/silx/gui/plot/_utils/ticklayout.py
+++ b/silx/gui/plot/_utils/ticklayout.py
@@ -109,7 +109,7 @@ def ticks(vMin, vMax, nbTicks=5):
"""Returns tick positions and labels using nice numbers algorithm.
This enforces ticks to be within [vMin, vMax] range.
- It returns at least 2 ticks.
+ It returns at least 1 tick (when vMin == vMax).
:param float vMin: The min value on the axis
:param float vMax: The max value on the axis
@@ -117,13 +117,19 @@ def ticks(vMin, vMax, nbTicks=5):
:returns: tick positions and corresponding text labels
:rtype: 2-tuple: list of float, list of string
"""
- start, end, step, nfrac = niceNumbers(vMin, vMax, nbTicks)
- positions = [t for t in _frange(start, end, step) if vMin <= t <= vMax]
+ assert vMin <= vMax
+ if vMin == vMax:
+ positions = [vMin]
+ nfrac = 0
+
+ else:
+ start, end, step, nfrac = niceNumbers(vMin, vMax, nbTicks)
+ positions = [t for t in _frange(start, end, step) if vMin <= t <= vMax]
- # Makes sure there is at least 2 ticks
- if len(positions) < 2:
- positions = [vMin, vMax]
- nfrac = numberOfDigits(vMax - vMin)
+ # Makes sure there is at least 2 ticks
+ if len(positions) < 2:
+ positions = [vMin, vMax]
+ nfrac = numberOfDigits(vMax - vMin)
# Generate labels
format_ = '%g' if nfrac == 0 else '%.{}f'.format(nfrac)
diff --git a/silx/gui/plot/actions/PlotAction.py b/silx/gui/plot/actions/PlotAction.py
index 6eb9ba3..2983775 100644
--- a/silx/gui/plot/actions/PlotAction.py
+++ b/silx/gui/plot/actions/PlotAction.py
@@ -32,10 +32,9 @@ from __future__ import division
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__license__ = "MIT"
-__date__ = "20/04/2017"
+__date__ = "03/01/2018"
-from collections import OrderedDict
import weakref
from silx.gui import icons
from silx.gui import qt
diff --git a/silx/gui/plot/actions/__init__.py b/silx/gui/plot/actions/__init__.py
index 73829cd..930c728 100644
--- a/silx/gui/plot/actions/__init__.py
+++ b/silx/gui/plot/actions/__init__.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -22,10 +22,14 @@
# THE SOFTWARE.
#
# ###########################################################################*/
-"""This package provides a set of QActions to use with :class:`PlotWidget`
+"""This package provides a set of QAction to use with
+:class:`~silx.gui.plot.PlotWidget`
-It also contains the :class:'.PlotAction' (Base class for QAction that operates
-on a PlotWidget)
+Those actions are useful to add menu items or toolbar items
+that interact with a :class:`~silx.gui.plot.PlotWidget`.
+
+It provides a base class used to define new plot actions:
+:class:`~silx.gui.plot.actions.PlotAction`.
"""
__authors__ = ["H. Payno"]
diff --git a/silx/gui/plot/actions/control.py b/silx/gui/plot/actions/control.py
index 23e710e..ac6dc2f 100644
--- a/silx/gui/plot/actions/control.py
+++ b/silx/gui/plot/actions/control.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -50,11 +50,10 @@ from __future__ import division
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__license__ = "MIT"
-__date__ = "27/06/2017"
+__date__ = "15/02/2018"
from . import PlotAction
import logging
-import numpy
from silx.gui.plot import items
from silx.gui.plot.ColormapDialog import ColormapDialog
from silx.gui.plot._utils import applyZoomToPlot as _applyZoomToPlot
@@ -327,67 +326,112 @@ class ColormapAction(PlotAction):
plot, icon='colormap', text='Colormap',
tooltip="Change colormap",
triggered=self._actionTriggered,
- checkable=False, parent=parent)
+ checkable=True, parent=parent)
+ self.plot.sigActiveImageChanged.connect(self._updateColormap)
+
+ def setColorDialog(self, colorDialog):
+ """Set a specific color dialog instead of using the default dialog."""
+ assert(colorDialog is not None)
+ assert(self._dialog is None)
+ self._dialog = colorDialog
+ self._dialog.visibleChanged.connect(self._dialogVisibleChanged)
+ self.setChecked(self._dialog.isVisible())
+
+ @staticmethod
+ def _createDialog(parent):
+ """Create the dialog if not already existing
+
+ :parent QWidget parent: Parent of the new colormap
+ :rtype: ColormapDialog
+ """
+ dialog = ColormapDialog(parent=parent)
+ dialog.setModal(False)
+ return dialog
def _actionTriggered(self, checked=False):
"""Create a cmap dialog and update active image and default cmap."""
- # Create the dialog if not already existing
if self._dialog is None:
- self._dialog = ColormapDialog()
+ self._dialog = self._createDialog(self.plot)
+ self._dialog.visibleChanged.connect(self._dialogVisibleChanged)
+
+ # Run the dialog listening to colormap change
+ if checked is True:
+ self._dialog.show()
+ self._updateColormap()
+ else:
+ self._dialog.hide()
+
+ def _dialogVisibleChanged(self, isVisible):
+ self.setChecked(isVisible)
+ def _updateColormap(self):
+ if self._dialog is None:
+ return
image = self.plot.getActiveImage()
- if not isinstance(image, items.ColormapMixIn):
- # No active image or active image is RGBA,
- # set dialog from default info
- colormap = self.plot.getDefaultColormap()
- self._dialog.setHistogram() # Reset histogram and range if any
+ if isinstance(image, items.ImageComplexData):
+ # Specific init for complex images
+ colormap = image.getColormap()
- else:
+ mode = image.getVisualizationMode()
+ if mode in (items.ImageComplexData.Mode.AMPLITUDE_PHASE,
+ items.ImageComplexData.Mode.LOG10_AMPLITUDE_PHASE):
+ data = image.getData(
+ copy=False, mode=items.ImageComplexData.Mode.PHASE)
+ else:
+ data = image.getData(copy=False)
+
+ # Set histogram and range if any
+ self._dialog.setData(data)
+
+ elif isinstance(image, items.ColormapMixIn):
# Set dialog from active image
colormap = image.getColormap()
-
data = image.getData(copy=False)
+ # Set histogram and range if any
+ self._dialog.setData(data)
- goodData = data[numpy.isfinite(data)]
- if goodData.size > 0:
- dataMin = goodData.min()
- dataMax = goodData.max()
- else:
- qt.QMessageBox.warning(
- None, "No Data",
- "Image data does not contain any real value")
- dataMin, dataMax = 1., 10.
-
- self._dialog.setHistogram() # Reset histogram if any
- self._dialog.setDataRange(dataMin, dataMax)
- # The histogram should be done in a worker thread
- # hist, bin_edges = numpy.histogram(goodData, bins=256)
- # self._dialog.setHistogram(hist, bin_edges)
-
- self._dialog.setColormap(name=colormap.getName(),
- normalization=colormap.getNormalization(),
- autoscale=colormap.isAutoscale(),
- vmin=colormap.getVMin(),
- vmax=colormap.getVMax(),
- colors=colormap.getColormapLUT())
+ else:
+ # No active image or active image is RGBA,
+ # set dialog from default info
+ colormap = self.plot.getDefaultColormap()
+ # Reset histogram and range if any
+ self._dialog.setData(None)
- # Run the dialog listening to colormap change
- self._dialog.sigColormapChanged.connect(self._colormapChanged)
- result = self._dialog.exec_()
- self._dialog.sigColormapChanged.disconnect(self._colormapChanged)
+ self._dialog.setColormap(colormap)
- if not result: # Restore the previous colormap
- self._colormapChanged(colormap)
- def _colormapChanged(self, colormap):
- # Update default colormap
- self.plot.setDefaultColormap(colormap)
+class ColorBarAction(PlotAction):
+ """QAction opening the ColorBarWidget of the specified plot.
+
+ :param plot: :class:`.PlotWidget` instance on which to operate
+ :param parent: See :class:`QAction`
+ """
+ def __init__(self, plot, parent=None):
+ self._dialog = None # To store an instance of ColormapDialog
+ super(ColorBarAction, self).__init__(
+ plot, icon='colorbar', text='Colorbar',
+ tooltip="Show/Hide the colorbar",
+ triggered=self._actionTriggered,
+ checkable=True, parent=parent)
+ colorBarWidget = self.plot.getColorBarWidget()
+ old = self.blockSignals(True)
+ self.setChecked(colorBarWidget.isVisibleTo(self.plot))
+ self.blockSignals(old)
+ colorBarWidget.sigVisibleChanged.connect(self._widgetVisibleChanged)
+
+ def _widgetVisibleChanged(self, isVisible):
+ """Callback when the colorbar `visible` property change."""
+ if self.isChecked() == isVisible:
+ return
+ self.setChecked(isVisible)
- # Update active image colormap
- activeImage = self.plot.getActiveImage()
- if isinstance(activeImage, items.ColormapMixIn):
- activeImage.setColormap(colormap)
+ def _actionTriggered(self, checked=False):
+ """Create a cmap dialog and update active image and default cmap."""
+ colorBarWidget = self.plot.getColorBarWidget()
+ if not colorBarWidget.isHidden() == checked:
+ return
+ self.plot.getColorBarWidget().setVisible(checked)
class KeepAspectRatioAction(PlotAction):
diff --git a/silx/gui/plot/actions/fit.py b/silx/gui/plot/actions/fit.py
index d7256ab..5ca649c 100644
--- a/silx/gui/plot/actions/fit.py
+++ b/silx/gui/plot/actions/fit.py
@@ -36,7 +36,7 @@ from __future__ import division
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__license__ = "MIT"
-__date__ = "28/06/2017"
+__date__ = "03/01/2018"
from . import PlotAction
import logging
@@ -111,7 +111,7 @@ class FitAction(PlotAction):
if histo is None and curve is None:
# ambiguous case, we need to ask which plot item to fit
- isd = ItemsSelectionDialog(plot=self.plot)
+ isd = ItemsSelectionDialog(parent=self.plot, plot=self.plot)
isd.setWindowTitle("Select item to be fitted")
isd.setItemsSelectionMode(qt.QTableWidget.SingleSelection)
isd.setAvailableKinds(["curve", "histogram"])
diff --git a/silx/gui/plot/actions/histogram.py b/silx/gui/plot/actions/histogram.py
index a4a91e9..40ef873 100644
--- a/silx/gui/plot/actions/histogram.py
+++ b/silx/gui/plot/actions/histogram.py
@@ -39,6 +39,7 @@ __license__ = "MIT"
from . import PlotAction
from silx.math.histogram import Histogramnd
+from silx.math.combo import min_max
import numpy
import logging
from silx.gui import qt
@@ -107,8 +108,7 @@ class PixelIntensitiesHistoAction(PlotAction):
image[:, :, 1] * 0.587 +
image[:, :, 2] * 0.114)
- xmin = numpy.nanmin(image)
- xmax = numpy.nanmax(image)
+ xmin, xmax = min_max(image, min_positive=False, finite=True)
nbins = min(1024, int(numpy.sqrt(image.size)))
data_range = xmin, xmax
diff --git a/silx/gui/plot/actions/io.py b/silx/gui/plot/actions/io.py
index 50410e3..d6d5909 100644
--- a/silx/gui/plot/actions/io.py
+++ b/silx/gui/plot/actions/io.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -37,10 +37,11 @@ from __future__ import division
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__license__ = "MIT"
-__date__ = "27/06/2017"
+__date__ = "02/02/2018"
from . import PlotAction
from silx.io.utils import save1D, savespec
+from silx.io.nxdata import save_NXdata
import logging
import sys
from collections import OrderedDict
@@ -59,6 +60,10 @@ else:
_logger = logging.getLogger(__name__)
+_NEXUS_HDF5_EXT = [".nx5", ".nxs", ".hdf", ".hdf5", ".cxi", ".h5"]
+_NEXUS_HDF5_EXT_STR = ' '.join(['*' + ext for ext in _NEXUS_HDF5_EXT])
+
+
class SaveAction(PlotAction):
"""QAction for saving Plot content.
@@ -89,12 +94,15 @@ class SaveAction(PlotAction):
('Curve as OMNIC CSV (*.csv)',
{'fmt': '%.7E', 'delimiter': ',', 'header': False}),
('Curve as SpecFile (*.dat)',
- {'fmt': '%.7g', 'delimiter': '', 'header': False})
+ {'fmt': '%.10g', 'delimiter': '', 'header': False})
))
CURVE_FILTER_NPY = 'Curve as NumPy binary file (*.npy)'
- CURVE_FILTERS = list(CURVE_FILTERS_TXT.keys()) + [CURVE_FILTER_NPY]
+ CURVE_FILTER_NXDATA = 'Curve as NXdata (%s)' % _NEXUS_HDF5_EXT_STR
+
+ CURVE_FILTERS = list(CURVE_FILTERS_TXT.keys()) + [CURVE_FILTER_NPY,
+ CURVE_FILTER_NXDATA]
ALL_CURVES_FILTERS = ("All curves as SpecFile (*.dat)", )
@@ -107,6 +115,7 @@ class SaveAction(PlotAction):
IMAGE_FILTER_CSV_TAB = 'Image data as tab-separated CSV (*.csv)'
IMAGE_FILTER_RGB_PNG = 'Image as PNG (*.png)'
IMAGE_FILTER_RGB_TIFF = 'Image as TIFF (*.tif)'
+ IMAGE_FILTER_NXDATA = 'Image as NXdata (%s)' % _NEXUS_HDF5_EXT_STR
IMAGE_FILTERS = (IMAGE_FILTER_EDF,
IMAGE_FILTER_TIFF,
IMAGE_FILTER_NUMPY,
@@ -115,7 +124,11 @@ class SaveAction(PlotAction):
IMAGE_FILTER_CSV_SEMICOLON,
IMAGE_FILTER_CSV_TAB,
IMAGE_FILTER_RGB_PNG,
- IMAGE_FILTER_RGB_TIFF)
+ IMAGE_FILTER_RGB_TIFF,
+ IMAGE_FILTER_NXDATA)
+
+ SCATTER_FILTER_NXDATA = 'Scatter as NXdata (%s)' % _NEXUS_HDF5_EXT_STR
+ SCATTER_FILTERS = (SCATTER_FILTER_NXDATA, )
def __init__(self, plot, parent=None):
super(SaveAction, self).__init__(
@@ -183,7 +196,7 @@ class SaveAction(PlotAction):
csvdelim = filter_['delimiter']
autoheader = filter_['header']
else:
- # .npy
+ # .npy or nxdata
fmt, csvdelim, autoheader = ("", "", False)
# If curve has no associated label, get the default from the plot
@@ -194,6 +207,19 @@ class SaveAction(PlotAction):
if ylabel is None:
ylabel = self.plot.getYAxis().getLabel()
+ if nameFilter == self.CURVE_FILTER_NXDATA:
+ return save_NXdata(
+ filename,
+ signal=curve.getYData(copy=False),
+ axes=[curve.getXData(copy=False)],
+ signal_name="y",
+ axes_names=["x"],
+ signal_long_name=ylabel,
+ axes_long_names=[xlabel],
+ signal_errors=curve.getYErrorData(copy=False),
+ axes_errors=[curve.getXErrorData(copy=True)],
+ title=self.plot.getGraphTitle())
+
try:
save1D(filename,
curve.getXData(copy=False),
@@ -226,11 +252,13 @@ class SaveAction(PlotAction):
curve = curves[0]
scanno = 1
try:
+ xlabel = curve.getXLabel() or self.plot.getGraphXLabel()
+ ylabel = curve.getYLabel() or self.plot.getGraphYLabel(curve.getYAxis())
specfile = savespec(filename,
curve.getXData(copy=False),
curve.getYData(copy=False),
- curve.getXLabel(),
- curve.getYLabel(),
+ xlabel,
+ ylabel,
fmt="%.7g", scan_number=1, mode="w",
write_file_header=True,
close_file=False)
@@ -241,12 +269,14 @@ class SaveAction(PlotAction):
for curve in curves[1:]:
try:
scanno += 1
+ xlabel = curve.getXLabel() or self.plot.getGraphXLabel()
+ ylabel = curve.getYLabel() or self.plot.getGraphYLabel(curve.getYAxis())
specfile = savespec(specfile,
curve.getXData(copy=False),
curve.getYData(copy=False),
- curve.getXLabel(),
- curve.getYLabel(),
- fmt="%.7g", scan_number=scanno, mode="w",
+ xlabel,
+ ylabel,
+ fmt="%.7g", scan_number=scanno,
write_file_header=False,
close_file=False)
except IOError:
@@ -294,6 +324,24 @@ class SaveAction(PlotAction):
return False
return True
+ elif nameFilter == self.IMAGE_FILTER_NXDATA:
+ xorigin, yorigin = image.getOrigin()
+ xscale, yscale = image.getScale()
+ xaxis = xorigin + xscale * numpy.arange(data.shape[1])
+ yaxis = yorigin + yscale * numpy.arange(data.shape[0])
+ xlabel = image.getXLabel() or self.plot.getGraphXLabel()
+ ylabel = image.getYLabel() or self.plot.getGraphYLabel()
+ interpretation = "image" if len(data.shape) == 2 else "rgba-image"
+
+ return save_NXdata(filename,
+ signal=data,
+ axes=[yaxis, xaxis],
+ signal_name="image",
+ axes_names=["y", "x"],
+ axes_long_names=[ylabel, xlabel],
+ title=self.plot.getGraphTitle(),
+ interpretation=interpretation)
+
elif nameFilter in (self.IMAGE_FILTER_ASCII,
self.IMAGE_FILTER_CSV_COMMA,
self.IMAGE_FILTER_CSV_SEMICOLON,
@@ -343,6 +391,45 @@ class SaveAction(PlotAction):
return False
+ def _saveScatter(self, filename, nameFilter):
+ """Save an image from the plot.
+
+ :param str filename: The name of the file to write
+ :param str nameFilter: The selected name filter
+ :return: False if format is not supported or save failed,
+ True otherwise.
+ """
+ if nameFilter not in self.SCATTER_FILTERS:
+ return False
+
+ if nameFilter == self.SCATTER_FILTER_NXDATA:
+ scatter = self.plot.getScatter()
+ # TODO: we could get all scatters on this plot and concatenate their (x, y, values)
+ x = scatter.getXData(copy=False)
+ y = scatter.getYData(copy=False)
+ z = scatter.getValueData(copy=False)
+
+ xerror = scatter.getXErrorData(copy=False)
+ if isinstance(xerror, float):
+ xerror = xerror * numpy.ones(x.shape, dtype=numpy.float32)
+
+ yerror = scatter.getYErrorData(copy=False)
+ if isinstance(yerror, float):
+ yerror = yerror * numpy.ones(x.shape, dtype=numpy.float32)
+
+ xlabel = self.plot.getGraphXLabel()
+ ylabel = self.plot.getGraphYLabel()
+
+ return save_NXdata(
+ filename,
+ signal=z,
+ axes=[x, y],
+ signal_name="values",
+ axes_names=["x", "y"],
+ axes_long_names=[xlabel, ylabel],
+ axes_errors=[xerror, yerror],
+ title=self.plot.getGraphTitle())
+
def _actionTriggered(self, checked=False):
"""Handle save action."""
# Set-up filters
@@ -359,6 +446,11 @@ class SaveAction(PlotAction):
if len(self.plot.getAllCurves()) > 1:
filters.extend(self.ALL_CURVES_FILTERS)
+ # Add scatter filters if there is a scatter
+ # todo: CSV
+ if self.plot.getScatter() is not None:
+ filters.extend(self.SCATTER_FILTERS)
+
filters.extend(self.SNAPSHOT_FILTERS)
# Create and run File dialog
@@ -378,10 +470,19 @@ class SaveAction(PlotAction):
dialog.close()
# Forces the filename extension to match the chosen filter
- extension = nameFilter.split()[-1][2:-1]
- if (len(filename) <= len(extension) or
- filename[-len(extension):].lower() != extension.lower()):
- filename += extension
+ if "NXdata" in nameFilter:
+ has_allowed_ext = False
+ for ext in _NEXUS_HDF5_EXT:
+ if (len(filename) > len(ext) and
+ filename[-len(ext):].lower() == ext.lower()):
+ has_allowed_ext = True
+ if not has_allowed_ext:
+ filename += ".h5"
+ else:
+ default_extension = nameFilter.split()[-1][2:-1]
+ if (len(filename) <= len(default_extension) or
+ filename[-len(default_extension):].lower() != default_extension.lower()):
+ filename += default_extension
# Handle save
if nameFilter in self.SNAPSHOT_FILTERS:
@@ -392,6 +493,8 @@ class SaveAction(PlotAction):
return self._saveCurves(filename, nameFilter)
elif nameFilter in self.IMAGE_FILTERS:
return self._saveImage(filename, nameFilter)
+ elif nameFilter in self.SCATTER_FILTERS:
+ return self._saveScatter(filename, nameFilter)
else:
_logger.warning('Unsupported file filter: %s', nameFilter)
return False
diff --git a/silx/gui/plot/actions/medfilt.py b/silx/gui/plot/actions/medfilt.py
index 3305d1b..4284a8b 100644
--- a/silx/gui/plot/actions/medfilt.py
+++ b/silx/gui/plot/actions/medfilt.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -39,7 +39,7 @@ from __future__ import division
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__license__ = "MIT"
-__date__ = "24/05/2017"
+__date__ = "03/01/2018"
from . import PlotAction
from silx.gui.widgets.MedianFilterDialog import MedianFilterDialog
@@ -67,7 +67,7 @@ class MedianFilterAction(PlotAction):
self._originalImage = None
self._legend = None
self._filteredImage = None
- self._popup = MedianFilterDialog(parent=None)
+ self._popup = MedianFilterDialog(parent=plot)
self._popup.sigFilterOptChanged.connect(self._updateFilter)
self.plot.sigActiveImageChanged.connect(self._updateActiveImage)
self._updateActiveImage()
@@ -101,7 +101,7 @@ class MedianFilterAction(PlotAction):
self.plot.sigActiveImageChanged.connect(self._updateActiveImage)
def _computeFilteredImage(self, kernelWidth, conditional):
- raise NotImplemented('MedianFilterAction is a an abstract class')
+ raise NotImplementedError('MedianFilterAction is a an abstract class')
def getFilteredImage(self):
"""
diff --git a/silx/gui/plot/backends/BackendBase.py b/silx/gui/plot/backends/BackendBase.py
index 12561b2..45bf785 100644
--- a/silx/gui/plot/backends/BackendBase.py
+++ b/silx/gui/plot/backends/BackendBase.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -189,7 +189,7 @@ class BackendBase(object):
def addMarker(self, x, y, legend, text, color,
selectable, draggable,
- symbol, constraint, overlay):
+ symbol, constraint):
"""Add a point, vertical line or horizontal line marker to the plot.
:param float x: Horizontal position of the marker in graph coordinates.
@@ -221,9 +221,6 @@ class BackendBase(object):
:type constraint: None or a callable that takes the coordinates of
the current cursor position in the plot as input
and that returns the filtered coordinates.
- :param bool overlay: True if marker is an overlay (Default: False).
- This allows for rendering optimization if this
- marker is changed often.
:return: Handle used by the backend to univocally access the marker
"""
return legend
@@ -270,11 +267,13 @@ class BackendBase(object):
"""
pass
- def pickItems(self, x, y):
+ def pickItems(self, x, y, kinds):
"""Get a list of items at a pixel position.
:param float x: The x pixel coord where to pick.
:param float y: The y pixel coord where to pick.
+ :param List[str] kind: List of item kinds to pick.
+ Supported kinds: 'marker', 'curve', 'image'.
:return: All picked items from back to front.
One dict per item,
with 'kind' key in 'curve', 'marker', 'image';
diff --git a/silx/gui/plot/backends/BackendMatplotlib.py b/silx/gui/plot/backends/BackendMatplotlib.py
index b41f20e..f9a1fe5 100644
--- a/silx/gui/plot/backends/BackendMatplotlib.py
+++ b/silx/gui/plot/backends/BackendMatplotlib.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -58,6 +58,59 @@ from . import BackendBase
from .._utils import FLOAT32_MINPOS
+class _MarkerContainer(Container):
+ """Marker artists container supporting draw/remove and text position update
+
+ :param artists:
+ Iterable with either one Line2D or a Line2D and a Text.
+ The use of an iterable if enforced by Container being
+ a subclass of tuple that defines a specific __new__.
+ :param x: X coordinate of the marker (None for horizontal lines)
+ :param y: Y coordinate of the marker (None for vertical lines)
+ """
+
+ def __init__(self, artists, x, y):
+ self.line = artists[0]
+ self.text = artists[1] if len(artists) > 1 else None
+ self.x = x
+ self.y = y
+
+ Container.__init__(self, artists)
+
+ def draw(self, *args, **kwargs):
+ """artist-like draw to broadcast draw to line and text"""
+ self.line.draw(*args, **kwargs)
+ if self.text is not None:
+ self.text.draw(*args, **kwargs)
+
+ def updateMarkerText(self, xmin, xmax, ymin, ymax):
+ """Update marker text position and visibility according to plot limits
+
+ :param xmin: X axis lower limit
+ :param xmax: X axis upper limit
+ :param ymin: Y axis lower limit
+ :param ymax: Y axis upprt limit
+ """
+ if self.text is not None:
+ visible = ((self.x is None or xmin <= self.x <= xmax) and
+ (self.y is None or ymin <= self.y <= ymax))
+ self.text.set_visible(visible)
+
+ if self.x is not None and self.y is None: # vertical line
+ delta = abs(ymax - ymin)
+ if ymin > ymax:
+ ymax = ymin
+ ymax -= 0.005 * delta
+ self.text.set_y(ymax)
+
+ if self.x is None and self.y is not None: # Horizontal line
+ delta = abs(xmax - xmin)
+ if xmin > xmax:
+ xmax = xmin
+ xmax -= 0.005 * delta
+ self.text.set_x(xmax)
+
+
class BackendMatplotlib(BackendBase.BackendBase):
"""Base class for Matplotlib backend without a FigureCanvas.
@@ -356,10 +409,13 @@ class BackendMatplotlib(BackendBase.BackendBase):
self.ax.add_patch(item)
elif shape in ('polygon', 'polylines'):
- xView = xView.reshape(1, -1)
- yView = yView.reshape(1, -1)
- item = Polygon(numpy.vstack((xView, yView)).T,
- closed=(shape == 'polygon'),
+ points = numpy.array((xView, yView)).T
+ if shape == 'polygon':
+ closed = True
+ else: # shape == 'polylines'
+ closed = numpy.all(numpy.equal(points[0], points[-1]))
+ item = Polygon(points,
+ closed=closed,
fill=False,
label=legend,
color=color)
@@ -381,9 +437,14 @@ class BackendMatplotlib(BackendBase.BackendBase):
def addMarker(self, x, y, legend, text, color,
selectable, draggable,
- symbol, constraint, overlay):
+ symbol, constraint):
legend = "__MARKER__" + legend
+ textArtist = None
+
+ xmin, xmax = self.getGraphXLimits()
+ ymin, ymax = self.getGraphYLimits(axis='left')
+
if x is not None and y is not None:
line = self.ax.plot(x, y, label=legend,
linestyle=" ",
@@ -392,49 +453,35 @@ class BackendMatplotlib(BackendBase.BackendBase):
markersize=10.)[-1]
if text is not None:
- xtmp, ytmp = self.ax.transData.transform_point((x, y))
- inv = self.ax.transData.inverted()
- xtmp, ytmp = inv.transform_point((xtmp, ytmp))
-
if symbol is None:
valign = 'baseline'
else:
valign = 'top'
text = " " + text
- line._infoText = self.ax.text(x, ytmp, text,
- color=color,
- horizontalalignment='left',
- verticalalignment=valign)
+ textArtist = self.ax.text(x, y, text,
+ color=color,
+ horizontalalignment='left',
+ verticalalignment=valign)
elif x is not None:
line = self.ax.axvline(x, label=legend, color=color)
if text is not None:
- text = " " + text
- ymin, ymax = self.getGraphYLimits(axis='left')
- delta = abs(ymax - ymin)
- if ymin > ymax:
- ymax = ymin
- ymax -= 0.005 * delta
- line._infoText = self.ax.text(x, ymax, text,
- color=color,
- horizontalalignment='left',
- verticalalignment='top')
+ # Y position will be updated in updateMarkerText call
+ textArtist = self.ax.text(x, 1., " " + text,
+ color=color,
+ horizontalalignment='left',
+ verticalalignment='top')
elif y is not None:
line = self.ax.axhline(y, label=legend, color=color)
if text is not None:
- text = " " + text
- xmin, xmax = self.getGraphXLimits()
- delta = abs(xmax - xmin)
- if xmin > xmax:
- xmax = xmin
- xmax -= 0.005 * delta
- line._infoText = self.ax.text(xmax, y, text,
- color=color,
- horizontalalignment='right',
- verticalalignment='top')
+ # X position will be updated in updateMarkerText call
+ textArtist = self.ax.text(1., y, " " + text,
+ color=color,
+ horizontalalignment='right',
+ verticalalignment='top')
else:
raise RuntimeError('A marker must at least have one coordinate')
@@ -442,19 +489,29 @@ class BackendMatplotlib(BackendBase.BackendBase):
if selectable or draggable:
line.set_picker(5)
- if overlay:
- line.set_animated(True)
- self._overlays.add(line)
+ # All markers are overlays
+ line.set_animated(True)
+ if textArtist is not None:
+ textArtist.set_animated(True)
+
+ artists = [line] if textArtist is None else [line, textArtist]
+ container = _MarkerContainer(artists, x, y)
+ container.updateMarkerText(xmin, xmax, ymin, ymax)
+ self._overlays.add(container)
- return line
+ return container
+
+ def _updateMarkers(self):
+ xmin, xmax = self.ax.get_xbound()
+ ymin, ymax = self.ax.get_ybound()
+ for item in self._overlays:
+ if isinstance(item, _MarkerContainer):
+ item.updateMarkerText(xmin, xmax, ymin, ymax)
# Remove methods
def remove(self, item):
# Warning: It also needs to remove extra stuff if added as for markers
- if hasattr(item, "_infoText"): # For markers text
- item._infoText.remove()
- item._infoText = None
self._overlays.discard(item)
try:
item.remove()
@@ -562,6 +619,8 @@ class BackendMatplotlib(BackendBase.BackendBase):
else:
self.ax.set_ylim(max(ymin, ymax), min(ymin, ymax))
+ self._updateMarkers()
+
def getGraphXLimits(self):
if self._dirtyLimits and self.isKeepDataAspectRatio():
self.replot() # makes sure we get the right limits
@@ -570,6 +629,7 @@ class BackendMatplotlib(BackendBase.BackendBase):
def setGraphXLimits(self, xmin, xmax):
self._dirtyLimits = True
self.ax.set_xlim(min(xmin, xmax), max(xmin, xmax))
+ self._updateMarkers()
def getGraphYLimits(self, axis):
assert axis in ('left', 'right')
@@ -607,6 +667,8 @@ class BackendMatplotlib(BackendBase.BackendBase):
else:
ax.set_ylim(ymax, ymin)
+ self._updateMarkers()
+
# Graph axes
def setXAxisLogarithmic(self, flag):
@@ -814,7 +876,7 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
self._picked.append({'kind': 'curve', 'legend': label,
'indices': event.ind})
- def pickItems(self, x, y):
+ def pickItems(self, x, y, kinds):
self._picked = []
# Weird way to do an explicit picking: Simulate a button press event
@@ -822,7 +884,8 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
cid = self.mpl_connect('pick_event', self._onPick)
self.fig.pick(mouseEvent)
self.mpl_disconnect(cid)
- picked = self._picked
+
+ picked = [p for p in self._picked if p['kind'] in kinds]
self._picked = None
return picked
@@ -882,6 +945,10 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
xLimits, yLimits, yRightLimits = self._limitsBeforeResize
self._limitsBeforeResize = None
+ if (xLimits != self.ax.get_xbound() or
+ yLimits != self.ax.get_ybound()):
+ self._updateMarkers()
+
if xLimits != self.ax.get_xbound():
self._plot.getXAxis()._emitLimitsChanged()
if yLimits != self.ax.get_ybound():
@@ -889,6 +956,7 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
if yRightLimits != self.ax2.get_ybound():
self._plot.getYAxis(axis='right')._emitLimitsChanged()
+
self._drawOverlays()
def replot(self):
diff --git a/silx/gui/plot/backends/BackendOpenGL.py b/silx/gui/plot/backends/BackendOpenGL.py
index c70b03a..3c18f4f 100644
--- a/silx/gui/plot/backends/BackendOpenGL.py
+++ b/silx/gui/plot/backends/BackendOpenGL.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2014-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2014-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -892,11 +892,13 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
for item in self._items.values():
shape2D = item.get('_shape2D')
if shape2D is None:
+ closed = item['shape'] != 'polylines'
shape2D = Shape2D(tuple(zip(item['x'], item['y'])),
fill=item['fill'],
fillColor=item['color'],
stroke=True,
- strokeColor=item['color'])
+ strokeColor=item['color'],
+ strokeClosed=closed)
item['_shape2D'] = shape2D
if ((isXLog and shape2D.xMin < FLOAT32_MINPOS) or
@@ -1032,17 +1034,8 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
data = numpy.array(data, dtype=numpy.float32, order='C')
colormapIsLog = colormap.getNormalization() == 'log'
-
cmapRange = colormap.getColormapRange(data=data)
-
- # Retrieve colormap LUT from name and color array
- colormapDisp = Colormap(name=colormap.getName(),
- normalization=Colormap.LINEAR,
- vmin=0,
- vmax=255,
- colors=colormap.getColormapLUT())
- colormapLut = colormapDisp.applyToData(
- numpy.arange(256, dtype=numpy.uint8))
+ colormapLut = colormap.getNColors(nbColors=256)
image = GLPlotColormap(data,
origin,
@@ -1087,7 +1080,8 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
def addItem(self, x, y, legend, shape, color, fill, overlay, z):
# TODO handle overlay
- if shape not in ('polygon', 'rectangle', 'line', 'vline', 'hline'):
+ if shape not in ('polygon', 'rectangle', 'line',
+ 'vline', 'hline', 'polylines'):
raise NotImplementedError("Unsupported shape {0}".format(shape))
x = numpy.array(x, copy=False)
@@ -1107,6 +1101,9 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
raise RuntimeError(
'Cannot add item with Y <= 0 with Y axis log scale')
+ # Ignore fill for polylines to mimic matplotlib
+ fill = fill if shape != 'polylines' else False
+
self._items[legend] = {
'shape': shape,
'color': Colors.rgba(color),
@@ -1119,8 +1116,7 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
def addMarker(self, x, y, legend, text, color,
selectable, draggable,
- symbol, constraint, overlay):
- # TODO handle overlay
+ symbol, constraint):
if symbol is None:
symbol = '+'
@@ -1227,90 +1223,93 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
self._plotFrame.size[1] - self._plotFrame.margins.bottom - 1)
return xPlot, yPlot
- def pickItems(self, x, y):
+ def pickItems(self, x, y, kinds):
picked = []
dataPos = self.pixelToData(x, y, axis='left', check=True)
if dataPos is not None:
# Pick markers
- for marker in reversed(list(self._markers.values())):
- pixelPos = self.dataToPixel(
- marker['x'], marker['y'], axis='left', check=False)
- if pixelPos is None: # negative coord on a log axis
- continue
-
- if marker['x'] is None: # Horizontal line
- pt1 = self.pixelToData(
- x, y - self._PICK_OFFSET, axis='left', check=False)
- pt2 = self.pixelToData(
- x, y + self._PICK_OFFSET, axis='left', check=False)
- isPicked = (min(pt1[1], pt2[1]) <= marker['y'] <=
- max(pt1[1], pt2[1]))
-
- elif marker['y'] is None: # Vertical line
- pt1 = self.pixelToData(
- x - self._PICK_OFFSET, y, axis='left', check=False)
- pt2 = self.pixelToData(
- x + self._PICK_OFFSET, y, axis='left', check=False)
- isPicked = (min(pt1[0], pt2[0]) <= marker['x'] <=
- max(pt1[0], pt2[0]))
-
- else:
- isPicked = (
- numpy.fabs(x - pixelPos[0]) <= self._PICK_OFFSET and
- numpy.fabs(y - pixelPos[1]) <= self._PICK_OFFSET)
-
- if isPicked:
- picked.append(dict(kind='marker',
- legend=marker['legend']))
-
- # Pick image and curves
- for item in self._plotContent.zOrderedPrimitives(reverse=True):
- if isinstance(item, (GLPlotColormap, GLPlotRGBAImage)):
- pickedPos = item.pick(*dataPos)
- if pickedPos is not None:
- picked.append(dict(kind='image',
- legend=item.info['legend']))
-
- elif isinstance(item, GLPlotCurve2D):
- offset = self._PICK_OFFSET
- if item.marker is not None:
- offset = max(item.markerSize / 2., offset)
- if item.lineStyle is not None:
- offset = max(item.lineWidth / 2., offset)
-
- yAxis = item.info['yAxis']
-
- inAreaPos = self._mouseInPlotArea(x - offset, y - offset)
- dataPos = self.pixelToData(inAreaPos[0], inAreaPos[1],
- axis=yAxis, check=True)
- if dataPos is None:
+ if 'marker' in kinds:
+ for marker in reversed(list(self._markers.values())):
+ pixelPos = self.dataToPixel(
+ marker['x'], marker['y'], axis='left', check=False)
+ if pixelPos is None: # negative coord on a log axis
continue
- xPick0, yPick0 = dataPos
- inAreaPos = self._mouseInPlotArea(x + offset, y + offset)
- dataPos = self.pixelToData(inAreaPos[0], inAreaPos[1],
- axis=yAxis, check=True)
- if dataPos is None:
- continue
- xPick1, yPick1 = dataPos
+ if marker['x'] is None: # Horizontal line
+ pt1 = self.pixelToData(
+ x, y - self._PICK_OFFSET, axis='left', check=False)
+ pt2 = self.pixelToData(
+ x, y + self._PICK_OFFSET, axis='left', check=False)
+ isPicked = (min(pt1[1], pt2[1]) <= marker['y'] <=
+ max(pt1[1], pt2[1]))
+
+ elif marker['y'] is None: # Vertical line
+ pt1 = self.pixelToData(
+ x - self._PICK_OFFSET, y, axis='left', check=False)
+ pt2 = self.pixelToData(
+ x + self._PICK_OFFSET, y, axis='left', check=False)
+ isPicked = (min(pt1[0], pt2[0]) <= marker['x'] <=
+ max(pt1[0], pt2[0]))
- if xPick0 < xPick1:
- xPickMin, xPickMax = xPick0, xPick1
else:
- xPickMin, xPickMax = xPick1, xPick0
+ isPicked = (
+ numpy.fabs(x - pixelPos[0]) <= self._PICK_OFFSET and
+ numpy.fabs(y - pixelPos[1]) <= self._PICK_OFFSET)
- if yPick0 < yPick1:
- yPickMin, yPickMax = yPick0, yPick1
- else:
- yPickMin, yPickMax = yPick1, yPick0
-
- pickedIndices = item.pick(xPickMin, yPickMin,
- xPickMax, yPickMax)
- if pickedIndices:
- picked.append(dict(kind='curve',
- legend=item.info['legend'],
- indices=pickedIndices))
+ if isPicked:
+ picked.append(dict(kind='marker',
+ legend=marker['legend']))
+
+ # Pick image and curves
+ if 'image' in kinds or 'curve' in kinds:
+ for item in self._plotContent.zOrderedPrimitives(reverse=True):
+ if ('image' in kinds and
+ isinstance(item, (GLPlotColormap, GLPlotRGBAImage))):
+ pickedPos = item.pick(*dataPos)
+ if pickedPos is not None:
+ picked.append(dict(kind='image',
+ legend=item.info['legend']))
+
+ elif 'curve' in kinds and isinstance(item, GLPlotCurve2D):
+ offset = self._PICK_OFFSET
+ if item.marker is not None:
+ offset = max(item.markerSize / 2., offset)
+ if item.lineStyle is not None:
+ offset = max(item.lineWidth / 2., offset)
+
+ yAxis = item.info['yAxis']
+
+ inAreaPos = self._mouseInPlotArea(x - offset, y - offset)
+ dataPos = self.pixelToData(inAreaPos[0], inAreaPos[1],
+ axis=yAxis, check=True)
+ if dataPos is None:
+ continue
+ xPick0, yPick0 = dataPos
+
+ inAreaPos = self._mouseInPlotArea(x + offset, y + offset)
+ dataPos = self.pixelToData(inAreaPos[0], inAreaPos[1],
+ axis=yAxis, check=True)
+ if dataPos is None:
+ continue
+ xPick1, yPick1 = dataPos
+
+ if xPick0 < xPick1:
+ xPickMin, xPickMax = xPick0, xPick1
+ else:
+ xPickMin, xPickMax = xPick1, xPick0
+
+ if yPick0 < yPick1:
+ yPickMin, yPickMax = yPick0, yPick1
+ else:
+ yPickMin, yPickMax = yPick1, yPick0
+
+ pickedIndices = item.pick(xPickMin, yPickMin,
+ xPickMax, yPickMax)
+ if pickedIndices:
+ picked.append(dict(kind='curve',
+ legend=item.info['legend'],
+ indices=pickedIndices))
return picked
diff --git a/silx/gui/plot/backends/glutils/GLPlotCurve.py b/silx/gui/plot/backends/glutils/GLPlotCurve.py
index 4433613..124a3da 100644
--- a/silx/gui/plot/backends/glutils/GLPlotCurve.py
+++ b/silx/gui/plot/backends/glutils/GLPlotCurve.py
@@ -606,7 +606,7 @@ class _Points2D(object):
""",
ASTERISK: """
float alphaSymbol(vec2 coord, float size) {
- /* Combining +, x and cirle */
+ /* Combining +, x and circle */
vec2 d_plus = abs(size * (coord - vec2(0.5, 0.5)));
vec2 pos = floor(size * coord) + 0.5;
vec2 d_x = abs(pos.x + vec2(- pos.y, pos.y - size));
diff --git a/silx/gui/plot/backends/glutils/PlotImageFile.py b/silx/gui/plot/backends/glutils/PlotImageFile.py
index f028ee8..83c7ae0 100644
--- a/silx/gui/plot/backends/glutils/PlotImageFile.py
+++ b/silx/gui/plot/backends/glutils/PlotImageFile.py
@@ -93,7 +93,7 @@ def saveImageToFile(data, fileNameOrObj, fileFormat):
assert fileFormat in ('png', 'ppm', 'svg', 'tiff')
if not hasattr(fileNameOrObj, 'write'):
- if sys.version < "3.0":
+ if sys.version_info < (3, ):
fileObj = open(fileNameOrObj, "wb")
else:
if fileFormat in ('png', 'ppm', 'tiff'):
diff --git a/silx/gui/plot/items/__init__.py b/silx/gui/plot/items/__init__.py
index bf39c87..e7957ac 100644
--- a/silx/gui/plot/items/__init__.py
+++ b/silx/gui/plot/items/__init__.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -35,6 +35,7 @@ __date__ = "22/06/2017"
from .core import (Item, LabelsMixIn, DraggableMixIn, ColormapMixIn, # noqa
SymbolMixIn, ColorMixIn, YAxisMixIn, FillMixIn, # noqa
AlphaMixIn, LineMixIn, ItemChangedType) # noqa
+from .complex import ImageComplexData # noqa
from .curve import Curve # noqa
from .histogram import Histogram # noqa
from .image import ImageBase, ImageData, ImageRgba, MaskImageData # noqa
@@ -42,3 +43,7 @@ from .shape import Shape # noqa
from .scatter import Scatter # noqa
from .marker import Marker, XMarker, YMarker # noqa
from .axis import Axis, XAxis, YAxis, YRightAxis
+
+DATA_ITEMS = ImageComplexData, Curve, Histogram, ImageBase, Scatter
+"""Classes of items representing data and to consider to compute data bounds.
+"""
diff --git a/silx/gui/plot/items/axis.py b/silx/gui/plot/items/axis.py
index ff36512..d7e6eff 100644
--- a/silx/gui/plot/items/axis.py
+++ b/silx/gui/plot/items/axis.py
@@ -27,7 +27,7 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "30/08/2017"
+__date__ = "06/12/2017"
import logging
from ... import qt
@@ -66,7 +66,7 @@ class Axis(qt.QObject):
"""Signal emitted when axis autoscale has changed"""
sigLimitsChanged = qt.Signal(float, float)
- """Signal emitted when axis autoscale has changed"""
+ """Signal emitted when axis limits have changed"""
def __init__(self, plot):
"""Constructor
@@ -262,7 +262,7 @@ class Axis(qt.QObject):
def setLimitsConstraints(self, minPos=None, maxPos=None):
"""
- Set a constaints on the position of the axes.
+ Set a constraint on the position of the axes.
:param float minPos: Minimum allowed axis value.
:param float maxPos: Maximum allowed axis value.
@@ -283,7 +283,7 @@ class Axis(qt.QObject):
def setRangeConstraints(self, minRange=None, maxRange=None):
"""
- Set a constaints on the position of the axes.
+ Set a constraint on the position of the axes.
:param float minRange: Minimum allowed left-to-right span across the
view
diff --git a/silx/gui/plot/items/complex.py b/silx/gui/plot/items/complex.py
new file mode 100644
index 0000000..ba57e85
--- /dev/null
+++ b/silx/gui/plot/items/complex.py
@@ -0,0 +1,356 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module provides the :class:`ImageComplexData` of the :class:`Plot`.
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["Vincent Favre-Nicolin", "T. Vincent"]
+__license__ = "MIT"
+__date__ = "19/01/2018"
+
+
+import logging
+import numpy
+
+from silx.third_party import enum
+
+from ..Colormap import Colormap
+from .core import ColormapMixIn, ItemChangedType
+from .image import ImageBase
+
+
+_logger = logging.getLogger(__name__)
+
+
+# Complex colormap functions
+
+def _phase2rgb(colormap, data):
+ """Creates RGBA image with colour-coded phase.
+
+ :param Colormap colormap: The colormap to use
+ :param numpy.ndarray data: The data to convert
+ :return: Array of RGBA colors
+ :rtype: numpy.ndarray
+ """
+ if data.size == 0:
+ return numpy.zeros((0, 0, 4), dtype=numpy.uint8)
+
+ phase = numpy.angle(data)
+ return colormap.applyToData(phase)
+
+
+def _complex2rgbalog(phaseColormap, data, amin=0., dlogs=2, smax=None):
+ """Returns RGBA colors: colour-coded phases and log10(amplitude) in alpha.
+
+ :param Colormap phaseColormap: Colormap to use for the phase
+ :param numpy.ndarray data: the complex data array to convert to RGBA
+ :param float amin: the minimum value for the alpha channel
+ :param float dlogs: amplitude range displayed, in log10 units
+ :param float smax:
+ if specified, all values above max will be displayed with an alpha=1
+ """
+ if data.size == 0:
+ return numpy.zeros((0, 0, 4), dtype=numpy.uint8)
+
+ rgba = _phase2rgb(phaseColormap, data)
+ sabs = numpy.absolute(data)
+ if smax is not None:
+ sabs[sabs > smax] = smax
+ a = numpy.log10(sabs + 1e-20)
+ a -= a.max() - dlogs # display dlogs orders of magnitude
+ rgba[..., 3] = 255 * (amin + a / dlogs * (1 - amin) * (a > 0))
+ return rgba
+
+
+def _complex2rgbalin(phaseColormap, data, gamma=1.0, smax=None):
+ """Returns RGBA colors: colour-coded phase and linear amplitude in alpha.
+
+ :param Colormap phaseColormap: Colormap to use for the phase
+ :param numpy.ndarray data:
+ :param float gamma: Optional exponent gamma applied to the amplitude
+ :param float smax:
+ """
+ if data.size == 0:
+ return numpy.zeros((0, 0, 4), dtype=numpy.uint8)
+
+ rgba = _phase2rgb(phaseColormap, data)
+ a = numpy.absolute(data)
+ if smax is not None:
+ a[a > smax] = smax
+ a /= a.max()
+ rgba[..., 3] = 255 * a**gamma
+ return rgba
+
+
+class ImageComplexData(ImageBase, ColormapMixIn):
+ """Specific plot item to force colormap when using complex colormap.
+
+ This is returning the specific colormap when displaying
+ colored phase + amplitude.
+ """
+
+ class Mode(enum.Enum):
+ """Identify available display mode for complex"""
+ ABSOLUTE = 'absolute'
+ PHASE = 'phase'
+ REAL = 'real'
+ IMAGINARY = 'imaginary'
+ AMPLITUDE_PHASE = 'amplitude_phase'
+ LOG10_AMPLITUDE_PHASE = 'log10_amplitude_phase'
+ SQUARE_AMPLITUDE = 'square_amplitude'
+
+ def __init__(self):
+ ImageBase.__init__(self)
+ ColormapMixIn.__init__(self)
+ self._data = numpy.zeros((0, 0), dtype=numpy.complex64)
+ self._dataByModesCache = {}
+ self._mode = self.Mode.ABSOLUTE
+ self._amplitudeRangeInfo = None, 2
+
+ # Use default from ColormapMixIn
+ colormap = super(ImageComplexData, self).getColormap()
+
+ phaseColormap = Colormap(
+ name='hsv',
+ vmin=-numpy.pi,
+ vmax=numpy.pi)
+ phaseColormap.setEditable(False)
+
+ self._colormaps = { # Default colormaps for all modes
+ self.Mode.ABSOLUTE: colormap,
+ self.Mode.PHASE: phaseColormap,
+ self.Mode.REAL: colormap,
+ self.Mode.IMAGINARY: colormap,
+ self.Mode.AMPLITUDE_PHASE: phaseColormap,
+ self.Mode.LOG10_AMPLITUDE_PHASE: phaseColormap,
+ self.Mode.SQUARE_AMPLITUDE: colormap,
+ }
+
+ def _addBackendRenderer(self, backend):
+ """Update backend renderer"""
+ plot = self.getPlot()
+ assert plot is not None
+ if not self._isPlotLinear(plot):
+ # Do not render with non linear scales
+ return None
+
+ mode = self.getVisualizationMode()
+ if mode in (self.Mode.AMPLITUDE_PHASE,
+ self.Mode.LOG10_AMPLITUDE_PHASE):
+ # For those modes, compute RGBA image here
+ colormap = None
+ data = self.getRgbaImageData(copy=False)
+ else:
+ colormap = self.getColormap()
+ data = self.getData(copy=False)
+
+ if data.size == 0:
+ return None # No data to display
+
+ return backend.addImage(data,
+ legend=self.getLegend(),
+ origin=self.getOrigin(),
+ scale=self.getScale(),
+ z=self.getZValue(),
+ selectable=self.isSelectable(),
+ draggable=self.isDraggable(),
+ colormap=colormap,
+ alpha=self.getAlpha())
+
+
+ def setVisualizationMode(self, mode):
+ """Set the visualization mode to use.
+
+ :param Mode mode:
+ """
+ assert isinstance(mode, self.Mode)
+ assert mode in self._colormaps
+
+ if mode != self._mode:
+ self._mode = mode
+
+ self._updated(ItemChangedType.VISUALIZATION_MODE)
+
+ # Send data updated as value returned by getData has changed
+ self._updated(ItemChangedType.DATA)
+
+ # Update ColormapMixIn colormap
+ colormap = self._colormaps[self._mode]
+ if colormap is not super(ImageComplexData, self).getColormap():
+ super(ImageComplexData, self).setColormap(colormap)
+
+ def getVisualizationMode(self):
+ """Returns the visualization mode in use.
+
+ :rtype: Mode
+ """
+ return self._mode
+
+ def _setAmplitudeRangeInfo(self, max_=None, delta=2):
+ """Set the amplitude range to display for 'log10_amplitude_phase' mode.
+
+ :param max_: Max of the amplitude range.
+ If None it autoscales to data max.
+ :param float delta: Delta range in log10 to display
+ """
+ self._amplitudeRangeInfo = max_, float(delta)
+ self._updated(ItemChangedType.VISUALIZATION_MODE)
+
+ def _getAmplitudeRangeInfo(self):
+ """Returns the amplitude range to use for 'log10_amplitude_phase' mode.
+
+ :return: (max, delta), if max is None, then it autoscales to data max
+ :rtype: 2-tuple"""
+ return self._amplitudeRangeInfo
+
+ def setColormap(self, colormap, mode=None):
+ """Set the colormap for this specific mode.
+
+ :param ~silx.gui.plot.Colormap.Colormap colormap: The colormap
+ :param Mode mode:
+ If specified, set the colormap of this specific mode.
+ Default: current mode.
+ """
+ if mode is None:
+ mode = self.getVisualizationMode()
+
+ self._colormaps[mode] = colormap
+ if mode is self.getVisualizationMode():
+ super(ImageComplexData, self).setColormap(colormap)
+ else:
+ self._updated(ItemChangedType.COLORMAP)
+
+ def getColormap(self, mode=None):
+ """Get the colormap for the (current) mode.
+
+ :param Mode mode:
+ If specified, get the colormap of this specific mode.
+ Default: current mode.
+ :rtype: ~silx.gui.plot.Colormap.Colormap
+ """
+ if mode is None:
+ mode = self.getVisualizationMode()
+
+ return self._colormaps[mode]
+
+ def setData(self, data, copy=True):
+ """"Set the image complex data
+
+ :param numpy.ndarray data: 2D array of complex with 2 dimensions (h, w)
+ :param bool copy: True (Default) to get a copy,
+ False to use internal representation (do not modify!)
+ """
+ data = numpy.array(data, copy=copy)
+ assert data.ndim == 2
+ if not numpy.issubdtype(data.dtype, numpy.complexfloating):
+ _logger.warning(
+ 'Image is not complex, converting it to complex to plot it.')
+ data = numpy.array(data, dtype=numpy.complex64)
+
+ self._data = data
+ self._dataByModesCache = {}
+
+ # TODO hackish data range implementation
+ if self.isVisible():
+ plot = self.getPlot()
+ if plot is not None:
+ plot._invalidateDataRange()
+
+ self._updated(ItemChangedType.DATA)
+
+ def getComplexData(self, copy=True):
+ """Returns the image complex data
+
+ :param bool copy: True (Default) to get a copy,
+ False to use internal representation (do not modify!)
+ :rtype: numpy.ndarray of complex
+ """
+ return numpy.array(self._data, copy=copy)
+
+ def getData(self, copy=True, mode=None):
+ """Returns the image data corresponding to (current) mode.
+
+ The returned data is always floats, to get the complex data, use
+ :meth:`getComplexData`.
+
+ :param bool copy: True (Default) to get a copy,
+ False to use internal representation (do not modify!)
+ :param Mode mode:
+ If specified, get data corresponding to the mode.
+ Default: Current mode.
+ :rtype: numpy.ndarray of float
+ """
+ if mode is None:
+ mode = self.getVisualizationMode()
+
+ if mode not in self._dataByModesCache:
+ # Compute data for mode and store it in cache
+ complexData = self.getComplexData(copy=False)
+ if mode is self.Mode.PHASE:
+ data = numpy.angle(complexData)
+ elif mode is self.Mode.REAL:
+ data = numpy.real(complexData)
+ elif mode is self.Mode.IMAGINARY:
+ data = numpy.imag(complexData)
+ elif mode in (self.Mode.ABSOLUTE,
+ self.Mode.LOG10_AMPLITUDE_PHASE,
+ self.Mode.AMPLITUDE_PHASE):
+ data = numpy.absolute(complexData)
+ elif mode is self.Mode.SQUARE_AMPLITUDE:
+ data = numpy.absolute(complexData) ** 2
+ else:
+ _logger.error(
+ 'Unsupported conversion mode: %s, fallback to absolute',
+ str(mode))
+ data = numpy.absolute(complexData)
+
+ self._dataByModesCache[mode] = data
+
+ return numpy.array(self._dataByModesCache[mode], copy=copy)
+
+ def getRgbaImageData(self, copy=True, mode=None):
+ """Get the displayed RGB(A) image for (current) mode
+
+ :param bool copy: Ignored for this class
+ :param Mode mode:
+ If specified, get data corresponding to the mode.
+ Default: Current mode.
+ :rtype: numpy.ndarray of uint8 of shape (height, width, 4)
+ """
+ if mode is None:
+ mode = self.getVisualizationMode()
+
+ colormap = self.getColormap(mode=mode)
+ if mode is self.Mode.AMPLITUDE_PHASE:
+ data = self.getComplexData(copy=False)
+ return _complex2rgbalin(colormap, data)
+ elif mode is self.Mode.LOG10_AMPLITUDE_PHASE:
+ data = self.getComplexData(copy=False)
+ max_, delta = self._getAmplitudeRangeInfo()
+ return _complex2rgbalog(colormap, data, dlogs=delta, smax=max_)
+ else:
+ data = self.getData(copy=False, mode=mode)
+ return colormap.applyToData(data)
diff --git a/silx/gui/plot/items/core.py b/silx/gui/plot/items/core.py
index 34ac700..bcb6dd1 100644
--- a/silx/gui/plot/items/core.py
+++ b/silx/gui/plot/items/core.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -115,6 +115,9 @@ class ItemChangedType(enum.Enum):
OVERLAY = 'overlayChanged'
"""Item's overlay state changed flag."""
+ VISUALIZATION_MODE = 'visualizationModeChanged'
+ """Item's visualization mode changed flag."""
+
class Item(qt.QObject):
"""Description of an item of the plot"""
@@ -136,7 +139,7 @@ class Item(qt.QObject):
"""
def __init__(self):
- super(Item, self).__init__()
+ qt.QObject.__init__(self)
self._dirty = True
self._plotRef = None
self._visible = True
@@ -312,7 +315,24 @@ class Item(qt.QObject):
# Mix-in classes ##############################################################
-class LabelsMixIn(object):
+class ItemMixInBase(qt.QObject):
+ """Base class for Item mix-in"""
+
+ def _updated(self, event=None, checkVisibility=True):
+ """This is implemented in :class:`Item`.
+
+ Mark the item as dirty (i.e., needing update).
+ This also triggers Plot.replot.
+
+ :param event: The event to send to :attr:`sigItemChanged` signal.
+ :param bool checkVisibility: True to only mark as dirty if visible,
+ False to always mark as dirty.
+ """
+ raise RuntimeError(
+ "Issue with Mix-In class inheritance order")
+
+
+class LabelsMixIn(ItemMixInBase):
"""Mix-in class for items with x and y labels
Setters are private, otherwise it needs to check the plot
@@ -352,7 +372,7 @@ class LabelsMixIn(object):
self._ylabel = str(label)
-class DraggableMixIn(object):
+class DraggableMixIn(ItemMixInBase):
"""Mix-in class for draggable items"""
def __init__(self):
@@ -375,7 +395,7 @@ class DraggableMixIn(object):
self._draggable = bool(draggable)
-class ColormapMixIn(object):
+class ColormapMixIn(ItemMixInBase):
"""Mix-in class for items with colormap"""
def __init__(self):
@@ -389,7 +409,7 @@ class ColormapMixIn(object):
def setColormap(self, colormap):
"""Set the colormap of this image
- :param Colormap colormap: colormap description
+ :param silx.gui.plot.Colormap.Colormap colormap: colormap description
"""
if isinstance(colormap, dict):
colormap = Colormap._fromDict(colormap)
@@ -406,7 +426,7 @@ class ColormapMixIn(object):
self._updated(ItemChangedType.COLORMAP)
-class SymbolMixIn(object):
+class SymbolMixIn(ItemMixInBase):
"""Mix-in class for items with symbol type"""
_DEFAULT_SYMBOL = ''
@@ -415,10 +435,49 @@ class SymbolMixIn(object):
_DEFAULT_SYMBOL_SIZE = 6.0
"""Default marker size of the item"""
+ _SUPPORTED_SYMBOLS = collections.OrderedDict((
+ ('o', 'Circle'),
+ ('d', 'Diamond'),
+ ('s', 'Square'),
+ ('+', 'Plus'),
+ ('x', 'Cross'),
+ ('.', 'Point'),
+ (',', 'Pixel'),
+ ('', 'None')))
+ """Dict of supported symbols"""
+
def __init__(self):
self._symbol = self._DEFAULT_SYMBOL
self._symbol_size = self._DEFAULT_SYMBOL_SIZE
+ @classmethod
+ def getSupportedSymbols(cls):
+ """Returns the list of supported symbol names.
+
+ :rtype: tuple of str
+ """
+ return tuple(cls._SUPPORTED_SYMBOLS.keys())
+
+ @classmethod
+ def getSupportedSymbolNames(cls):
+ """Returns the list of supported symbol human-readable names.
+
+ :rtype: tuple of str
+ """
+ return tuple(cls._SUPPORTED_SYMBOLS.values())
+
+ def getSymbolName(self, symbol=None):
+ """Returns human-readable name for a symbol.
+
+ :param str symbol: The symbol from which to get the name.
+ Default: current symbol.
+ :rtype: str
+ :raise KeyError: if symbol is not in :meth:`getSupportedSymbols`.
+ """
+ if symbol is None:
+ symbol = self.getSymbol()
+ return self._SUPPORTED_SYMBOLS[symbol]
+
def getSymbol(self):
"""Return the point marker type.
@@ -441,11 +500,19 @@ class SymbolMixIn(object):
See :meth:`getSymbol`.
- :param str symbol: Marker type
+ :param str symbol: Marker type or marker name
"""
- assert symbol in ('o', '.', ',', '+', 'x', 'd', 's', '', None)
if symbol is None:
symbol = self._DEFAULT_SYMBOL
+
+ elif symbol not in self.getSupportedSymbols():
+ for symbolCode, name in self._SUPPORTED_SYMBOLS.items():
+ if name.lower() == symbol.lower():
+ symbol = symbolCode
+ break
+ else:
+ raise ValueError('Unsupported symbol %s' % str(symbol))
+
if symbol != self._symbol:
self._symbol = symbol
self._updated(ItemChangedType.SYMBOL)
@@ -471,7 +538,7 @@ class SymbolMixIn(object):
self._updated(ItemChangedType.SYMBOL_SIZE)
-class LineMixIn(object):
+class LineMixIn(ItemMixInBase):
"""Mix-in class for item with line"""
_DEFAULT_LINEWIDTH = 1.
@@ -531,7 +598,7 @@ class LineMixIn(object):
self._updated(ItemChangedType.LINE_STYLE)
-class ColorMixIn(object):
+class ColorMixIn(ItemMixInBase):
"""Mix-in class for item with color"""
_DEFAULT_COLOR = (0., 0., 0., 1.)
@@ -570,7 +637,7 @@ class ColorMixIn(object):
self._updated(ItemChangedType.COLOR)
-class YAxisMixIn(object):
+class YAxisMixIn(ItemMixInBase):
"""Mix-in class for item with yaxis"""
_DEFAULT_YAXIS = 'left'
@@ -600,7 +667,7 @@ class YAxisMixIn(object):
self._updated(ItemChangedType.YAXIS)
-class FillMixIn(object):
+class FillMixIn(ItemMixInBase):
"""Mix-in class for item with fill"""
def __init__(self):
@@ -624,7 +691,7 @@ class FillMixIn(object):
self._updated(ItemChangedType.FILL)
-class AlphaMixIn(object):
+class AlphaMixIn(ItemMixInBase):
"""Mix-in class for item with opacity"""
def __init__(self):
diff --git a/silx/gui/plot/items/image.py b/silx/gui/plot/items/image.py
index acf7bf6..99a916a 100644
--- a/silx/gui/plot/items/image.py
+++ b/silx/gui/plot/items/image.py
@@ -28,7 +28,7 @@ of the :class:`Plot`.
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "27/06/2017"
+__date__ = "20/10/2017"
from collections import Sequence
@@ -38,7 +38,6 @@ import numpy
from .core import (Item, LabelsMixIn, DraggableMixIn, ColormapMixIn,
AlphaMixIn, ItemChangedType)
-from ..Colors import applyColormapToData
_logger = logging.getLogger(__name__)
@@ -62,7 +61,7 @@ def _convertImageToRgba32(image, copy=True):
assert image.shape[-1] in (3, 4)
# Convert type to uint8
- if image.dtype.name != 'uin8':
+ if image.dtype.name != 'uint8':
if image.dtype.kind == 'f': # Float in [0, 1]
image = (numpy.clip(image, 0., 1.) * 255).astype(numpy.uint8)
elif image.dtype.kind == 'b': # boolean
@@ -334,7 +333,7 @@ class ImageData(ImageBase, ColormapMixIn):
_logger.warning(
'Converting boolean image to int8 to plot it.')
data = numpy.array(data, copy=False, dtype=numpy.int8)
- elif numpy.issubdtype(data.dtype, numpy.complex):
+ elif numpy.iscomplexobj(data):
_logger.warning(
'Converting complex image to absolute value to plot it.')
data = numpy.absolute(data)
diff --git a/silx/gui/plot/items/marker.py b/silx/gui/plot/items/marker.py
index 5f930b7..8f79033 100644
--- a/silx/gui/plot/items/marker.py
+++ b/silx/gui/plot/items/marker.py
@@ -69,8 +69,7 @@ class _BaseMarker(Item, DraggableMixIn, ColorMixIn):
selectable=self.isSelectable(),
draggable=self.isDraggable(),
symbol=symbol,
- constraint=self.getConstraint(),
- overlay=self.isOverlay())
+ constraint=self.getConstraint())
def isOverlay(self):
"""Return true if marker is drawn as an overlay.
diff --git a/silx/gui/plot/matplotlib/Colormap.py b/silx/gui/plot/matplotlib/Colormap.py
index a86d76e..d035605 100644
--- a/silx/gui/plot/matplotlib/Colormap.py
+++ b/silx/gui/plot/matplotlib/Colormap.py
@@ -168,70 +168,16 @@ def getScalarMappable(colormap, data=None):
colors = colors.astype(numpy.float32) / 255.
cmap = matplotlib.colors.ListedColormap(colors)
+ vmin, vmax = colormap.getColormapRange(data)
if colormap.getNormalization().startswith('log'):
- vmin, vmax = None, None
- if not colormap.isAutoscale():
- if colormap.getVMin() > 0.:
- vmin = colormap.getVMin()
- if colormap.getVMax() > 0.:
- vmax = colormap.getVMax()
-
- if vmin is None or vmax is None:
- _logger.warning('Log colormap with negative bounds, ' +
- 'changing bounds to positive ones.')
- elif vmin > vmax:
- _logger.warning('Colormap bounds are inverted.')
- vmin, vmax = vmax, vmin
-
- # Set unset/negative bounds to positive bounds
- if vmin is None or vmax is None:
- # Convert to numpy array
- data = numpy.array(data if data is not None else [], copy=False)
-
- if data.size > 0:
- finiteData = data[numpy.isfinite(data)]
- posData = finiteData[finiteData > 0]
- if vmax is None:
- # 1. as an ultimate fallback
- vmax = posData.max() if posData.size > 0 else 1.
- if vmin is None:
- vmin = posData.min() if posData.size > 0 else vmax
- if vmin > vmax:
- vmin = vmax
- else:
- vmin, vmax = 1., 1.
-
norm = matplotlib.colors.LogNorm(vmin, vmax)
-
else: # Linear normalization
- if colormap.isAutoscale():
- # Convert to numpy array
- data = numpy.array(data if data is not None else [], copy=False)
-
- if data.size == 0:
- vmin, vmax = 1., 1.
- else:
- finiteData = data[numpy.isfinite(data)]
- if finiteData.size > 0:
- vmin = finiteData.min()
- vmax = finiteData.max()
- else:
- vmin, vmax = 1., 1.
-
- else:
- vmin = colormap.getVMin()
- vmax = colormap.getVMax()
- if vmin > vmax:
- _logger.warning('Colormap bounds are inverted.')
- vmin, vmax = vmax, vmin
-
norm = matplotlib.colors.Normalize(vmin, vmax)
return matplotlib.cm.ScalarMappable(norm=norm, cmap=cmap)
-def applyColormapToData(data,
- colormap):
+def applyColormapToData(data, colormap):
"""Apply a colormap to the data and returns the RGBA image
This supports data of any dimensions (not only of dimension 2).
diff --git a/silx/gui/plot/matplotlib/__init__.py b/silx/gui/plot/matplotlib/__init__.py
index be9cb9a..384d049 100644
--- a/silx/gui/plot/matplotlib/__init__.py
+++ b/silx/gui/plot/matplotlib/__init__.py
@@ -59,6 +59,11 @@ elif qt.BINDING == 'PyQt4':
matplotlib.rcParams['backend'] = 'Qt4Agg'
import matplotlib.backends.backend_qt4agg as backend
+elif qt.BINDING == 'PySide2':
+ matplotlib.rcParams['backend'] = 'Qt5Agg'
+ matplotlib.rcParams['backend.qt5'] = 'PySide2'
+ import matplotlib.backends.backend_qt5agg as backend
+
elif qt.BINDING == 'PyQt5':
matplotlib.rcParams['backend'] = 'Qt5Agg'
import matplotlib.backends.backend_qt5agg as backend
diff --git a/silx/gui/plot/test/__init__.py b/silx/gui/plot/test/__init__.py
index 07338b6..154a70a 100644
--- a/silx/gui/plot/test/__init__.py
+++ b/silx/gui/plot/test/__init__.py
@@ -24,7 +24,7 @@
# ###########################################################################*/
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "04/08/2017"
+__date__ = "28/11/2017"
import unittest
@@ -52,6 +52,7 @@ from . import testUtilsAxis
from . import testLimitConstraints
from . import testComplexImageView
from . import testImageView
+from . import testSaveAction
def suite():
@@ -79,5 +80,6 @@ def suite():
testUtilsAxis.suite(),
testLimitConstraints.suite(),
testComplexImageView.suite(),
- testImageView.suite()])
+ testImageView.suite(),
+ testSaveAction.suite()])
return test_suite
diff --git a/silx/gui/plot/test/testColormap.py b/silx/gui/plot/test/testColormap.py
index aa285d3..4888a7c 100644
--- a/silx/gui/plot/test/testColormap.py
+++ b/silx/gui/plot/test/testColormap.py
@@ -29,12 +29,14 @@ from __future__ import absolute_import
__authors__ = ["H.Payno"]
__license__ = "MIT"
-__date__ = "05/12/2016"
+__date__ = "17/01/2018"
import unittest
import numpy
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
from silx.gui.plot.Colormap import Colormap
+from silx.gui.plot.Colormap import preferredColormaps, setPreferredColormaps
+from silx.utils.exceptions import NotEditableError
class TestDictAPI(unittest.TestCase):
@@ -134,14 +136,11 @@ class TestDictAPI(unittest.TestCase):
'autoscale': False
}
with self.assertRaises(ValueError):
- colormapObject = Colormap._fromDict(clm_dict)
+ Colormap._fromDict(clm_dict)
class TestObjectAPI(ParametricTestCase):
"""Test the new Object API of the colormap"""
- def setUp(self):
- signalHasBeenEmitting = False
-
def testVMinVMax(self):
"""Test getter and setter associated to vmin and vmax values"""
vmin = 1.0
@@ -277,10 +276,73 @@ class TestObjectAPI(ParametricTestCase):
self.assertEqual(image.shape[-1], 4)
self.assertEqual(image.shape[:-1], data.shape)
+ def testGetNColors(self):
+ """Test getNColors method"""
+ # specific LUT
+ colormap = Colormap(name=None,
+ colors=((0, 0, 0), (1, 1, 1)),
+ vmin=1000,
+ vmax=2000)
+ colors = colormap.getNColors()
+ self.assertTrue(numpy.all(numpy.equal(
+ colors,
+ ((0, 0, 0, 255), (255, 255, 255, 255)))))
+
+ def testEditableMode(self):
+ """Make sure the colormap will raise NotEditableError when try to
+ change a colormap not editable"""
+ colormap = Colormap()
+ colormap.setEditable(False)
+ with self.assertRaises(NotEditableError):
+ colormap.setVRange(0., 1.)
+ with self.assertRaises(NotEditableError):
+ colormap.setVMin(1.)
+ with self.assertRaises(NotEditableError):
+ colormap.setVMax(1.)
+ with self.assertRaises(NotEditableError):
+ colormap.setNormalization(Colormap.LOGARITHM)
+ with self.assertRaises(NotEditableError):
+ colormap.setName('magma')
+ with self.assertRaises(NotEditableError):
+ colormap.setColormapLUT(numpy.array([0, 1]))
+ with self.assertRaises(NotEditableError):
+ colormap._setFromDict(colormap._toDict())
+ state = colormap.saveState()
+ with self.assertRaises(NotEditableError):
+ colormap.restoreState(state)
+
+
+class TestPreferredColormaps(unittest.TestCase):
+ """Test get|setPreferredColormaps functions"""
+
+ def setUp(self):
+ # Save preferred colormaps
+ self._colormaps = preferredColormaps()
+
+ def tearDown(self):
+ # Restore saved preferred colormaps
+ setPreferredColormaps(self._colormaps)
+
+ def test(self):
+ colormaps = 'viridis', 'magma'
+
+ setPreferredColormaps(colormaps)
+ self.assertEqual(preferredColormaps(), colormaps)
+
+ with self.assertRaises(ValueError):
+ setPreferredColormaps(())
+
+ with self.assertRaises(ValueError):
+ setPreferredColormaps(('This is not a colormap',))
+
+ colormaps = 'red', 'green'
+ setPreferredColormaps(('This is not a colormap',) + colormaps)
+ self.assertEqual(preferredColormaps(), colormaps)
+
def suite():
test_suite = unittest.TestSuite()
- for ui in (TestDictAPI, TestObjectAPI):
+ for ui in (TestDictAPI, TestObjectAPI, TestPreferredColormaps):
test_suite.addTest(
unittest.defaultTestLoader.loadTestsFromTestCase(ui))
diff --git a/silx/gui/plot/test/testColormapDialog.py b/silx/gui/plot/test/testColormapDialog.py
index d016548..8087369 100644
--- a/silx/gui/plot/test/testColormapDialog.py
+++ b/silx/gui/plot/test/testColormapDialog.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -26,7 +26,7 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "05/12/2016"
+__date__ = "17/01/2018"
import doctest
@@ -35,6 +35,12 @@ import unittest
from silx.gui.test.utils import qWaitForWindowExposedAndActivate
from silx.gui import qt
from silx.gui.plot import ColormapDialog
+from silx.gui.test.utils import TestCaseQt
+from silx.gui.plot.Colormap import Colormap, preferredColormaps
+from silx.utils.testutils import ParametricTestCase
+from silx.gui.plot.PlotWindow import PlotWindow
+
+import numpy.random
# Makes sure a QApplication exists
@@ -58,9 +64,320 @@ cmapDocTestSuite = doctest.DocTestSuite(ColormapDialog, tearDown=_tearDownQt)
"""Test suite of tests from the module's docstrings."""
+class TestColormapDialog(TestCaseQt, ParametricTestCase):
+ """Test the ColormapDialog."""
+ def setUp(self):
+ TestCaseQt.setUp(self)
+ ParametricTestCase.setUp(self)
+ self.colormap = Colormap(name='gray', vmin=10.0, vmax=20.0,
+ normalization='linear')
+
+ self.colormapDiag = ColormapDialog.ColormapDialog()
+ self.colormapDiag.setAttribute(qt.Qt.WA_DeleteOnClose)
+
+ def tearDown(self):
+ del self.colormapDiag
+ ParametricTestCase.tearDown(self)
+ TestCaseQt.tearDown(self)
+
+ def testGUIEdition(self):
+ """Make sure the colormap is correctly edited and also that the
+ modification are correctly updated if an other colormapdialog is
+ editing the same colormap"""
+ colormapDiag2 = ColormapDialog.ColormapDialog()
+ colormapDiag2.setColormap(self.colormap)
+ self.colormapDiag.setColormap(self.colormap)
+
+ self.colormapDiag._comboBoxColormap.setCurrentName('red')
+ self.colormapDiag._normButtonLog.setChecked(True)
+ self.assertTrue(self.colormap.getName() == 'red')
+ self.assertTrue(self.colormapDiag.getColormap().getName() == 'red')
+ self.assertTrue(self.colormap.getNormalization() == 'log')
+ self.assertTrue(self.colormap.getVMin() == 10)
+ self.assertTrue(self.colormap.getVMax() == 20)
+ # checked second colormap dialog
+ self.assertTrue(colormapDiag2._comboBoxColormap.getCurrentName() == 'red')
+ self.assertTrue(colormapDiag2._normButtonLog.isChecked())
+ self.assertTrue(int(colormapDiag2._minValue.getValue()) == 10)
+ self.assertTrue(int(colormapDiag2._maxValue.getValue()) == 20)
+ colormapDiag2.close()
+
+ def testGUIModalOk(self):
+ """Make sure the colormap is modified if gone through accept"""
+ assert self.colormap.isAutoscale() is False
+ self.colormapDiag.setModal(True)
+ self.colormapDiag.show()
+ self.colormapDiag.setColormap(self.colormap)
+ self.assertTrue(self.colormap.getVMin() is not None)
+ self.colormapDiag._minValue.setValue(None)
+ self.assertTrue(self.colormap.getVMin() is None)
+ self.colormapDiag._maxValue.setValue(None)
+ self.mouseClick(
+ widget=self.colormapDiag._buttonsModal.button(qt.QDialogButtonBox.Ok),
+ button=qt.Qt.LeftButton
+ )
+ self.assertTrue(self.colormap.getVMin() is None)
+ self.assertTrue(self.colormap.getVMax() is None)
+ self.assertTrue(self.colormap.isAutoscale() is True)
+
+ def testGUIModalCancel(self):
+ """Make sure the colormap is not modified if gone through reject"""
+ assert self.colormap.isAutoscale() is False
+ self.colormapDiag.setModal(True)
+ self.colormapDiag.show()
+ self.colormapDiag.setColormap(self.colormap)
+ self.assertTrue(self.colormap.getVMin() is not None)
+ self.colormapDiag._minValue.setValue(None)
+ self.assertTrue(self.colormap.getVMin() is None)
+ self.mouseClick(
+ widget=self.colormapDiag._buttonsModal.button(qt.QDialogButtonBox.Cancel),
+ button=qt.Qt.LeftButton
+ )
+ self.assertTrue(self.colormap.getVMin() is not None)
+
+ def testGUIModalClose(self):
+ assert self.colormap.isAutoscale() is False
+ self.colormapDiag.setModal(False)
+ self.colormapDiag.show()
+ self.colormapDiag.setColormap(self.colormap)
+ self.assertTrue(self.colormap.getVMin() is not None)
+ self.colormapDiag._minValue.setValue(None)
+ self.assertTrue(self.colormap.getVMin() is None)
+ self.mouseClick(
+ widget=self.colormapDiag._buttonsNonModal.button(qt.QDialogButtonBox.Close),
+ button=qt.Qt.LeftButton
+ )
+ self.assertTrue(self.colormap.getVMin() is None)
+
+ def testGUIModalReset(self):
+ assert self.colormap.isAutoscale() is False
+ self.colormapDiag.setModal(False)
+ self.colormapDiag.show()
+ self.colormapDiag.setColormap(self.colormap)
+ self.assertTrue(self.colormap.getVMin() is not None)
+ self.colormapDiag._minValue.setValue(None)
+ self.assertTrue(self.colormap.getVMin() is None)
+ self.mouseClick(
+ widget=self.colormapDiag._buttonsNonModal.button(qt.QDialogButtonBox.Reset),
+ button=qt.Qt.LeftButton
+ )
+ self.assertTrue(self.colormap.getVMin() is not None)
+ self.colormapDiag.close()
+
+ def testGUIClose(self):
+ """Make sure the colormap is modify if go through reject"""
+ assert self.colormap.isAutoscale() is False
+ self.colormapDiag.show()
+ self.colormapDiag.setColormap(self.colormap)
+ self.assertTrue(self.colormap.getVMin() is not None)
+ self.colormapDiag._minValue.setValue(None)
+ self.assertTrue(self.colormap.getVMin() is None)
+ self.colormapDiag.close()
+ self.assertTrue(self.colormap.getVMin() is None)
+
+ def testSetColormapIsCorrect(self):
+ """Make sure the interface fir the colormap when set a new colormap"""
+ self.colormap.setName('red')
+ for norm in (Colormap.NORMALIZATIONS):
+ for autoscale in (True, False):
+ if autoscale is True:
+ self.colormap.setVRange(None, None)
+ else:
+ self.colormap.setVRange(11, 101)
+ self.colormap.setNormalization(norm)
+ with self.subTest(colormap=self.colormap):
+ self.colormapDiag.setColormap(self.colormap)
+ self.assertTrue(
+ self.colormapDiag._normButtonLinear.isChecked() == (norm is Colormap.LINEAR))
+ self.assertTrue(
+ self.colormapDiag._comboBoxColormap.getCurrentName() == 'red')
+ self.assertTrue(
+ self.colormapDiag._minValue.isAutoChecked() == autoscale)
+ self.assertTrue(
+ self.colormapDiag._maxValue.isAutoChecked() == autoscale)
+ if autoscale is False:
+ self.assertTrue(self.colormapDiag._minValue.getValue() == 11)
+ self.assertTrue(self.colormapDiag._maxValue.getValue() == 101)
+ self.assertTrue(self.colormapDiag._minValue.isEnabled())
+ self.assertTrue(self.colormapDiag._maxValue.isEnabled())
+ else:
+ self.assertFalse(self.colormapDiag._minValue._numVal.isEnabled())
+ self.assertFalse(self.colormapDiag._maxValue._numVal.isEnabled())
+
+ def testColormapDel(self):
+ """Check behavior if the colormap has been deleted outside. For now
+ we make sure the colormap is still running and nothing more"""
+ self.colormapDiag.setColormap(self.colormap)
+ self.colormapDiag.show()
+ del self.colormap
+ self.assertTrue(self.colormapDiag.getColormap() is None)
+ self.colormapDiag._comboBoxColormap.setCurrentName('blue')
+
+ def testColormapEditedOutside(self):
+ """Make sure the GUI is still up to date if the colormap is modified
+ outside"""
+ self.colormapDiag.setColormap(self.colormap)
+ self.colormapDiag.show()
+
+ self.colormap.setName('red')
+ self.assertTrue(
+ self.colormapDiag._comboBoxColormap.getCurrentName() == 'red')
+ self.colormap.setNormalization(Colormap.LOGARITHM)
+ self.assertFalse(self.colormapDiag._normButtonLinear.isChecked())
+ self.colormap.setVRange(11, 201)
+ self.assertTrue(self.colormapDiag._minValue.getValue() == 11)
+ self.assertTrue(self.colormapDiag._maxValue.getValue() == 201)
+ self.assertTrue(self.colormapDiag._minValue._numVal.isEnabled())
+ self.assertTrue(self.colormapDiag._maxValue._numVal.isEnabled())
+ self.assertFalse(self.colormapDiag._minValue.isAutoChecked())
+ self.assertFalse(self.colormapDiag._maxValue.isAutoChecked())
+ self.colormap.setVRange(None, None)
+ self.assertFalse(self.colormapDiag._minValue._numVal.isEnabled())
+ self.assertFalse(self.colormapDiag._maxValue._numVal.isEnabled())
+ self.assertTrue(self.colormapDiag._minValue.isAutoChecked())
+ self.assertTrue(self.colormapDiag._maxValue.isAutoChecked())
+
+ def testSetColormapScenario(self):
+ """Test of a simple scenario of a colormap dialog editing several
+ colormap"""
+ colormap1 = Colormap(name='gray', vmin=10.0, vmax=20.0,
+ normalization='linear')
+ colormap2 = Colormap(name='red', vmin=10.0, vmax=20.0,
+ normalization='log')
+ colormap3 = Colormap(name='blue', vmin=None, vmax=None,
+ normalization='linear')
+ self.colormapDiag.setColormap(self.colormap)
+ self.colormapDiag.setColormap(colormap1)
+ del colormap1
+ self.colormapDiag.setColormap(colormap2)
+ del colormap2
+ self.colormapDiag.setColormap(colormap3)
+ del colormap3
+
+ def testNotPreferredColormap(self):
+ """Test that the colormapEditor is able to edit a colormap which is not
+ part of the 'prefered colormap'
+ """
+ def getFirstNotPreferredColormap():
+ cms = Colormap.getSupportedColormaps()
+ preferred = preferredColormaps()
+ for cm in cms:
+ if cm not in preferred:
+ return cm
+ return None
+
+ colormapName = getFirstNotPreferredColormap()
+ assert colormapName is not None
+ colormap = Colormap(name=colormapName)
+ self.colormapDiag.setColormap(colormap)
+ self.colormapDiag.show()
+ cb = self.colormapDiag._comboBoxColormap
+ self.assertTrue(cb.getCurrentName() == colormapName)
+ cb.setCurrentIndex(0)
+ index = cb.findColormap(colormapName)
+ assert index is not 0 # if 0 then the rest of the test has no sense
+ cb.setCurrentIndex(index)
+ self.assertTrue(cb.getCurrentName() == colormapName)
+
+ def testColormapEditableMode(self):
+ """Test that the colormapDialog is correctly updated when changing the
+ colormap editable status"""
+ colormap = Colormap(normalization='linear', vmin=1.0, vmax=10.0)
+ self.colormapDiag.setColormap(colormap)
+ for editable in (True, False):
+ with self.subTest(editable=editable):
+ colormap.setEditable(editable)
+ self.assertTrue(
+ self.colormapDiag._comboBoxColormap.isEnabled() is editable)
+ self.assertTrue(
+ self.colormapDiag._minValue.isEnabled() is editable)
+ self.assertTrue(
+ self.colormapDiag._maxValue.isEnabled() is editable)
+ self.assertTrue(
+ self.colormapDiag._normButtonLinear.isEnabled() is editable)
+ self.assertTrue(
+ self.colormapDiag._normButtonLog.isEnabled() is editable)
+
+ # Make sure the reset button is also set to enable when edition mode is
+ # False
+ self.colormapDiag.setModal(False)
+ colormap.setEditable(True)
+ self.colormapDiag._normButtonLog.setChecked(True)
+ resetButton = self.colormapDiag._buttonsNonModal.button(qt.QDialogButtonBox.Reset)
+ self.assertTrue(resetButton.isEnabled())
+ colormap.setEditable(False)
+ self.assertFalse(resetButton.isEnabled())
+
+
+class TestColormapAction(TestCaseQt):
+ def setUp(self):
+ TestCaseQt.setUp(self)
+ self.plot = PlotWindow()
+ self.plot.setAttribute(qt.Qt.WA_DeleteOnClose)
+
+ self.colormap1 = Colormap(name='blue', vmin=0.0, vmax=1.0,
+ normalization='linear')
+ self.colormap2 = Colormap(name='red', vmin=10.0, vmax=100.0,
+ normalization='log')
+ self.defaultColormap = self.plot.getDefaultColormap()
+
+ self.plot.getColormapAction()._actionTriggered(checked=True)
+ self.colormapDialog = self.plot.getColormapAction()._dialog
+ self.colormapDialog.setAttribute(qt.Qt.WA_DeleteOnClose)
+
+ def tearDown(self):
+ self.colormapDialog.close()
+ self.plot.close()
+ del self.colormapDialog
+ del self.plot
+ TestCaseQt.tearDown(self)
+
+ def testActiveColormap(self):
+ self.assertTrue(self.colormapDialog.getColormap() is self.defaultColormap)
+
+ self.plot.addImage(data=numpy.random.rand(10, 10), legend='img1',
+ replace=False, origin=(0, 0),
+ colormap=self.colormap1)
+ self.plot.setActiveImage('img1')
+ self.assertTrue(self.colormapDialog.getColormap() is self.colormap1)
+
+ self.plot.addImage(data=numpy.random.rand(10, 10), legend='img2',
+ replace=False, origin=(0, 0),
+ colormap=self.colormap2)
+ self.plot.addImage(data=numpy.random.rand(10, 10), legend='img3',
+ replace=False, origin=(0, 0))
+
+ self.plot.setActiveImage('img3')
+ self.assertTrue(self.colormapDialog.getColormap() is self.defaultColormap)
+ self.plot.getActiveImage().setColormap(self.colormap2)
+ self.assertTrue(self.colormapDialog.getColormap() is self.colormap2)
+
+ self.plot.remove('img2')
+ self.plot.remove('img3')
+ self.plot.remove('img1')
+ self.assertTrue(self.colormapDialog.getColormap() is self.defaultColormap)
+
+ def testShowHideColormapDialog(self):
+ self.plot.getColormapAction()._actionTriggered(checked=False)
+ self.assertFalse(self.plot.getColormapAction().isChecked())
+ self.plot.getColormapAction()._actionTriggered(checked=True)
+ self.assertTrue(self.plot.getColormapAction().isChecked())
+ self.plot.addImage(data=numpy.random.rand(10, 10), legend='img1',
+ replace=False, origin=(0, 0),
+ colormap=self.colormap1)
+ self.colormap1.setName('red')
+ self.plot.getColormapAction()._actionTriggered()
+ self.colormap1.setName('blue')
+ self.colormapDialog.close()
+ self.assertFalse(self.plot.getColormapAction().isChecked())
+
+
def suite():
test_suite = unittest.TestSuite()
test_suite.addTest(cmapDocTestSuite)
+ for testClass in (TestColormapDialog, TestColormapAction):
+ test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(
+ testClass))
return test_suite
diff --git a/silx/gui/plot/test/testColors.py b/silx/gui/plot/test/testColors.py
index 18f0902..4d617eb 100644
--- a/silx/gui/plot/test/testColors.py
+++ b/silx/gui/plot/test/testColors.py
@@ -26,13 +26,13 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "05/12/2016"
+__date__ = "17/01/2018"
import numpy
import unittest
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
from silx.gui.plot import Colors
from silx.gui.plot.Colormap import Colormap
diff --git a/silx/gui/plot/test/testComplexImageView.py b/silx/gui/plot/test/testComplexImageView.py
index f8ec370..1933a95 100644
--- a/silx/gui/plot/test/testComplexImageView.py
+++ b/silx/gui/plot/test/testComplexImageView.py
@@ -26,14 +26,14 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "14/09/2017"
+__date__ = "17/01/2018"
import unittest
import logging
import numpy
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
from silx.gui.plot import ComplexImageView
from .utils import PlotWidgetTestCase
diff --git a/silx/gui/plot/test/testCurvesROIWidget.py b/silx/gui/plot/test/testCurvesROIWidget.py
index 716960a..0fd2456 100644
--- a/silx/gui/plot/test/testCurvesROIWidget.py
+++ b/silx/gui/plot/test/testCurvesROIWidget.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,9 +24,9 @@
# ###########################################################################*/
"""Basic tests for CurvesROIWidget"""
-__authors__ = ["T. Vincent"]
+__authors__ = ["T. Vincent", "P. Knobel"]
__license__ = "MIT"
-__date__ = "15/05/2017"
+__date__ = "16/11/2017"
import logging
@@ -105,6 +105,19 @@ class TestCurvesROIWidget(TestCaseQt):
del self.tmpFile
+ def testMiddleMarker(self):
+ """Test with middle marker enabled"""
+ self.widget.roiWidget.setMiddleROIMarkerFlag(True)
+
+ # Add a ROI
+ self.mouseClick(self.widget.roiWidget.addButton, qt.Qt.LeftButton)
+
+ xleftMarker = self.plot._getMarker(legend='ROI min').getXPosition()
+ xMiddleMarker = self.plot._getMarker(legend='ROI middle').getXPosition()
+ xRightMarker = self.plot._getMarker(legend='ROI max').getXPosition()
+ self.assertAlmostEqual(xMiddleMarker,
+ xleftMarker + (xRightMarker - xleftMarker) / 2.)
+
def testCalculation(self):
x = numpy.arange(100.)
y = numpy.arange(100.)
diff --git a/silx/gui/plot/test/testItem.py b/silx/gui/plot/test/testItem.py
index 8c15bb7..1ba09c6 100644
--- a/silx/gui/plot/test/testItem.py
+++ b/silx/gui/plot/test/testItem.py
@@ -58,7 +58,7 @@ class TestSigItemChangedSignal(PlotWidgetTestCase):
curve.setData(numpy.arange(100), numpy.arange(100))
# SymbolMixIn
- curve.setSymbol('o')
+ curve.setSymbol('Circle')
curve.setSymbol('d')
curve.setSymbolSize(20)
@@ -220,10 +220,28 @@ class TestSigItemChangedSignal(PlotWidgetTestCase):
(ItemChangedType.DATA,)])
+class TestSymbol(PlotWidgetTestCase):
+ """Test item's symbol """
+
+ def test(self):
+ """Test sigItemChanged for curve"""
+ self.plot.addCurve(numpy.arange(10), numpy.arange(10), legend='test')
+ curve = self.plot.getCurve('test')
+
+ # SymbolMixIn
+ curve.setSymbol('o')
+ name = curve.getSymbolName()
+ self.assertEqual('Circle', name)
+
+ name = curve.getSymbolName('d')
+ self.assertEqual('Diamond', name)
+
+
def suite():
test_suite = unittest.TestSuite()
loadTests = unittest.defaultTestLoader.loadTestsFromTestCase
test_suite.addTest(loadTests(TestSigItemChangedSignal))
+ test_suite.addTest(loadTests(TestSymbol))
return test_suite
diff --git a/silx/gui/plot/test/testMaskToolsWidget.py b/silx/gui/plot/test/testMaskToolsWidget.py
index 191bbe0..40c1db3 100644
--- a/silx/gui/plot/test/testMaskToolsWidget.py
+++ b/silx/gui/plot/test/testMaskToolsWidget.py
@@ -26,7 +26,7 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "01/09/2017"
+__date__ = "17/01/2018"
import logging
@@ -36,7 +36,8 @@ import unittest
import numpy
from silx.gui import qt
-from silx.test.utils import temp_dir, ParametricTestCase
+from silx.test.utils import temp_dir
+from silx.utils.testutils import ParametricTestCase
from silx.gui.test.utils import getQToolButtonFromAction
from silx.gui.plot import PlotWindow, MaskToolsWidget
from .utils import PlotWidgetTestCase
@@ -84,8 +85,10 @@ class TestMaskToolsWidget(PlotWidgetTestCase, ParametricTestCase):
pos0 = xCenter, yCenter
pos1 = xCenter + offset, yCenter + offset
+ self.mouseMove(plot, pos=(0, 0))
self.mouseMove(plot, pos=pos0)
self.mousePress(plot, qt.Qt.LeftButton, pos=pos0)
+ self.mouseMove(plot, pos=(0, 0))
self.mouseMove(plot, pos=pos1)
self.mouseRelease(plot, qt.Qt.LeftButton, pos=pos1)
@@ -194,7 +197,7 @@ class TestMaskToolsWidget(PlotWidgetTestCase, ParametricTestCase):
self.assertIsNot(toolButton, None)
self.mouseClick(toolButton, qt.Qt.LeftButton)
- self.maskWidget.pencilSpinBox.setValue(10)
+ self.maskWidget.pencilSpinBox.setValue(30)
self.qapp.processEvents()
# mask
diff --git a/silx/gui/plot/test/testPlotTools.py b/silx/gui/plot/test/testPlotTools.py
index a08a18a..3d5849f 100644
--- a/silx/gui/plot/test/testPlotTools.py
+++ b/silx/gui/plot/test/testPlotTools.py
@@ -26,13 +26,13 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "01/09/2017"
+__date__ = "17/01/2018"
import numpy
import unittest
-from silx.test.utils import ParametricTestCase, TestLogging
+from silx.utils.testutils import ParametricTestCase, TestLogging
from silx.gui.test.utils import (
qWaitForWindowExposedAndActivate, TestCaseQt, getQToolButtonFromAction)
from silx.gui import qt
diff --git a/silx/gui/plot/test/testPlotWidget.py b/silx/gui/plot/test/testPlotWidget.py
index ccee428..72617e5 100644
--- a/silx/gui/plot/test/testPlotWidget.py
+++ b/silx/gui/plot/test/testPlotWidget.py
@@ -26,17 +26,17 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "01/09/2017"
+__date__ = "26/01/2018"
import unittest
import logging
import numpy
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
from silx.gui.test.utils import SignalListener
from silx.gui.test.utils import TestCaseQt
-from silx.test import utils
+from silx.utils import testutils
from silx.utils import deprecation
from silx.gui import qt
@@ -77,9 +77,9 @@ class TestPlotWidget(PlotWidgetTestCase, ParametricTestCase):
self.assertEqual(self.plot.getYAxis().getLabel(), ylabel)
def _checkLimits(self,
- expectedXLim=None,
- expectedYLim=None,
- expectedRatio=None):
+ expectedXLim=None,
+ expectedYLim=None,
+ expectedRatio=None):
"""Assert that limits are as expected"""
xlim = self.plot.getXAxis().getLimits()
ylim = self.plot.getYAxis().getLimits()
@@ -132,13 +132,11 @@ class TestPlotWidget(PlotWidgetTestCase, ParametricTestCase):
# Resize with aspect ratio
self.plot.setKeepDataAspectRatio(True)
- listener.clear() # Clean-up received signal
self.qapp.processEvents()
- self.assertEqual(listener.callCount(), 0) # No event when redrawing
+ listener.clear() # Clean-up received signal
self.plot.resize(200, 200)
self.qapp.processEvents()
-
self.assertNotEqual(listener.callCount(), 0)
@@ -723,7 +721,7 @@ class TestPlotAxes(TestCaseQt, ParametricTestCase):
if getter is not None:
self.assertEqual(getter(), expected)
- @utils.test_logging(deprecation.depreclog.name, warning=2)
+ @testutils.test_logging(deprecation.depreclog.name, warning=2)
def testOldPlotAxis_Logarithmic(self):
"""Test silx API prior to silx 0.6"""
x = self.plot.getXAxis()
@@ -762,7 +760,7 @@ class TestPlotAxes(TestCaseQt, ParametricTestCase):
self.assertEqual(self.plot.isYAxisLogarithmic(), False)
self.assertEqual(listener.arguments(callIndex=-1), ("y", False))
- @utils.test_logging(deprecation.depreclog.name, warning=2)
+ @testutils.test_logging(deprecation.depreclog.name, warning=2)
def testOldPlotAxis_AutoScale(self):
"""Test silx API prior to silx 0.6"""
x = self.plot.getXAxis()
@@ -801,7 +799,7 @@ class TestPlotAxes(TestCaseQt, ParametricTestCase):
self.assertEqual(self.plot.isYAxisAutoScale(), True)
self.assertEqual(listener.arguments(callIndex=-1), ("y", True))
- @utils.test_logging(deprecation.depreclog.name, warning=1)
+ @testutils.test_logging(deprecation.depreclog.name, warning=1)
def testOldPlotAxis_Inverted(self):
"""Test silx API prior to silx 0.6"""
x = self.plot.getXAxis()
diff --git a/silx/gui/plot/test/testPlotWidgetNoBackend.py b/silx/gui/plot/test/testPlotWidgetNoBackend.py
index 3094a20..0d0ddc4 100644
--- a/silx/gui/plot/test/testPlotWidgetNoBackend.py
+++ b/silx/gui/plot/test/testPlotWidgetNoBackend.py
@@ -26,12 +26,12 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "27/06/2017"
+__date__ = "17/01/2018"
import unittest
from functools import reduce
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
import numpy
diff --git a/silx/gui/plot/test/testProfile.py b/silx/gui/plot/test/testProfile.py
index 43d3329..28d9669 100644
--- a/silx/gui/plot/test/testProfile.py
+++ b/silx/gui/plot/test/testProfile.py
@@ -26,12 +26,12 @@
__authors__ = ["T. Vincent", "P. Knobel"]
__license__ = "MIT"
-__date__ = "23/02/2017"
+__date__ = "17/01/2018"
import numpy
import unittest
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
from silx.gui.test.utils import (
TestCaseQt, getQToolButtonFromAction)
from silx.gui import qt
diff --git a/silx/gui/plot/test/testSaveAction.py b/silx/gui/plot/test/testSaveAction.py
new file mode 100644
index 0000000..4dfe373
--- /dev/null
+++ b/silx/gui/plot/test/testSaveAction.py
@@ -0,0 +1,97 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Test the plot's save action (consistency of output)"""
+
+__authors__ = ["P. Knobel"]
+__license__ = "MIT"
+__date__ = "28/11/2017"
+
+
+import unittest
+import tempfile
+import os
+
+from silx.gui.plot import PlotWidget
+from silx.gui.plot.actions.io import SaveAction
+
+
+class TestSaveAction(unittest.TestCase):
+
+ def setUp(self):
+ self.plot = PlotWidget(backend='none')
+ self.saveAction = SaveAction(plot=self.plot)
+
+ self.tempdir = tempfile.mkdtemp()
+ self.out_fname = os.path.join(self.tempdir, "out.dat")
+
+ def tearDown(self):
+ os.unlink(self.out_fname)
+ os.rmdir(self.tempdir)
+
+ def testSaveMultipleCurvesAsSpec(self):
+ """Test that labels are properly used."""
+ self.plot.setGraphXLabel("graph x label")
+ self.plot.setGraphYLabel("graph y label")
+
+ self.plot.addCurve([0, 1], [1, 2], "curve with labels",
+ xlabel="curve0 X", ylabel="curve0 Y")
+ self.plot.addCurve([-1, 3], [-6, 2], "curve with X label",
+ xlabel="curve1 X")
+ self.plot.addCurve([-2, 0], [8, 12], "curve with Y label",
+ ylabel="curve2 Y")
+ self.plot.addCurve([3, 1], [7, 6], "curve with no labels")
+
+ self.saveAction._saveCurves(self.out_fname,
+ SaveAction.ALL_CURVES_FILTERS[0]) # "All curves as SpecFile (*.dat)"
+
+ with open(self.out_fname, "rb") as f:
+ file_content = f.read()
+ if hasattr(file_content, "decode"):
+ file_content = file_content.decode()
+
+ # case with all curve labels specified
+ self.assertIn("#S 1 curve0 Y", file_content)
+ self.assertIn("#L curve0 X curve0 Y", file_content)
+
+ # graph X&Y labels are used when no curve label is specified
+ self.assertIn("#S 2 graph y label", file_content)
+ self.assertIn("#L curve1 X graph y label", file_content)
+
+ self.assertIn("#S 3 curve2 Y", file_content)
+ self.assertIn("#L graph x label curve2 Y", file_content)
+
+ self.assertIn("#S 4 graph y label", file_content)
+ self.assertIn("#L graph x label graph y label", file_content)
+
+
+def suite():
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(
+ unittest.defaultTestLoader.loadTestsFromTestCase(TestSaveAction))
+ return test_suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
diff --git a/silx/gui/plot/test/testScatterMaskToolsWidget.py b/silx/gui/plot/test/testScatterMaskToolsWidget.py
index 178274a..0342c8f 100644
--- a/silx/gui/plot/test/testScatterMaskToolsWidget.py
+++ b/silx/gui/plot/test/testScatterMaskToolsWidget.py
@@ -26,7 +26,7 @@
__authors__ = ["T. Vincent", "P. Knobel"]
__license__ = "MIT"
-__date__ = "01/09/2017"
+__date__ = "17/01/2018"
import logging
@@ -36,7 +36,8 @@ import unittest
import numpy
from silx.gui import qt
-from silx.test.utils import temp_dir, ParametricTestCase
+from silx.test.utils import temp_dir
+from silx.utils.testutils import ParametricTestCase
from silx.gui.test.utils import getQToolButtonFromAction
from silx.gui.plot import PlotWindow, ScatterMaskToolsWidget
from .utils import PlotWidgetTestCase
@@ -86,8 +87,10 @@ class TestScatterMaskToolsWidget(PlotWidgetTestCase, ParametricTestCase):
pos0 = xCenter, yCenter
pos1 = xCenter + offset, yCenter + offset
+ self.mouseMove(plot, pos=(0, 0))
self.mouseMove(plot, pos=pos0)
self.mousePress(plot, qt.Qt.LeftButton, pos=pos0)
+ self.mouseMove(plot, pos=(0, 0))
self.mouseMove(plot, pos=pos1)
self.mouseRelease(plot, qt.Qt.LeftButton, pos=pos1)
@@ -197,7 +200,7 @@ class TestScatterMaskToolsWidget(PlotWidgetTestCase, ParametricTestCase):
self.assertIsNot(toolButton, None)
self.mouseClick(toolButton, qt.Qt.LeftButton)
- self.maskWidget.pencilSpinBox.setValue(10)
+ self.maskWidget.pencilSpinBox.setValue(30)
self.qapp.processEvents()
# mask
diff --git a/silx/gui/plot/test/testUtilsAxis.py b/silx/gui/plot/test/testUtilsAxis.py
index 6702b00..3f19dcd 100644
--- a/silx/gui/plot/test/testUtilsAxis.py
+++ b/silx/gui/plot/test/testUtilsAxis.py
@@ -26,18 +26,20 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "04/08/2017"
+__date__ = "14/02/2018"
import unittest
from silx.gui.plot import PlotWidget
+from silx.gui.test.utils import TestCaseQt
from silx.gui.plot.utils.axis import SyncAxes
-class TestAxisSync(unittest.TestCase):
+class TestAxisSync(TestCaseQt):
"""Tests AxisSync class"""
def setUp(self):
+ TestCaseQt.setUp(self)
self.plot1 = PlotWidget()
self.plot2 = PlotWidget()
self.plot3 = PlotWidget()
@@ -46,6 +48,7 @@ class TestAxisSync(unittest.TestCase):
self.plot1 = None
self.plot2 = None
self.plot3 = None
+ TestCaseQt.tearDown(self)
def testMoveFirstAxis(self):
"""Test synchronization after construction"""
@@ -85,6 +88,22 @@ class TestAxisSync(unittest.TestCase):
self.assertNotEqual(self.plot2.getXAxis().getLimits(), (10, 500))
self.assertNotEqual(self.plot3.getXAxis().getLimits(), (10, 500))
+ def testAxisDestruction(self):
+ """Test synchronization when an axis disappear"""
+ _sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()])
+
+ # Destroy the plot is possible
+ import weakref
+ plot = weakref.ref(self.plot2)
+ self.plot2 = None
+ result = self.qWaitForDestroy(plot)
+ if not result:
+ # We can't test
+ self.skipTest("Object not destroyed")
+
+ self.plot1.getXAxis().setLimits(10, 500)
+ self.assertEqual(self.plot3.getXAxis().getLimits(), (10, 500))
+
def testStop(self):
"""Test synchronization after calling stop"""
sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()])
diff --git a/silx/gui/plot/test/utils.py b/silx/gui/plot/test/utils.py
index ef547c6..ec9bc7c 100644
--- a/silx/gui/plot/test/utils.py
+++ b/silx/gui/plot/test/utils.py
@@ -26,17 +26,15 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "01/09/2017"
+__date__ = "26/01/2018"
import logging
-import contextlib
from silx.gui.test.utils import TestCaseQt
from silx.gui import qt
from silx.gui.plot import PlotWidget
-from silx.gui.plot.backends.BackendMatplotlib import BackendMatplotlibQt
logger = logging.getLogger(__name__)
@@ -48,9 +46,10 @@ class PlotWidgetTestCase(TestCaseQt):
plot attribute is the PlotWidget created for the test.
"""
+ __screenshot_already_taken = False
+
def __init__(self, methodName='runTest'):
TestCaseQt.__init__(self, methodName=methodName)
- self.__mousePos = None
def _createPlot(self):
return PlotWidget()
@@ -79,116 +78,16 @@ class PlotWidgetTestCase(TestCaseQt):
logger.error("Plot is still alive")
def tearDown(self):
+ if not self._currentTestSucceeded():
+ # MPL is the only widget which uses the real system mouse.
+ # In case of a the windows is outside of the screen, minimzed,
+ # overlapped by a system popup, the MPL widget will not receive the
+ # mouse event.
+ # Taking a screenshot help debuging this cases in the continuous
+ # integration environement.
+ if not PlotWidgetTestCase.__screenshot_already_taken:
+ PlotWidgetTestCase.__screenshot_already_taken = True
+ self.logScreenShot()
self.qapp.processEvents()
self._waitForPlotClosed()
super(PlotWidgetTestCase, self).tearDown()
-
- def _logMplEvents(self, event):
- self.__mplEvents.append(event)
-
- @contextlib.contextmanager
- def _waitForMplEvent(self, plot, mplEventType):
- """Check if an event was received by the MPL backend.
-
- :param PlotWidget plot: A plot widget or a MPL plot backend
- :param str mplEventType: MPL event type
- :raises RuntimeError: When the event did not happen
- """
- self.__mplEvents = []
- if isinstance(plot, BackendMatplotlibQt):
- backend = plot
- else:
- backend = plot._backend
-
- callbackId = backend.mpl_connect(mplEventType, self._logMplEvents)
- received = False
- yield
- for _ in range(100):
- if len(self.__mplEvents) > 0:
- received = True
- break
- self.qWait(10)
- backend.mpl_disconnect(callbackId)
- del self.__mplEvents
- if not received:
- self.logScreenShot()
- raise RuntimeError("MPL event %s expected but nothing received" % mplEventType)
-
- def _haveMplEvent(self, widget, pos):
- """Check if the widget at this position is a matplotlib widget."""
- if isinstance(pos, qt.QPoint):
- pass
- else:
- pos = qt.QPoint(pos[0], pos[1])
- pos = widget.mapTo(widget.window(), pos)
- target = widget.window().childAt(pos)
-
- # Check if the target is a MPL container
- backend = target
- if hasattr(target, "_backend"):
- backend = target._backend
- haveEvent = isinstance(backend, BackendMatplotlibQt)
- return haveEvent
-
- def _patchPos(self, widget, pos):
- """Return a real position relative to the widget.
-
- If pos is None, the returned value is the center of the widget,
- as the default behaviour of functions like QTest.mouseMove.
- Else the position is returned as it is.
- """
- if pos is None:
- pos = widget.size() / 2
- pos = pos.width(), pos.height()
- return pos
-
- def _checkMouseMove(self, widget, pos):
- """Returns true if the position differe from the current position of
- the cursor"""
- pos = qt.QPoint(pos[0], pos[1])
- pos = widget.mapTo(widget.window(), pos)
- willMove = pos != self.__mousePos
- self.__mousePos = pos
- return willMove
-
- def mouseMove(self, widget, pos=None, delay=-1):
- """Override TestCaseQt to wait while MPL did not reveive the expected
- event"""
- pos = self._patchPos(widget, pos)
- willMove = self._checkMouseMove(widget, pos)
- hadMplEvents = self._haveMplEvent(widget, self.__mousePos)
- willHaveMplEvents = self._haveMplEvent(widget, pos)
- if (not hadMplEvents and not willHaveMplEvents) or not willMove:
- return TestCaseQt.mouseMove(self, widget, pos=pos, delay=delay)
- with self._waitForMplEvent(widget, "motion_notify_event"):
- TestCaseQt.mouseMove(self, widget, pos=pos, delay=delay)
-
- def mouseClick(self, widget, button, modifier=None, pos=None, delay=-1):
- """Override TestCaseQt to wait while MPL did not reveive the expected
- event"""
- pos = self._patchPos(widget, pos)
- self._checkMouseMove(widget, pos)
- if not self._haveMplEvent(widget, pos):
- return TestCaseQt.mouseClick(self, widget, button, modifier=modifier, pos=pos, delay=delay)
- with self._waitForMplEvent(widget, "button_release_event"):
- TestCaseQt.mouseClick(self, widget, button, modifier=modifier, pos=pos, delay=delay)
-
- def mousePress(self, widget, button, modifier=None, pos=None, delay=-1):
- """Override TestCaseQt to wait while MPL did not reveive the expected
- event"""
- pos = self._patchPos(widget, pos)
- self._checkMouseMove(widget, pos)
- if not self._haveMplEvent(widget, pos):
- return TestCaseQt.mousePress(self, widget, button, modifier=modifier, pos=pos, delay=delay)
- with self._waitForMplEvent(widget, "button_press_event"):
- TestCaseQt.mousePress(self, widget, button, modifier=modifier, pos=pos, delay=delay)
-
- def mouseRelease(self, widget, button, modifier=None, pos=None, delay=-1):
- """Override TestCaseQt to wait while MPL did not reveive the expected
- event"""
- pos = self._patchPos(widget, pos)
- self._checkMouseMove(widget, pos)
- if not self._haveMplEvent(widget, pos):
- return TestCaseQt.mouseRelease(self, widget, button, modifier=modifier, pos=pos, delay=delay)
- with self._waitForMplEvent(widget, "button_release_event"):
- TestCaseQt.mouseRelease(self, widget, button, modifier=modifier, pos=pos, delay=delay)
diff --git a/silx/gui/plot/utils/axis.py b/silx/gui/plot/utils/axis.py
index f7ec711..80e1dc4 100644
--- a/silx/gui/plot/utils/axis.py
+++ b/silx/gui/plot/utils/axis.py
@@ -27,12 +27,13 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "04/08/2017"
+__date__ = "23/02/2018"
import functools
import logging
from contextlib import contextmanager
-from silx.utils import weakref
+import weakref
+import silx.utils.weakref as silxWeakref
_logger = logging.getLogger(__name__)
@@ -63,14 +64,20 @@ class SyncAxes(object):
:param bool syncDirection: Synchronize axes direction
"""
object.__init__(self)
- self.__axes = []
self.__locked = False
+ self.__axes = []
self.__syncLimits = syncLimits
self.__syncScale = syncScale
self.__syncDirection = syncDirection
- self.__callbacks = []
+ self.__callbacks = None
+
+ qtCallback = silxWeakref.WeakMethodProxy(self.__deleteAxisQt)
+ for axis in axes:
+ ref = weakref.ref(axis)
+ self.__axes.append(ref)
+ callback = functools.partial(qtCallback, ref)
+ axis.destroyed.connect(callback)
- self.__axes.extend(axes)
self.start()
def start(self):
@@ -80,54 +87,71 @@ class SyncAxes(object):
After that, any changes to any axes will be used to synchronize other
axes.
"""
- if len(self.__callbacks) != 0:
+ if self.__callbacks is not None:
raise RuntimeError("Axes already synchronized")
+ self.__callbacks = {}
# register callback for further sync
- for axis in self.__axes:
+ for refAxis in self.__axes:
+ axis = refAxis()
+ callbacks = []
if self.__syncLimits:
# the weakref is needed to be able ignore self references
- callback = weakref.WeakMethodProxy(self.__axisLimitsChanged)
- callback = functools.partial(callback, axis)
+ callback = silxWeakref.WeakMethodProxy(self.__axisLimitsChanged)
+ callback = functools.partial(callback, refAxis)
sig = axis.sigLimitsChanged
sig.connect(callback)
- self.__callbacks.append((sig, callback))
+ callbacks.append(("sigLimitsChanged", callback))
if self.__syncScale:
# the weakref is needed to be able ignore self references
- callback = weakref.WeakMethodProxy(self.__axisScaleChanged)
- callback = functools.partial(callback, axis)
+ callback = silxWeakref.WeakMethodProxy(self.__axisScaleChanged)
+ callback = functools.partial(callback, refAxis)
sig = axis.sigScaleChanged
sig.connect(callback)
- self.__callbacks.append((sig, callback))
+ callbacks.append(("sigScaleChanged", callback))
if self.__syncDirection:
# the weakref is needed to be able ignore self references
- callback = weakref.WeakMethodProxy(self.__axisInvertedChanged)
- callback = functools.partial(callback, axis)
+ callback = silxWeakref.WeakMethodProxy(self.__axisInvertedChanged)
+ callback = functools.partial(callback, refAxis)
sig = axis.sigInvertedChanged
sig.connect(callback)
- self.__callbacks.append((sig, callback))
+ callbacks.append(("sigInvertedChanged", callback))
+
+ self.__callbacks[refAxis] = callbacks
# sync the current state
- mainAxis = self.__axes[0]
+ refMainAxis = self.__axes[0]
+ mainAxis = refMainAxis()
if self.__syncLimits:
- self.__axisLimitsChanged(mainAxis, *mainAxis.getLimits())
+ self.__axisLimitsChanged(refMainAxis, *mainAxis.getLimits())
if self.__syncScale:
- self.__axisScaleChanged(mainAxis, mainAxis.getScale())
+ self.__axisScaleChanged(refMainAxis, mainAxis.getScale())
if self.__syncDirection:
- self.__axisInvertedChanged(mainAxis, mainAxis.isInverted())
+ self.__axisInvertedChanged(refMainAxis, mainAxis.isInverted())
+
+ def __deleteAxis(self, ref):
+ _logger.debug("Delete axes ref %s", ref)
+ self.__axes.remove(ref)
+ del self.__callbacks[ref]
+
+ def __deleteAxisQt(self, ref, qobject):
+ self.__deleteAxis(ref)
def stop(self):
"""Stop the synchronization of the axes"""
- if len(self.__callbacks) == 0:
+ if self.__callbacks is None:
raise RuntimeError("Axes not synchronized")
- for sig, callback in self.__callbacks:
- sig.disconnect(callback)
- self.__callbacks = []
+ for ref, callbacks in self.__callbacks.items():
+ axes = ref()
+ for sigName, callback in callbacks:
+ sig = getattr(axes, sigName)
+ sig.disconnect(callback)
+ self.__callbacks = None
def __del__(self):
"""Destructor"""
# clean up references
- if len(self.__callbacks) != 0:
+ if self.__callbacks is not None:
self.stop()
@contextmanager
@@ -138,6 +162,7 @@ class SyncAxes(object):
def __otherAxes(self, changedAxis):
for axis in self.__axes:
+ axis = axis()
if axis is changedAxis:
continue
yield axis
@@ -145,6 +170,7 @@ class SyncAxes(object):
def __axisLimitsChanged(self, changedAxis, vmin, vmax):
if self.__locked:
return
+ changedAxis = changedAxis()
with self.__inhibitSignals():
for axis in self.__otherAxes(changedAxis):
axis.setLimits(vmin, vmax)
@@ -152,6 +178,7 @@ class SyncAxes(object):
def __axisScaleChanged(self, changedAxis, scale):
if self.__locked:
return
+ changedAxis = changedAxis()
with self.__inhibitSignals():
for axis in self.__otherAxes(changedAxis):
axis.setScale(scale)
@@ -159,6 +186,7 @@ class SyncAxes(object):
def __axisInvertedChanged(self, changedAxis, isInverted):
if self.__locked:
return
+ changedAxis = changedAxis()
with self.__inhibitSignals():
for axis in self.__otherAxes(changedAxis):
axis.setInverted(isInverted)
diff --git a/silx/gui/plot3d/ParamTreeView.py b/silx/gui/plot3d/ParamTreeView.py
new file mode 100644
index 0000000..a352627
--- /dev/null
+++ b/silx/gui/plot3d/ParamTreeView.py
@@ -0,0 +1,541 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This module provides a :class:`QTreeView` dedicated to display plot3d models.
+
+This module contains:
+- :class:`ParamTreeView`: A QTreeView specific for plot3d parameters and scene.
+- :class:`ParameterTreeDelegate`: The delegate for :class:`ParamTreeView`.
+- A set of specific editors used by :class:`ParameterTreeDelegate`:
+ :class:`FloatEditor`, :class:`Vector3DEditor`,
+ :class:`Vector4DEditor`, :class:`IntSliderEditor`, :class:`BooleanEditor`
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "05/12/2017"
+
+
+import sys
+
+from silx.third_party import six
+
+from .. import qt
+from ..widgets.FloatEdit import FloatEdit as _FloatEdit
+from ._model import visitQAbstractItemModel
+
+
+class FloatEditor(_FloatEdit):
+ """Editor widget for float.
+
+ :param parent: The widget's parent
+ :param float value: The initial editor value
+ """
+
+ valueChanged = qt.Signal(float)
+ """Signal emitted when the float value has changed"""
+
+ def __init__(self, parent=None, value=None):
+ super(FloatEditor, self).__init__(parent, value)
+ self.setAlignment(qt.Qt.AlignLeft)
+ self.editingFinished.connect(self._emit)
+
+ def _emit(self):
+ self.valueChanged.emit(self.value)
+
+ value = qt.Property(float,
+ fget=_FloatEdit.value,
+ fset=_FloatEdit.setValue,
+ user=True,
+ notify=valueChanged)
+ """Qt user property of the float value this widget edits"""
+
+
+class Vector3DEditor(qt.QWidget):
+ """Editor widget for QVector3D.
+
+ :param parent: The widget's parent
+ :param flags: The widgets's flags
+ """
+
+ valueChanged = qt.Signal(qt.QVector3D)
+ """Signal emitted when the QVector3D value has changed"""
+
+ def __init__(self, parent=None, flags=qt.Qt.Widget):
+ super(Vector3DEditor, self).__init__(parent, flags)
+ layout = qt.QHBoxLayout(self)
+ # layout.setSpacing(0)
+ layout.setContentsMargins(0, 0, 0, 0)
+ self.setLayout(layout)
+ self._xEdit = _FloatEdit(parent=self, value=0.)
+ self._xEdit.setAlignment(qt.Qt.AlignLeft)
+ # self._xEdit.editingFinished.connect(self._emit)
+ self._yEdit = _FloatEdit(parent=self, value=0.)
+ self._yEdit.setAlignment(qt.Qt.AlignLeft)
+ # self._yEdit.editingFinished.connect(self._emit)
+ self._zEdit = _FloatEdit(parent=self, value=0.)
+ self._zEdit.setAlignment(qt.Qt.AlignLeft)
+ # self._zEdit.editingFinished.connect(self._emit)
+ layout.addWidget(qt.QLabel('x:'))
+ layout.addWidget(self._xEdit)
+ layout.addWidget(qt.QLabel('y:'))
+ layout.addWidget(self._yEdit)
+ layout.addWidget(qt.QLabel('z:'))
+ layout.addWidget(self._zEdit)
+ layout.addStretch(1)
+
+ def _emit(self):
+ vector = self.value
+ self.valueChanged.emit(vector)
+
+ def getValue(self):
+ """Returns the QVector3D value of this widget
+
+ :rtype: QVector3D
+ """
+ return qt.QVector3D(
+ self._xEdit.value(), self._yEdit.value(), self._zEdit.value())
+
+ def setValue(self, value):
+ """Set the QVector3D value
+
+ :param QVector3D value: The new value
+ """
+ self._xEdit.setValue(value.x())
+ self._yEdit.setValue(value.y())
+ self._zEdit.setValue(value.z())
+ self.valueChanged.emit(value)
+
+ value = qt.Property(qt.QVector3D,
+ fget=getValue,
+ fset=setValue,
+ user=True,
+ notify=valueChanged)
+ """Qt user property of the QVector3D value this widget edits"""
+
+
+class Vector4DEditor(qt.QWidget):
+ """Editor widget for QVector4D.
+
+ :param parent: The widget's parent
+ :param flags: The widgets's flags
+ """
+
+ valueChanged = qt.Signal(qt.QVector4D)
+ """Signal emitted when the QVector4D value has changed"""
+
+ def __init__(self, parent=None, flags=qt.Qt.Widget):
+ super(Vector4DEditor, self).__init__(parent, flags)
+ layout = qt.QHBoxLayout(self)
+ # layout.setSpacing(0)
+ layout.setContentsMargins(0, 0, 0, 0)
+ self.setLayout(layout)
+ self._xEdit = _FloatEdit(parent=self, value=0.)
+ self._xEdit.setAlignment(qt.Qt.AlignLeft)
+ # self._xEdit.editingFinished.connect(self._emit)
+ self._yEdit = _FloatEdit(parent=self, value=0.)
+ self._yEdit.setAlignment(qt.Qt.AlignLeft)
+ # self._yEdit.editingFinished.connect(self._emit)
+ self._zEdit = _FloatEdit(parent=self, value=0.)
+ self._zEdit.setAlignment(qt.Qt.AlignLeft)
+ # self._zEdit.editingFinished.connect(self._emit)
+ self._wEdit = _FloatEdit(parent=self, value=0.)
+ self._wEdit.setAlignment(qt.Qt.AlignLeft)
+ # self._wEdit.editingFinished.connect(self._emit)
+ layout.addWidget(qt.QLabel('x:'))
+ layout.addWidget(self._xEdit)
+ layout.addWidget(qt.QLabel('y:'))
+ layout.addWidget(self._yEdit)
+ layout.addWidget(qt.QLabel('z:'))
+ layout.addWidget(self._zEdit)
+ layout.addWidget(qt.QLabel('w:'))
+ layout.addWidget(self._wEdit)
+ layout.addStretch(1)
+
+ def _emit(self):
+ vector = self.value
+ self.valueChanged.emit(vector)
+
+ def getValue(self):
+ """Returns the QVector4D value of this widget
+
+ :rtype: QVector4D
+ """
+ return qt.QVector4D(self._xEdit.value(), self._yEdit.value(),
+ self._zEdit.value(), self._wEdit.value())
+
+ def setValue(self, value):
+ """Set the QVector4D value
+
+ :param QVector4D value: The new value
+ """
+ self._xEdit.setValue(value.x())
+ self._yEdit.setValue(value.y())
+ self._zEdit.setValue(value.z())
+ self._wEdit.setValue(value.w())
+ self.valueChanged.emit(value)
+
+ value = qt.Property(qt.QVector4D,
+ fget=getValue,
+ fset=setValue,
+ user=True,
+ notify=valueChanged)
+ """Qt user property of the QVector4D value this widget edits"""
+
+
+class IntSliderEditor(qt.QSlider):
+ """Slider editor widget for integer.
+
+ Note: Tracking is disabled.
+
+ :param parent: The widget's parent
+ """
+
+ def __init__(self, parent=None):
+ super(IntSliderEditor, self).__init__(parent)
+ self.setOrientation(qt.Qt.Horizontal)
+ self.setSingleStep(1)
+ self.setRange(0, 255)
+ self.setValue(0)
+
+
+class BooleanEditor(qt.QCheckBox):
+ """Checkbox editor for bool.
+
+ This is a QCheckBox with white background.
+
+ :param parent: The widget's parent
+ """
+
+ def __init__(self, parent=None):
+ super(BooleanEditor, self).__init__(parent)
+ self.setStyleSheet("background: white;")
+
+
+class ParameterTreeDelegate(qt.QStyledItemDelegate):
+ """TreeView delegate specific to plot3d scene and object parameter tree.
+
+ It provides additional editors.
+
+ :param parent: Delegate's parent
+ """
+
+ EDITORS = {
+ bool: BooleanEditor,
+ float: FloatEditor,
+ qt.QVector3D: Vector3DEditor,
+ qt.QVector4D: Vector4DEditor,
+ }
+ """Specific editors for different type of data"""
+
+ def __init__(self, parent=None):
+ super(ParameterTreeDelegate, self).__init__(parent)
+
+ def _fixVariant(self, data):
+ """Fix PyQt4 zero vectors being stored as QPyNullVariant.
+
+ :param data: Data retrieved from the model
+ :return: Corresponding object
+ """
+ if qt.BINDING == 'PyQt4' and isinstance(data, qt.QPyNullVariant):
+ typeName = data.typeName()
+ if typeName == 'QVector3D':
+ data = qt.QVector3D()
+ elif typeName == 'QVector4D':
+ data = qt.QVector4D()
+ return data
+
+ def paint(self, painter, option, index):
+ """See :meth:`QStyledItemDelegate.paint`"""
+ data = index.data(qt.Qt.DisplayRole)
+ data = self._fixVariant(data)
+
+ if isinstance(data, (qt.QVector3D, qt.QVector4D)):
+ if isinstance(data, qt.QVector3D):
+ text = '(x: %g; y: %g; z: %g)' % (data.x(), data.y(), data.z())
+ elif isinstance(data, qt.QVector4D):
+ text = '(%g; %g; %g; %g)' % (data.x(), data.y(), data.z(), data.w())
+ else:
+ text = ''
+
+ painter.save()
+ painter.setRenderHint(qt.QPainter.Antialiasing, True)
+
+ # Select palette color group
+ colorGroup = qt.QPalette.Inactive
+ if option.state & qt.QStyle.State_Active:
+ colorGroup = qt.QPalette.Active
+ if not option.state & qt.QStyle.State_Enabled:
+ colorGroup = qt.QPalette.Disabled
+
+ # Draw background if selected
+ if option.state & qt.QStyle.State_Selected:
+ brush = option.palette.brush(colorGroup,
+ qt.QPalette.Highlight)
+ painter.fillRect(option.rect, brush)
+
+ # Draw text
+ if option.state & qt.QStyle.State_Selected:
+ colorRole = qt.QPalette.HighlightedText
+ else:
+ colorRole = qt.QPalette.WindowText
+ color = option.palette.color(colorGroup, colorRole)
+ painter.setPen(qt.QPen(color))
+ painter.drawText(option.rect, qt.Qt.AlignLeft, text)
+
+ painter.restore()
+
+ # The following commented code does the same as QPainter based code
+ # but it does not work with PySide
+ # self.initStyleOption(option, index)
+ # option.text = text
+ # widget = option.widget
+ # style = qt.QApplication.style() if not widget else widget.style()
+ # style.drawControl(qt.QStyle.CE_ItemViewItem, option, painter, widget)
+
+ else:
+ super(ParameterTreeDelegate, self).paint(painter, option, index)
+
+ def _commit(self, *args):
+ """Commit data to the model from editors"""
+ sender = self.sender()
+ self.commitData.emit(sender)
+
+ def editorEvent(self, event, model, option, index):
+ """See :meth:`QStyledItemDelegate.editorEvent`"""
+ if (event.type() == qt.QEvent.MouseButtonPress and
+ isinstance(index.data(qt.Qt.EditRole), qt.QColor)):
+ initialColor = index.data(qt.Qt.EditRole)
+
+ def callback(color):
+ theModel = index.model()
+ theModel.setData(index, color, qt.Qt.EditRole)
+
+ dialog = qt.QColorDialog(self.parent())
+ # dialog.setOption(qt.QColorDialog.ShowAlphaChannel, True)
+ if sys.platform == 'darwin':
+ # Use of native color dialog on macos might cause problems
+ dialog.setOption(qt.QColorDialog.DontUseNativeDialog, True)
+ dialog.setCurrentColor(initialColor)
+ dialog.currentColorChanged.connect(callback)
+ if dialog.exec_() == qt.QDialog.Rejected:
+ # Reset color
+ dialog.setCurrentColor(initialColor)
+
+ return True
+ else:
+ return super(ParameterTreeDelegate, self).editorEvent(
+ event, model, option, index)
+
+ def createEditor(self, parent, option, index):
+ """See :meth:`QStyledItemDelegate.createEditor`"""
+ data = index.data(qt.Qt.EditRole)
+ data = self._fixVariant(data)
+ editorHint = index.data(qt.Qt.UserRole)
+
+ if callable(editorHint):
+ editor = editorHint()
+ assert isinstance(editor, qt.QWidget)
+ editor.setParent(parent)
+
+ elif isinstance(data, (int, float)) and editorHint is not None:
+ # Use a slider
+ editor = IntSliderEditor(parent)
+ range_ = editorHint
+ editor.setRange(*range_)
+ editor.sliderReleased.connect(self._commit)
+
+ elif isinstance(data, six.string_types) and editorHint is not None:
+ # Use a combo box
+ editor = qt.QComboBox(parent)
+ if data not in editorHint:
+ editor.addItem(data)
+ editor.addItems(editorHint)
+
+ index = editor.findText(data)
+ editor.setCurrentIndex(index)
+
+ editor.currentIndexChanged.connect(self._commit)
+
+ else:
+ # Handle overridden editors from Python
+ # Mimic Qt C++ implementation
+ for type_, editorClass in self.EDITORS.items():
+ if isinstance(data, type_):
+ editor = editorClass(parent)
+ metaObject = editor.metaObject()
+ userProperty = metaObject.userProperty()
+ if userProperty.isValid() and userProperty.hasNotifySignal():
+ notifySignal = userProperty.notifySignal()
+ if hasattr(notifySignal, 'signature'): # Qt4
+ signature = notifySignal.signature()
+ else:
+ signature = bytes(notifySignal.methodSignature())
+
+ if hasattr(signature, 'decode'): # For PySide with python3
+ signature = signature.decode('ascii')
+ signalName = signature.split('(')[0]
+
+ signal = getattr(editor, signalName)
+ signal.connect(self._commit)
+ break
+
+ else: # Default handling for default types
+ return super(ParameterTreeDelegate, self).createEditor(
+ parent, option, index)
+
+ editor.setAutoFillBackground(True)
+ return editor
+
+ def setModelData(self, editor, model, index):
+ """See :meth:`QStyledItemDelegate.setModelData`"""
+ if isinstance(editor, tuple(self.EDITORS.values())):
+ # Special handling of Python classes
+ # Translation of QStyledItemDelegate::setModelData to Python
+ # To make it work with Python QVariant wrapping/unwrapping
+ name = editor.metaObject().userProperty().name()
+ if not name:
+ pass # TODO handle the case of missing user property
+ if name:
+ if hasattr(editor, name):
+ value = getattr(editor, name)
+ else:
+ value = editor.property(name)
+ model.setData(index, value, qt.Qt.EditRole)
+
+ else:
+ super(ParameterTreeDelegate, self).setModelData(editor, model, index)
+
+
+class ParamTreeView(qt.QTreeView):
+ """QTreeView specific to handle plot3d scene and object parameters.
+
+ It provides additional editors and specific creation of persistent editors.
+
+ :param parent: The widget's parent.
+ """
+
+ def __init__(self, parent=None):
+ super(ParamTreeView, self).__init__(parent)
+
+ header = self.header()
+ header.setMinimumSectionSize(128) # For colormap pixmaps
+ if hasattr(header, 'setSectionResizeMode'): # Qt5
+ header.setSectionResizeMode(qt.QHeaderView.ResizeToContents)
+ else: # Qt4
+ header.setResizeMode(qt.QHeaderView.ResizeToContents)
+
+ delegate = ParameterTreeDelegate()
+ self.setItemDelegate(delegate)
+
+ self.setSelectionBehavior(qt.QAbstractItemView.SelectRows)
+ self.setSelectionMode(qt.QAbstractItemView.SingleSelection)
+
+ self.expanded.connect(self._expanded)
+
+ self.setEditTriggers(qt.QAbstractItemView.CurrentChanged |
+ qt.QAbstractItemView.DoubleClicked)
+
+ self.__persistentEditors = set()
+
+ def _openEditorForIndex(self, index):
+ """Check if it has to open a persistent editor for a specific cell.
+
+ :param QModelIndex index: The cell index
+ """
+ if index.flags() & qt.Qt.ItemIsEditable:
+ data = index.data(qt.Qt.EditRole)
+ editorHint = index.data(qt.Qt.UserRole)
+ if (isinstance(data, bool) or
+ callable(editorHint) or
+ (isinstance(data, (float, int)) and editorHint)):
+ self.openPersistentEditor(index)
+ self.__persistentEditors.add(index)
+
+ def _openEditors(self, parent=qt.QModelIndex()):
+ """Open persistent editors in a subtree starting at parent.
+
+ :param QModelIndex parent: The root of the subtree to process.
+ """
+ model = self.model()
+ if model is not None:
+ for index in visitQAbstractItemModel(model, parent):
+ self._openEditorForIndex(index)
+
+ def setModel(self, model):
+ """Set the model this TreeView is displaying
+
+ :param QAbstractItemModel model:
+ """
+ super(ParamTreeView, self).setModel(model)
+ self._openEditors()
+
+ def rowsInserted(self, parent, start, end):
+ """See :meth:`QTreeView.rowsInserted`"""
+ super(ParamTreeView, self).rowsInserted(parent, start, end)
+ model = self.model()
+ if model is not None:
+ for row in range(start, end+1):
+ self._openEditorForIndex(model.index(row, 1, parent))
+ self._openEditors(model.index(row, 0, parent))
+
+ def _expanded(self, index):
+ """Handle QTreeView expanded signal"""
+ name = index.data(qt.Qt.DisplayRole)
+ if name == 'Transform':
+ rotateIndex = self.model().index(1, 0, index)
+ self.setExpanded(rotateIndex, True)
+
+ def dataChanged(self, topLeft, bottomRight, roles=()):
+ """Handle model dataChanged signal eventually closing editors"""
+ if roles: # Qt 5
+ super(ParamTreeView, self).dataChanged(topLeft, bottomRight, roles)
+ else: # Qt4 compatibility
+ super(ParamTreeView, self).dataChanged(topLeft, bottomRight)
+ if not roles or qt.Qt.UserRole in roles: # Check editorHint update
+ for row in range(topLeft.row(), bottomRight.row() + 1):
+ for column in range(topLeft.column(), bottomRight.column() + 1):
+ index = topLeft.sibling(row, column)
+ if index.isValid():
+ if self._isPersistentEditorOpen(index):
+ self.closePersistentEditor(index)
+ self._openEditorForIndex(index)
+
+ def _isPersistentEditorOpen(self, index):
+ """Returns True if a persistent editor is opened for index
+
+ :param QModelIndex index:
+ :rtype: bool
+ """
+ return index in self.__persistentEditors
+
+ def selectionCommand(self, index, event=None):
+ """Filter out selection of not selectable items"""
+ if index.flags() & qt.Qt.ItemIsSelectable:
+ return super(ParamTreeView, self).selectionCommand(index, event)
+ else:
+ return qt.QItemSelectionModel.NoUpdate
diff --git a/silx/gui/plot3d/Plot3DWidget.py b/silx/gui/plot3d/Plot3DWidget.py
index aae3955..15e2356 100644
--- a/silx/gui/plot3d/Plot3DWidget.py
+++ b/silx/gui/plot3d/Plot3DWidget.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -54,12 +54,26 @@ class _OverviewViewport(scene.Viewport):
:param Camera camera: The camera to track.
"""
+ _SIZE = 100
+ """Size in pixels of the overview square"""
+
def __init__(self, camera=None):
super(_OverviewViewport, self).__init__()
- self.size = 100, 100
+ self.size = self._SIZE, self._SIZE
+ self.background = None # Disable clear
self.scene.transforms = [transform.Scale(2.5, 2.5, 2.5)]
+ # Add a point to draw the background (in a group with depth mask)
+ backgroundPoint = primitives.ColorPoints(
+ x=0., y=0., z=0.,
+ color=(1., 1., 1., 0.5),
+ size=self._SIZE)
+ backgroundPoint.marker = 'o'
+ noDepthGroup = primitives.GroupNoDepth(mask=True, notest=True)
+ noDepthGroup.children.append(backgroundPoint)
+ self.scene.children.append(noDepthGroup)
+
axes = primitives.Axes()
self.scene.children.append(axes)
@@ -86,6 +100,12 @@ class Plot3DWidget(glu.OpenGLWidget):
"""Signal emitted when the interactive mode has changed
"""
+ sigStyleChanged = qt.Signal(str)
+ """Signal emitted when the style of the scene has changed
+
+ It provides the updated property.
+ """
+
def __init__(self, parent=None, f=qt.Qt.WindowFlags()):
self._firstRender = True
@@ -108,7 +128,6 @@ class Plot3DWidget(glu.OpenGLWidget):
# Main viewport
self.viewport = scene.Viewport()
- self.viewport.background = 0.2, 0.2, 0.2, 1.
self._sceneScale = transform.Scale(1., 1., 1.)
self.viewport.scene.transforms = [self._sceneScale,
@@ -143,18 +162,27 @@ class Plot3DWidget(glu.OpenGLWidget):
self.viewport,
orbitAroundCenter=False,
mode='position',
- scaleTransform=self._sceneScale)
+ scaleTransform=self._sceneScale,
+ selectCB=None)
elif mode == 'pan':
self.eventHandler = interaction.PanCameraControl(
self.viewport,
+ orbitAroundCenter=False,
mode='position',
scaleTransform=self._sceneScale,
selectCB=None)
+ elif isinstance(mode, interaction.StateMachine):
+ self.eventHandler = mode
+
else:
raise ValueError('Unsupported interactive mode %s', str(mode))
+ if (self.eventHandler is not None and
+ qt.QApplication.keyboardModifiers() & qt.Qt.ControlModifier):
+ self.eventHandler.handleEvent('keyPress', qt.Qt.Key_Control)
+
self.sigInteractiveModeChanged.emit()
def getInteractiveMode(self):
@@ -208,8 +236,9 @@ class Plot3DWidget(glu.OpenGLWidget):
QColor, str or array-like of 3 or 4 float in [0., 1.] or uint8
"""
color = rgba(color)
- self.viewport.background = color
- self.overview.background = color[0]*0.5, color[1]*0.5, color[2]*0.5, 1.
+ if color != self.viewport.background:
+ self.viewport.background = color
+ self.sigStyleChanged.emit('backgroundColor')
def getBackgroundColor(self):
"""Returns the RGBA background color (QColor)."""
@@ -233,6 +262,7 @@ class Plot3DWidget(glu.OpenGLWidget):
self._window.viewports = [self.viewport, self.overview]
else:
self._window.viewports = [self.viewport]
+ self.sigStyleChanged.emit('orientationIndicatorVisible')
def centerScene(self):
"""Position the center of the scene at the center of rotation."""
@@ -315,7 +345,7 @@ class Plot3DWidget(glu.OpenGLWidget):
self.eventHandler.handleEvent('wheel', xpixel, ypixel, angle)
def keyPressEvent(self, event):
- keycode = event.key()
+ keyCode = event.key()
# No need to accept QKeyEvent
converter = {
@@ -324,7 +354,7 @@ class Plot3DWidget(glu.OpenGLWidget):
qt.Qt.Key_Up: 'up',
qt.Qt.Key_Down: 'down'
}
- direction = converter.get(keycode, None)
+ direction = converter.get(keyCode, None)
if direction is not None:
if event.modifiers() == qt.Qt.ControlModifier:
self.viewport.camera.rotate(direction)
@@ -334,9 +364,23 @@ class Plot3DWidget(glu.OpenGLWidget):
self.viewport.orbitCamera(direction)
else:
+ if (keyCode == qt.Qt.Key_Control and
+ self.eventHandler is not None and
+ self.isValid()):
+ self.eventHandler.handleEvent('keyPress', keyCode)
+
# Key not handled, call base class implementation
super(Plot3DWidget, self).keyPressEvent(event)
+ def keyReleaseEvent(self, event):
+ """Catch Ctrl key release"""
+ keyCode = event.key()
+ if (keyCode == qt.Qt.Key_Control and
+ self.eventHandler is not None and
+ self.isValid()):
+ self.eventHandler.handleEvent('keyRelease', keyCode)
+ super(Plot3DWidget, self).keyReleaseEvent(event)
+
# Mouse events #
_MOUSE_BTNS = {1: 'left', 2: 'right', 4: 'middle'}
diff --git a/silx/gui/plot3d/Plot3DWindow.py b/silx/gui/plot3d/Plot3DWindow.py
index d8c393e..331eca2 100644
--- a/silx/gui/plot3d/Plot3DWindow.py
+++ b/silx/gui/plot3d/Plot3DWindow.py
@@ -35,9 +35,7 @@ __date__ = "26/01/2017"
from silx.gui import qt
from .Plot3DWidget import Plot3DWidget
-from .actions.viewpoint import RotateViewport
-from .tools import OutputToolBar, InteractiveModeToolBar
-from .tools import ViewpointToolButton
+from .tools import OutputToolBar, InteractiveModeToolBar, ViewpointToolBar
class Plot3DWindow(qt.QMainWindow):
@@ -52,20 +50,11 @@ class Plot3DWindow(qt.QMainWindow):
self._plot3D = Plot3DWidget()
self.setCentralWidget(self._plot3D)
- toolbar = InteractiveModeToolBar(parent=self)
- toolbar.setPlot3DWidget(self._plot3D)
- self.addToolBar(toolbar)
- self.addActions(toolbar.actions())
-
- toolbar = qt.QToolBar(self)
- toolbar.addWidget(ViewpointToolButton(plot3D=self._plot3D))
- toolbar.addAction(RotateViewport(parent=toolbar, plot3d=self._plot3D))
- self.addToolBar(toolbar)
-
- toolbar = OutputToolBar(parent=self)
- toolbar.setPlot3DWidget(self._plot3D)
- self.addToolBar(toolbar)
- self.addActions(toolbar.actions())
+ for klass in (InteractiveModeToolBar, ViewpointToolBar, OutputToolBar):
+ toolbar = klass(parent=self)
+ toolbar.setPlot3DWidget(self._plot3D)
+ self.addToolBar(toolbar)
+ self.addActions(toolbar.actions())
def getPlot3DWidget(self):
"""Get the :class:`Plot3DWidget` of this window"""
diff --git a/silx/gui/plot3d/SFViewParamTree.py b/silx/gui/plot3d/SFViewParamTree.py
index e67c17e..314e5a1 100644
--- a/silx/gui/plot3d/SFViewParamTree.py
+++ b/silx/gui/plot3d/SFViewParamTree.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -102,7 +102,7 @@ class SubjectItem(qt.QStandardItem):
Overloaded method from QStandardItem. The pushData keyword tells
the item to push data to the subject if the role is equal to EditRole.
This is useful to let this method know if the setData method was called
- internaly or from the view.
+ internally or from the view.
:param value: the value ti set to data
:param role: role in the item
@@ -355,6 +355,183 @@ class HighlightColorItem(ColorItem):
return self.subject.getHighlightColor()
+class _LightDirectionAngleBaseItem(SubjectItem):
+ """Base class for directional light angle item."""
+ editable = True
+ persistent = True
+
+ def _init(self):
+ pass
+
+ def getSignals(self):
+ """Override to provide signals to listen"""
+ raise NotImplementedError("MUST be implemented in subclass")
+
+ def _pullData(self):
+ """Override in subclass to get current angle"""
+ raise NotImplementedError("MUST be implemented in subclass")
+
+ def _pushData(self, value, role=qt.Qt.UserRole):
+ """Override in subclass to set the angle"""
+ raise NotImplementedError("MUST be implemented in subclass")
+
+ def getEditor(self, parent, option, index):
+ editor = qt.QSlider(parent)
+ editor.setOrientation(qt.Qt.Horizontal)
+ editor.setMinimum(-90)
+ editor.setMaximum(90)
+ editor.setValue(self._pullData())
+
+ # Wrapping call in lambda is a workaround for PySide with Python 3
+ editor.valueChanged.connect(
+ lambda value: self._pushData(value))
+
+ return editor
+
+ def setEditorData(self, editor):
+ editor.setValue(self._pullData())
+ return True
+
+ def _setModelData(self, editor):
+ value = editor.value()
+ self._pushData(value)
+ return True
+
+
+class LightAzimuthAngleItem(_LightDirectionAngleBaseItem):
+ """Light direction azimuth angle item."""
+
+ def getSignals(self):
+ return self.subject.sigAzimuthAngleChanged
+
+ def _pullData(self):
+ return self.subject.getAzimuthAngle()
+
+ def _pushData(self, value, role=qt.Qt.UserRole):
+ self.subject.setAzimuthAngle(value)
+
+
+class LightAltitudeAngleItem(_LightDirectionAngleBaseItem):
+ """Light direction altitude angle item."""
+
+ def getSignals(self):
+ return self.subject.sigAltitudeAngleChanged
+
+ def _pullData(self):
+ return self.subject.getAltitudeAngle()
+
+ def _pushData(self, value, role=qt.Qt.UserRole):
+ self.subject.setAltitudeAngle(value)
+
+
+class _DirectionalLightProxy(qt.QObject):
+ """Proxy to handle directional light with angles rather than vector.
+ """
+
+ sigAzimuthAngleChanged = qt.Signal()
+ """Signal sent when the azimuth angle has changed."""
+
+ sigAltitudeAngleChanged = qt.Signal()
+ """Signal sent when altitude angle has changed."""
+
+ def __init__(self, light):
+ super(_DirectionalLightProxy, self).__init__()
+ self._light = light
+ light.addListener(self._directionUpdated)
+ self._azimuth = 0.
+ self._altitude = 0.
+
+ def getAzimuthAngle(self):
+ """Returns the signed angle in the horizontal plane.
+
+ Unit: degrees.
+ The 0 angle corresponds to the axis perpendicular to the screen.
+
+ :rtype: float
+ """
+ return self._azimuth
+
+ def getAltitudeAngle(self):
+ """Returns the signed vertical angle from the horizontal plane.
+
+ Unit: degrees.
+ Range: [-90, +90]
+
+ :rtype: float
+ """
+ return self._altitude
+
+ def setAzimuthAngle(self, angle):
+ """Set the horizontal angle.
+
+ :param float angle: Angle from -z axis in zx plane in degrees.
+ """
+ if angle != self._azimuth:
+ self._azimuth = angle
+ self._updateLight()
+ self.sigAzimuthAngleChanged.emit()
+
+ def setAltitudeAngle(self, angle):
+ """Set the horizontal angle.
+
+ :param float angle: Angle from -z axis in zy plane in degrees.
+ """
+ if angle != self._altitude:
+ self._altitude = angle
+ self._updateLight()
+ self.sigAltitudeAngleChanged.emit()
+
+ def _directionUpdated(self, *args, **kwargs):
+ """Handle light direction update in the scene"""
+ # Invert direction to manipulate the 'source' pointing to
+ # the center of the viewport
+ x, y, z = - self._light.direction
+
+ # Horizontal plane is plane xz
+ azimuth = numpy.degrees(numpy.arctan2(x, z))
+ altitude = numpy.degrees(numpy.pi/2. - numpy.arccos(y))
+
+ if (abs(azimuth - self.getAzimuthAngle()) > 0.01 and
+ abs(abs(altitude) - 90.) >= 0.001): # Do not update when at zenith
+ self.setAzimuthAngle(azimuth)
+
+ if abs(altitude - self.getAltitudeAngle()) > 0.01:
+ self.setAltitudeAngle(altitude)
+
+ def _updateLight(self):
+ """Update light direction in the scene"""
+ azimuth = numpy.radians(self._azimuth)
+ delta = numpy.pi/2. - numpy.radians(self._altitude)
+ z = - numpy.sin(delta) * numpy.cos(azimuth)
+ x = - numpy.sin(delta) * numpy.sin(azimuth)
+ y = - numpy.cos(delta)
+ self._light.direction = x, y, z
+
+
+class DirectionalLightGroup(SubjectItem):
+ """
+ Root Item for the directional light
+ """
+
+ def __init__(self,subject, *args):
+ self._light = _DirectionalLightProxy(
+ subject.getPlot3DWidget().viewport.light)
+
+ super(DirectionalLightGroup, self).__init__(subject, *args)
+
+ def _init(self):
+
+ nameItem = qt.QStandardItem('Azimuth')
+ nameItem.setEditable(False)
+ valueItem = LightAzimuthAngleItem(self._light)
+ self.appendRow([nameItem, valueItem])
+
+ nameItem = qt.QStandardItem('Altitude')
+ nameItem.setEditable(False)
+ valueItem = LightAltitudeAngleItem(self._light)
+ self.appendRow([nameItem, valueItem])
+
+
class BoundingBoxItem(SubjectItem):
"""Bounding box, axes labels and grid visibility item.
@@ -402,14 +579,20 @@ class ViewSettingsItem(qt.QStandardItem):
self.setEditable(False)
- classes = (BackgroundColorItem, ForegroundColorItem,
+ classes = (BackgroundColorItem,
+ ForegroundColorItem,
HighlightColorItem,
- BoundingBoxItem, OrientationIndicatorItem)
+ BoundingBoxItem,
+ OrientationIndicatorItem)
for cls in classes:
titleItem = qt.QStandardItem(cls.itemName)
titleItem.setEditable(False)
self.appendRow([titleItem, cls(subject)])
+ nameItem = DirectionalLightGroup(subject, 'Light Direction')
+ valueItem = qt.QStandardItem()
+ self.appendRow([nameItem, valueItem])
+
# Data information ############################################################
@@ -421,7 +604,7 @@ class DataChangedItem(SubjectItem):
def getSignals(self):
subject = self.subject
if subject:
- return subject.sigDataChanged
+ return subject.sigDataChanged, subject.sigTransformChanged
return None
def _init(self):
@@ -463,6 +646,17 @@ class ScaleItem(DataChangedItem):
return ((scale is not None) and str(scale)) or 'N/A'
+class MatrixItem(DataChangedItem):
+
+ def __init__(self, subject, row, *args):
+ self.__row = row
+ super(MatrixItem, self).__init__(subject, *args)
+
+ def _pullData(self):
+ matrix = self.subject.getTransformMatrix()
+ return str(matrix[self.__row])
+
+
class DataSetItem(qt.QStandardItem):
def __init__(self, subject, *args):
@@ -471,12 +665,27 @@ class DataSetItem(qt.QStandardItem):
self.setEditable(False)
- klasses = [DataTypeItem, DataShapeItem, OffsetItem, ScaleItem]
+ klasses = [DataTypeItem, DataShapeItem, OffsetItem]
for klass in klasses:
titleItem = qt.QStandardItem(klass.itemName)
titleItem.setEditable(False)
self.appendRow([titleItem, klass(subject)])
+ matrixItem = qt.QStandardItem('matrix')
+ matrixItem.setEditable(False)
+ valueItem = qt.QStandardItem()
+ self.appendRow([matrixItem, valueItem])
+
+ for row in range(3):
+ titleItem = qt.QStandardItem()
+ titleItem.setEditable(False)
+ valueItem = MatrixItem(subject, row)
+ matrixItem.appendRow([titleItem, valueItem])
+
+ titleItem = qt.QStandardItem(ScaleItem.itemName)
+ titleItem.setEditable(False)
+ self.appendRow([titleItem, ScaleItem(subject)])
+
# Isosurface ##################################################################
@@ -559,9 +768,17 @@ class IsoSurfaceLevelItem(SubjectItem):
return [subject.sigLevelChanged,
subject.sigVisibilityChanged]
+ def getEditor(self, parent, option, index):
+ return FloatEdit(parent)
+
def setEditorData(self, editor):
+ editor.setValue(self._pullData())
return False
+ def _setModelData(self, editor):
+ self._pushData(editor.value())
+ return True
+
def _pullData(self):
return self.subject.getLevel()
@@ -1004,9 +1221,10 @@ class PlaneOrientationItem(SubjectItem):
return [self.subject.getCutPlanes()[0].sigPlaneChanged]
def _pullData(self):
- currentNormal = self.subject.getCutPlanes()[0].getNormal()
+ currentNormal = self.subject.getCutPlanes()[0].getNormal(
+ coordinates='scene')
for _, text, _, normal in self._PLANE_ACTIONS:
- if numpy.array_equal(normal, currentNormal):
+ if numpy.allclose(normal, currentNormal):
return text
return ''
@@ -1023,7 +1241,7 @@ class PlaneOrientationItem(SubjectItem):
def __editorChanged(self, index):
normal = self._PLANE_ACTIONS[index][3]
plane = self.subject.getCutPlanes()[0]
- plane.setNormal(normal)
+ plane.setNormal(normal, coordinates='scene')
plane.moveToCenter()
def setEditorData(self, editor):
@@ -1069,6 +1287,35 @@ class PlaneInterpolationItem(SubjectItem):
self.subject.getCutPlanes()[0].setInterpolation(interpolation)
+class PlaneDisplayBelowMinItem(SubjectItem):
+ """Toggle whether to display or not values <= colormap min of the cut plane
+
+ Item is checkable
+ """
+
+ def _init(self):
+ display = self.subject.getCutPlanes()[0].getDisplayValuesBelowMin()
+ self.setCheckable(True)
+ self.setCheckState(
+ qt.Qt.Checked if display else qt.Qt.Unchecked)
+ self.setData(self._pullData(), role=qt.Qt.DisplayRole, pushData=False)
+
+ def getSignals(self):
+ return [self.subject.getCutPlanes()[0].sigTransparencyChanged]
+
+ def leftClicked(self):
+ checked = self.checkState() == qt.Qt.Checked
+ self._setDisplayValuesBelowMin(checked)
+
+ def _pullData(self):
+ display = self.subject.getCutPlanes()[0].getDisplayValuesBelowMin()
+ self._setDisplayValuesBelowMin(display)
+ return "Displayed" if display else "Hidden"
+
+ def _setDisplayValuesBelowMin(self, display):
+ self.subject.getCutPlanes()[0].setDisplayValuesBelowMin(display)
+
+
class PlaneColormapItem(ColormapBase):
"""
colormap name item.
@@ -1241,6 +1488,11 @@ class PlaneGroup(SubjectItem):
valueItem = PlaneMaxRangeItem(self.subject)
self.appendRow([nameItem, valueItem])
+ nameItem = qt.QStandardItem('Values<=Min')
+ nameItem.setEditable(False)
+ valueItem = PlaneDisplayBelowMinItem(self.subject)
+ self.appendRow([nameItem, valueItem])
+
class PlaneVisibleItem(SubjectItem):
"""
diff --git a/silx/gui/plot3d/ScalarFieldView.py b/silx/gui/plot3d/ScalarFieldView.py
index 6a4d9d4..a41999b 100644
--- a/silx/gui/plot3d/ScalarFieldView.py
+++ b/silx/gui/plot3d/ScalarFieldView.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -56,48 +56,6 @@ from .tools import InteractiveModeToolBar
_logger = logging.getLogger(__name__)
-class _BoundedGroup(scene.Group):
- """Group with data bounds"""
-
- _shape = None # To provide a default value without overriding __init__
-
- @property
- def shape(self):
- """Data shape (depth, height, width) of this group or None"""
- return self._shape
-
- @shape.setter
- def shape(self, shape):
- if shape is None:
- self._shape = None
- else:
- depth, height, width = shape
- self._shape = float(depth), float(height), float(width)
-
- @property
- def size(self):
- """Data size (width, height, depth) of this group or None"""
- shape = self.shape
- if shape is None:
- return None
- else:
- return shape[2], shape[1], shape[0]
-
- @size.setter
- def size(self, size):
- if size is None:
- self.shape = None
- else:
- self.shape = size[2], size[1], size[0]
-
- def _bounds(self, dataBounds=False):
- if dataBounds and self.size is not None:
- return numpy.array(((0., 0., 0.), self.size),
- dtype=numpy.float32)
- else:
- return super(_BoundedGroup, self)._bounds(dataBounds)
-
-
class Isosurface(qt.QObject):
"""Class representing an iso-surface
@@ -272,24 +230,26 @@ class SelectedRegion(object):
:param arrayRange: Range of the selection in the array
((zmin, zmax), (ymin, ymax), (xmin, xmax))
+ :param dataBBox: Bounding box of the selection in data coordinates
+ ((xmin, xmax), (ymin, ymax), (zmin, zmax))
:param translation: Offset from array to data coordinates (ox, oy, oz)
:param scale: Scale from array to data coordinates (sx, sy, sz)
"""
- def __init__(self, arrayRange,
+ def __init__(self, arrayRange, dataBBox,
translation=(0., 0., 0.),
scale=(1., 1., 1.)):
self._arrayRange = numpy.array(arrayRange, copy=True, dtype=numpy.int)
assert self._arrayRange.shape == (3, 2)
assert numpy.all(self._arrayRange[:, 1] >= self._arrayRange[:, 0])
+
+ self._dataRange = dataBBox
+
self._translation = numpy.array(translation, dtype=numpy.float32)
assert self._translation.shape == (3,)
self._scale = numpy.array(scale, dtype=numpy.float32)
assert self._scale.shape == (3,)
- self._dataRange = (self._translation.reshape(3, -1) +
- self._arrayRange[::-1] * self._scale.reshape(3, -1))
-
def getArrayRange(self):
"""Returns array ranges of the selection: 3x2 array of int
@@ -311,6 +271,10 @@ class SelectedRegion(object):
def getDataRange(self):
"""Range in the data coordinates of the selection: 3x2 array of float
+ When the transform matrix is not the identity matrix
+ (e.g., rotation, skew) the returned range is the one of the selected
+ region bounding box in data coordinates.
+
:return: A numpy array with ((xmin, xmax), (ymin, ymax), (zmin, zmax))
:rtype: numpy.ndarray
"""
@@ -336,7 +300,8 @@ class SelectedRegion(object):
class CutPlane(qt.QObject):
"""Class representing a cutting plane
- :param ScalarFieldView sfView: Widget in which the cut plane is applied.
+ :param ~silx.gui.plot3d.ScalarFieldView.ScalarFieldView sfView:
+ Widget in which the cut plane is applied.
"""
sigVisibilityChanged = qt.Signal(bool)
@@ -357,6 +322,12 @@ class CutPlane(qt.QObject):
This signal provides the new colormap.
"""
+ sigTransparencyChanged = qt.Signal()
+ """Signal emitted when the transparency of the plane has changed.
+
+ This signal is emitted when calling :meth:`setDisplayValuesBelowMin`.
+ """
+
sigInterpolationChanged = qt.Signal(str)
"""Signal emitted when the cut plane interpolation has changed
@@ -367,12 +338,22 @@ class CutPlane(qt.QObject):
super(CutPlane, self).__init__(parent=sfView)
self._dataRange = None
+ self._visible = False
+
+ self.__syncPlane = True
- self._plane = cutplane.CutPlane(normal=(0, 1, 0))
- self._plane.alpha = 1.
- self._plane.visible = self._visible = False
- self._plane.addListener(self._planeChanged)
- self._plane.plane.addListener(self._planePositionChanged)
+ # Plane stroke on the outer bounding box
+ self._planeStroke = primitives.PlaneInGroup(normal=(0, 1, 0))
+ self._planeStroke.visible = self._visible
+ self._planeStroke.addListener(self._planeChanged)
+ self._planeStroke.plane.addListener(self._planePositionChanged)
+
+ # Plane with texture on the data bounding box
+ self._dataPlane = cutplane.CutPlane(normal=(0, 1, 0))
+ self._dataPlane.strokeVisible = False
+ self._dataPlane.alpha = 1.
+ self._dataPlane.visible = self._visible
+ self._dataPlane.plane.addListener(self._planePositionChanged)
self._colormap = Colormap(
name='gray', normalization='linear', vmin=None, vmax=None)
@@ -380,14 +361,40 @@ class CutPlane(qt.QObject):
self._updateSceneColormap()
sfView.sigDataChanged.connect(self._sfViewDataChanged)
+ sfView.sigTransformChanged.connect(self._sfViewTransformChanged)
+
+ def _get3DPrimitives(self):
+ """Return the cut plane scene node."""
+ return self._planeStroke, self._dataPlane
+
+ def _keepPlaneInBBox(self):
+ """Makes sure the plane intersect its parent bounding box if any"""
+ bounds = self._planeStroke.parent.bounds(dataBounds=True)
+ if bounds is not None:
+ self._planeStroke.plane.point = numpy.clip(
+ self._planeStroke.plane.point,
+ a_min=bounds[0], a_max=bounds[1])
+
+ @staticmethod
+ def _syncPlanes(master, slave):
+ """Move slave PlaneInGroup so that it is coplanar with master.
+
+ :param PlaneInGroup master: Reference PlaneInGroup
+ :param PlaneInGroup slave: PlaneInGroup to align
+ """
+ masterToSlave = transform.StaticTransformList([
+ slave.objectToSceneTransform.inverse(),
+ master.objectToSceneTransform])
- def _get3DPrimitive(self):
- """Return the cut plane scene node"""
- return self._plane
+ point = masterToSlave.transformPoint(
+ master.plane.point)
+ normal = masterToSlave.transformNormal(
+ master.plane.normal)
+ slave.plane.setPlane(point, normal)
def _sfViewDataChanged(self):
"""Handle data change in the ScalarFieldView this plane belongs to"""
- self._plane.setData(self.sender().getData(), copy=False)
+ self._dataPlane.setData(self.sender().getData(), copy=False)
# Store data range info as 3-tuple of values
self._dataRange = self.sender().getDataRange()
@@ -398,6 +405,15 @@ class CutPlane(qt.QObject):
if self.getColormap().isAutoscale():
self._updateSceneColormap()
+ self._keepPlaneInBBox()
+
+ def _sfViewTransformChanged(self):
+ """Handle transform changed in the ScalarFieldView"""
+ self._keepPlaneInBBox()
+ self._syncPlanes(master=self._planeStroke,
+ slave=self._dataPlane)
+ self.sigPlaneChanged.emit()
+
def _planeChanged(self, source, *args, **kwargs):
"""Handle events from the plane primitive"""
# Using _visible for now, until scene as more info in events
@@ -407,68 +423,144 @@ class CutPlane(qt.QObject):
def _planePositionChanged(self, source, *args, **kwargs):
"""Handle update of cut plane position and normal"""
- if self._plane.visible:
- self.sigPlaneChanged.emit()
+ if self.__syncPlane:
+ self.__syncPlane = False
+ if source is self._planeStroke.plane:
+ self._syncPlanes(master=self._planeStroke,
+ slave=self._dataPlane)
+ elif source is self._dataPlane.plane:
+ self._syncPlanes(master=self._dataPlane,
+ slave=self._planeStroke)
+ else:
+ _logger.error('Received an unknown object %s',
+ str(source))
+
+ if self._planeStroke.visible or self._dataPlane.visible:
+ self.sigPlaneChanged.emit()
+
+ self.__syncPlane = True
# Plane position
def moveToCenter(self):
"""Move cut plane to center of data set"""
- self._plane.moveToCenter()
+ self._planeStroke.moveToCenter()
def isValid(self):
"""Returns whether the cut plane is defined or not (bool)"""
- return self._plane.isValid
+ return self._planeStroke.isValid
+
+ def _plane(self, coordinates='array'):
+ """Returns the scene plane to set.
+
+ :param str coordinates: The coordinate system to use:
+ Either 'scene' or 'array' (default)
+ :rtype: Plane
+ :raise ValueError: If coordinates is not correct
+ """
+ if coordinates == 'scene':
+ return self._planeStroke.plane
+ elif coordinates == 'array':
+ return self._dataPlane.plane
+ else:
+ raise ValueError(
+ 'Unsupported coordinates: %s' % str(coordinates))
- def getNormal(self):
+ def getNormal(self, coordinates='array'):
"""Returns the normal of the plane (as a unit vector)
+ :param str coordinates: The coordinate system to use:
+ Either 'scene' or 'array' (default)
:return: Normal (nx, ny, nz), vector is 0 if no plane is defined
:rtype: numpy.ndarray
+ :raise ValueError: If coordinates is not correct
"""
- return self._plane.plane.normal
+ return self._plane(coordinates).normal
- def setNormal(self, normal):
- """Set the normal of the plane
+ def setNormal(self, normal, coordinates='array'):
+ """Set the normal of the plane.
:param normal: 3-tuple of float: nx, ny, nz
+ :param str coordinates: The coordinate system to use:
+ Either 'scene' or 'array' (default)
+ :raise ValueError: If coordinates is not correct
"""
- self._plane.plane.normal = normal
+ self._plane(coordinates).normal = normal
- def getPoint(self):
- """Returns a point on the plane
+ def getPoint(self, coordinates='array'):
+ """Returns a point on the plane.
+ :param str coordinates: The coordinate system to use:
+ Either 'scene' or 'array' (default)
:return: (x, y, z)
:rtype: numpy.ndarray
+ :raise ValueError: If coordinates is not correct
+ """
+ return self._plane(coordinates).point
+
+ def setPoint(self, point, constraint=True, coordinates='array'):
+ """Set a point contained in the plane.
+
+ Warning: The plane might not intersect the bounding box of the data.
+
+ :param point: (x, y, z) position
+ :type point: 3-tuple of float
+ :param bool constraint:
+ True (default) to make sure the plane intersect data bounding box,
+ False to set the plane without any constraint.
+ :raise ValueError: If coordinates is not correc
"""
- return self._plane.plane.point
+ self._plane(coordinates).point = point
+ if constraint:
+ self._keepPlaneInBBox()
- def getParameters(self):
+ def getParameters(self, coordinates='array'):
"""Returns the plane equation parameters: a*x + b*y + c*z + d = 0
+ :param str coordinates: The coordinate system to use:
+ Either 'scene' or 'array' (default)
:return: Plane equation parameters: (a, b, c, d)
:rtype: numpy.ndarray
+ :raise ValueError: If coordinates is not correct
+ """
+ return self._plane(coordinates).parameters
+
+ def setParameters(self, parameters, constraint=True, coordinates='array'):
+ """Set the plane equation parameters: a*x + b*y + c*z + d = 0
+
+ Warning: The plane might not intersect the bounding box of the data.
+
+ :param parameters: (a, b, c, d) plane equation parameters.
+ :type parameters: 4-tuple of float
+ :param bool constraint:
+ True (default) to make sure the plane intersect data bounding box,
+ False to set the plane without any constraint.
+ :raise ValueError: If coordinates is not correc
"""
- return self._plane.plane.parameters
+ self._plane(coordinates).parameters = parameters
+ if constraint:
+ self._keepPlaneInBBox()
# Visibility
def isVisible(self):
"""Returns True if the plane is visible, False otherwise"""
- return self._plane.visible
+ return self._planeStroke.visible
def setVisible(self, visible):
"""Set the visibility of the plane
:param bool visible: True to make plane visible
"""
- self._plane.visible = visible
+ visible = bool(visible)
+ self._planeStroke.visible = visible
+ self._dataPlane.visible = visible
# Border stroke
def getStrokeColor(self):
"""Returns the color of the plane border (QColor)"""
- return qt.QColor.fromRgbF(*self._plane.color)
+ return qt.QColor.fromRgbF(*self._planeStroke.color)
def setStrokeColor(self, color):
"""Set the color of the plane border.
@@ -477,7 +569,9 @@ class CutPlane(qt.QObject):
:type color:
QColor, str or array-like of 3 or 4 float in [0., 1.] or uint8
"""
- self._plane.color = rgba(color)
+ color = rgba(color)
+ self._planeStroke.color = color
+ self._dataPlane.color = color
# Data
@@ -501,7 +595,7 @@ class CutPlane(qt.QObject):
:return: 'nearest' or 'linear'
:rtype: str
"""
- return self._plane.interpolation
+ return self._dataPlane.interpolation
def setInterpolation(self, interpolation):
"""Set the interpolation used to display to cut plane
@@ -511,7 +605,7 @@ class CutPlane(qt.QObject):
:param str interpolation: 'nearest' or 'linear'
"""
if interpolation != self.getInterpolation():
- self._plane.interpolation = interpolation
+ self._dataPlane.interpolation = interpolation
self.sigInterpolationChanged.emit(interpolation)
# Colormap
@@ -527,11 +621,29 @@ class CutPlane(qt.QObject):
# """
# self._plane.alpha = alpha
+ def getDisplayValuesBelowMin(self):
+ """Return whether values <= colormap min are displayed or not.
+
+ :rtype: bool
+ """
+ return self._dataPlane.colormap.displayValuesBelowMin
+
+ def setDisplayValuesBelowMin(self, display):
+ """Set whether to display values <= colormap min.
+
+ :param bool display: True to show values below min,
+ False to discard them
+ """
+ display = bool(display)
+ if display != self.getDisplayValuesBelowMin():
+ self._dataPlane.colormap.displayValuesBelowMin = display
+ self.sigTransparencyChanged.emit()
+
def getColormap(self):
"""Returns the colormap set by :meth:`setColormap`.
:return: The colormap
- :rtype: Colormap
+ :rtype: ~silx.gui.plot.Colormap.Colormap
"""
return self._colormap
@@ -548,7 +660,7 @@ class CutPlane(qt.QObject):
:param name: Name of the colormap in
'gray', 'reversed gray', 'temperature', 'red', 'green', 'blue'.
Or Colormap object.
- :type name: str or Colormap
+ :type name: str or ~silx.gui.plot.Colormap.Colormap
:param str norm: Colormap mapping: 'linear' or 'log'.
:param float vmin: The minimum value of the range or None for autoscale
:param float vmax: The maximum value of the range or None for autoscale
@@ -578,21 +690,14 @@ class CutPlane(qt.QObject):
:return: 2-tuple of float
"""
- return self._plane.colormap.range_
+ return self._dataPlane.colormap.range_
def _updateSceneColormap(self):
"""Synchronizes scene's colormap with Colormap object"""
colormap = self.getColormap()
- sceneCMap = self._plane.colormap
+ sceneCMap = self._dataPlane.colormap
- indices = numpy.linspace(0., 1., 256)
- colormapDisp = Colormap(name=colormap.getName(),
- normalization=Colormap.LINEAR,
- vmin=None,
- vmax=None,
- colors=colormap.getColormapLUT())
- colors = colormapDisp.applyToData(indices)
- sceneCMap.colormap = colors
+ sceneCMap.colormap = colormap.getNColors()
sceneCMap.norm = colormap.getNormalization()
range_ = colormap.getColormapRange(data=self._dataRange)
@@ -614,14 +719,14 @@ class _CutPlaneImage(object):
def __init__(self, cutPlane):
# Init attributes with default values
self._isValid = False
- self._data = numpy.array([])
+ self._data = numpy.zeros((0, 0), dtype=numpy.float32)
+ self._index = 0
self._xLabel = ''
self._yLabel = ''
self._normalLabel = ''
- self._scale = 1., 1.
- self._translation = 0., 0.
- self._index = 0
- self._position = 0.
+ self._scale = float('nan'), float('nan')
+ self._translation = float('nan'), float('nan')
+ self._position = float('nan')
sfView = cutPlane.parent()
if not sfView or not cutPlane.isValid():
@@ -633,19 +738,30 @@ class _CutPlaneImage(object):
_logger.info("No data available")
return
- normal = cutPlane.getNormal()
- point = numpy.array(cutPlane.getPoint(), dtype=numpy.int)
+ normal = cutPlane.getNormal(coordinates='array')
+ point = cutPlane.getPoint(coordinates='array')
- if numpy.all(numpy.equal(normal, (1., 0., 0.))):
- index = max(0, min(point[0], data.shape[2] - 1))
+ if numpy.linalg.norm(numpy.cross(normal, (1., 0., 0.))) < 0.0017:
+ if not 0 <= point[0] <= data.shape[2]:
+ _logger.info("Plane outside dataset")
+ return
+ index = max(0, min(int(point[0]), data.shape[2] - 1))
slice_ = data[:, :, index]
xAxisIndex, yAxisIndex, normalAxisIndex = 1, 2, 0 # y, z, x
- elif numpy.all(numpy.equal(normal, (0., 1., 0.))):
- index = max(0, min(point[1], data.shape[1] - 1))
+
+ elif numpy.linalg.norm(numpy.cross(normal, (0., 1., 0.))) < 0.0017:
+ if not 0 <= point[1] <= data.shape[1]:
+ _logger.info("Plane outside dataset")
+ return
+ index = max(0, min(int(point[1]), data.shape[1] - 1))
slice_ = numpy.transpose(data[:, index, :])
xAxisIndex, yAxisIndex, normalAxisIndex = 2, 0, 1 # z, x, y
- elif numpy.all(numpy.equal(normal, (0., 0., 1.))):
- index = max(0, min(point[2], data.shape[0] - 1))
+
+ elif numpy.linalg.norm(numpy.cross(normal, (0., 0., 1.))) < 0.0017:
+ if not 0 <= point[2] <= data.shape[0]:
+ _logger.info("Plane outside dataset")
+ return
+ index = max(0, min(int(point[2]), data.shape[0] - 1))
slice_ = data[index, :, :]
xAxisIndex, yAxisIndex, normalAxisIndex = 0, 1, 2 # x, y, z
else:
@@ -657,21 +773,25 @@ class _CutPlaneImage(object):
self._isValid = True
self._data = numpy.array(slice_, copy=True)
+ self._index = index
- labels = sfView.getAxesLabels()
- scale = sfView.getScale()
- translation = sfView.getTranslation()
+ # Only store extra information when no transform matrix is set
+ # Otherwise this information can be meaningless
+ if numpy.all(numpy.equal(sfView.getTransformMatrix(),
+ numpy.identity(3, dtype=numpy.float32))):
+ labels = sfView.getAxesLabels()
+ self._xLabel = labels[xAxisIndex]
+ self._yLabel = labels[yAxisIndex]
+ self._normalLabel = labels[normalAxisIndex]
- self._xLabel = labels[xAxisIndex]
- self._yLabel = labels[yAxisIndex]
- self._normalLabel = labels[normalAxisIndex]
+ scale = sfView.getScale()
+ self._scale = scale[xAxisIndex], scale[yAxisIndex]
- self._scale = scale[xAxisIndex], scale[yAxisIndex]
- self._translation = translation[xAxisIndex], translation[yAxisIndex]
+ translation = sfView.getTranslation()
+ self._translation = translation[xAxisIndex], translation[yAxisIndex]
- self._index = index
- self._position = float(index * scale[normalAxisIndex] +
- translation[normalAxisIndex])
+ self._position = float(index * scale[normalAxisIndex] +
+ translation[normalAxisIndex])
def isValid(self):
"""Returns True if the cut plane image is defined (bool)"""
@@ -727,6 +847,13 @@ class ScalarFieldView(Plot3DWindow):
sigDataChanged = qt.Signal()
"""Signal emitted when the scalar data field has changed."""
+ sigTransformChanged = qt.Signal()
+ """Signal emitted when the transformation has changed.
+
+ It is emitted by :meth:`setTranslation`, :meth:`setTransformMatrix`,
+ :meth:`setScale`.
+ """
+
sigSelectedRegionChanged = qt.Signal(object)
"""Signal emitted when the selected region has changed.
@@ -745,6 +872,7 @@ class ScalarFieldView(Plot3DWindow):
# Transformations
self._dataScale = transform.Scale()
self._dataTranslate = transform.Translate()
+ self._dataTransform = transform.Matrix() # default to identity
self._foregroundColor = 1., 1., 1., 1.
self._highlightColor = 0.7, 0.7, 0., 1.
@@ -752,8 +880,13 @@ class ScalarFieldView(Plot3DWindow):
self._data = None
self._dataRange = None
- self._group = _BoundedGroup()
- self._group.transforms = [self._dataTranslate, self._dataScale]
+ self._group = primitives.BoundedGroup()
+ self._group.transforms = [
+ self._dataTranslate, self._dataTransform, self._dataScale]
+
+ self._bbox = axes.LabelledAxes()
+ self._bbox.children = [self._group]
+ self.getPlot3DWidget().viewport.scene.children.append(self._bbox)
self._selectionBox = primitives.Box()
self._selectionBox.strokeSmooth = False
@@ -766,7 +899,9 @@ class ScalarFieldView(Plot3DWindow):
self._cutPlane = CutPlane(sfView=self)
self._cutPlane.sigVisibilityChanged.connect(
self._planeVisibilityChanged)
- self._group.children.append(self._cutPlane._get3DPrimitive())
+ planeStroke, dataPlane = self._cutPlane._get3DPrimitives()
+ self._bbox.children.append(planeStroke)
+ self._group.children.append(dataPlane)
self._isogroup = primitives.GroupDepthOffset()
self._isogroup.transforms = [
@@ -781,10 +916,6 @@ class ScalarFieldView(Plot3DWindow):
]
self._group.children.append(self._isogroup)
- self._bbox = axes.LabelledAxes()
- self._bbox.children = [self._group]
- self.getPlot3DWidget().viewport.scene.children.append(self._bbox)
-
self._initPanPlaneAction()
self._updateColors()
@@ -932,9 +1063,10 @@ class ScalarFieldView(Plot3DWindow):
"""Creates and init the pan plane action"""
self._panPlaneAction = qt.QAction(self)
self._panPlaneAction.setIcon(icons.getQIcon('3d-plane-pan'))
- self._panPlaneAction.setText('plane')
+ self._panPlaneAction.setText('Pan plane')
self._panPlaneAction.setCheckable(True)
- self._panPlaneAction.setToolTip('pan the cutting plane')
+ self._panPlaneAction.setToolTip(
+ 'Pan the cutting plane. Press <b>Ctrl</b> to rotate the scene.')
self._panPlaneAction.setEnabled(False)
self._panPlaneAction.triggered[bool].connect(self._planeActionTriggered)
@@ -972,24 +1104,21 @@ class ScalarFieldView(Plot3DWindow):
sceneScale = self.getPlot3DWidget().viewport.scene.transforms[0]
if mode == 'plane':
- self.getPlot3DWidget().setInteractiveMode(None)
-
- self.getPlot3DWidget().eventHandler = \
- interaction.PanPlaneZoomOnWheelControl(
- self.getPlot3DWidget().viewport,
- self._cutPlane._get3DPrimitive(),
- mode='position',
- scaleTransform=sceneScale)
- else:
- self.getPlot3DWidget().setInteractiveMode(mode)
+ mode = interaction.PanPlaneZoomOnWheelControl(
+ self.getPlot3DWidget().viewport,
+ self._cutPlane._get3DPrimitives()[0],
+ mode='position',
+ orbitAroundCenter=False,
+ scaleTransform=sceneScale)
+
+ self.getPlot3DWidget().setInteractiveMode(mode)
self._updateColors()
def getInteractiveMode(self):
"""Returns the current interaction mode, see :meth:`setInteractiveMode`
"""
- if (isinstance(self.getPlot3DWidget().eventHandler,
- interaction.PanPlaneZoomOnWheelControl) or
- self.getPlot3DWidget().eventHandler is None):
+ if isinstance(self.getPlot3DWidget().eventHandler,
+ interaction.PanPlaneZoomOnWheelControl):
return 'plane'
else:
return self.getPlot3DWidget().getInteractiveMode()
@@ -1085,6 +1214,7 @@ class ScalarFieldView(Plot3DWindow):
scale = numpy.array((sx, sy, sz), dtype=numpy.float32)
if not numpy.all(numpy.equal(scale, self.getScale())):
self._dataScale.scale = scale
+ self.sigTransformChanged.emit()
self.centerScene() # Reset viewpoint
def getScale(self):
@@ -1102,6 +1232,7 @@ class ScalarFieldView(Plot3DWindow):
translation = numpy.array((x, y, z), dtype=numpy.float32)
if not numpy.all(numpy.equal(translation, self.getTranslation())):
self._dataTranslate.translation = translation
+ self.sigTransformChanged.emit()
self.centerScene() # Reset viewpoint
def getTranslation(self):
@@ -1109,6 +1240,28 @@ class ScalarFieldView(Plot3DWindow):
"""
return self._dataTranslate.translation
+ def setTransformMatrix(self, matrix3x3):
+ """Set the transform matrix applied to the data.
+
+ :param numpy.ndarray matrix: 3x3 transform matrix
+ """
+ matrix3x3 = numpy.array(matrix3x3, copy=True, dtype=numpy.float32)
+ if not numpy.all(numpy.equal(matrix3x3, self.getTransformMatrix())):
+ matrix = numpy.identity(4, dtype=numpy.float32)
+ matrix[:3, :3] = matrix3x3
+ self._dataTransform.setMatrix(matrix)
+ self.sigTransformChanged.emit()
+ self.centerScene() # Reset viewpoint
+
+ def getTransformMatrix(self):
+ """Returns the transform matrix applied to the data.
+
+ See :meth:`setTransformMatrix`.
+
+ :rtype: numpy.ndarray
+ """
+ return self._dataTransform.getMatrix()[:3, :3]
+
# Axes labels
def isBoundingBoxVisible(self):
@@ -1123,7 +1276,8 @@ class ScalarFieldView(Plot3DWindow):
:param bool visible: True to show axes, False to hide
"""
- self._bbox.boxVisible = bool(visible)
+ visible = bool(visible)
+ self._bbox.boxVisible = visible
def setAxesLabels(self, xlabel=None, ylabel=None, zlabel=None):
"""Set the text labels of the axes.
@@ -1297,7 +1451,9 @@ class ScalarFieldView(Plot3DWindow):
if self._selectedRange is None:
return None
else:
- return SelectedRegion(self._selectedRange,
+ dataBBox = self._group.transforms.transformBounds(
+ self._selectedRange[::-1].T).T
+ return SelectedRegion(self._selectedRange, dataBBox,
translation=self.getTranslation(),
scale=self.getScale())
diff --git a/silx/gui/plot3d/SceneWidget.py b/silx/gui/plot3d/SceneWidget.py
new file mode 100644
index 0000000..4e75515
--- /dev/null
+++ b/silx/gui/plot3d/SceneWidget.py
@@ -0,0 +1,646 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module provides a widget to view data sets in 3D."""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "26/10/2017"
+
+import numpy
+import weakref
+
+from silx.third_party import enum
+from .. import qt
+from ..plot.Colors import rgba
+
+from .Plot3DWidget import Plot3DWidget
+from . import items
+from .scene import interaction
+from ._model import SceneModel, visitQAbstractItemModel
+from ._model.items import Item3DRow
+
+
+__all__ = ['items', 'SceneWidget']
+
+
+class _SceneSelectionHighlightManager(object):
+ """Class controlling the highlight of the selection in a SceneWidget
+
+ :param ~silx.gui.plot3d.SceneWidget.SceneSelection:
+ """
+
+ def __init__(self, selection):
+ assert isinstance(selection, SceneSelection)
+ self._sceneWidget = weakref.ref(selection.parent())
+
+ self._enabled = True
+ self._previousBBoxState = None
+
+ self.__selectItem(selection.getCurrentItem())
+ selection.sigCurrentChanged.connect(self.__currentChanged)
+
+ def isEnabled(self):
+ """Returns True if highlight of selection in enabled.
+
+ :rtype: bool
+ """
+ return self._enabled
+
+ def setEnabled(self, enabled=True):
+ """Activate/deactivate selection highlighting
+
+ :param bool enabled: True (default) to enable selection highlighting
+ """
+ enabled = bool(enabled)
+ if enabled != self._enabled:
+ self._enabled = enabled
+
+ sceneWidget = self.getSceneWidget()
+ if sceneWidget is not None:
+ selection = sceneWidget.selection()
+ current = selection.getCurrentItem()
+
+ if enabled:
+ self.__selectItem(current)
+ selection.sigCurrentChanged.connect(self.__currentChanged)
+
+ else: # disabled
+ self.__unselectItem(current)
+ selection.sigCurrentChanged.disconnect(
+ self.__currentChanged)
+
+ def getSceneWidget(self):
+ """Returns the SceneWidget this class controls highlight for.
+
+ :rtype: ~silx.gui.plot3d.SceneWidget.SceneWidget
+ """
+ return self._sceneWidget()
+
+ def __selectItem(self, current):
+ """Highlight given item.
+
+ :param ~silx.gui.plot3d.items.Item3D current: New current or None
+ """
+ if current is None:
+ return
+
+ sceneWidget = self.getSceneWidget()
+ if sceneWidget is None:
+ return
+
+ if isinstance(current, items.DataItem3D):
+ self._previousBBoxState = current.isBoundingBoxVisible()
+ current.setBoundingBoxVisible(True)
+ current._setForegroundColor(sceneWidget.getHighlightColor())
+ current.sigItemChanged.connect(self.__selectedChanged)
+
+ def __unselectItem(self, current):
+ """Remove highlight of given item.
+
+ :param ~silx.gui.plot3d.items.Item3D current:
+ Currently highlighted item
+ """
+ if current is None:
+ return
+
+ sceneWidget = self.getSceneWidget()
+ if sceneWidget is None:
+ return
+
+ # Restore bbox visibility and color
+ current.sigItemChanged.disconnect(self.__selectedChanged)
+ if (self._previousBBoxState is not None and
+ isinstance(current, items.DataItem3D)):
+ current.setBoundingBoxVisible(self._previousBBoxState)
+ current._setForegroundColor(sceneWidget.getForegroundColor())
+
+ def __currentChanged(self, current, previous):
+ """Handle change of current item in the selection
+
+ :param ~silx.gui.plot3d.items.Item3D current: New current or None
+ :param ~silx.gui.plot3d.items.Item3D previous: Previous current or None
+ """
+ self.__unselectItem(previous)
+ self.__selectItem(current)
+
+ def __selectedChanged(self, event):
+ """Handle updates of selected item bbox.
+
+ If bbox gets changed while selected, do not restore state.
+
+ :param event:
+ """
+ if event == items.Item3DChangedType.BOUNDING_BOX_VISIBLE:
+ self._previousBBoxState = None
+
+
+@enum.unique
+class HighlightMode(enum.Enum):
+ """:class:`SceneSelection` highlight modes"""
+
+ NONE = 'noHighlight'
+ """Do not highlight selected item"""
+
+ BOUNDING_BOX = 'boundingBox'
+ """Highlight selected item bounding box"""
+
+
+class SceneSelection(qt.QObject):
+ """Object managing a :class:`SceneWidget` selection
+
+ :param SceneWidget parent:
+ """
+
+ NO_SELECTION = 0
+ """Flag for no item selected"""
+
+ sigCurrentChanged = qt.Signal(object, object)
+ """This signal is emitted whenever the current item changes.
+
+ It provides the current and previous items.
+ Either of those can be :attr:`NO_SELECTION`.
+ """
+
+ def __init__(self, parent=None):
+ super(SceneSelection, self).__init__(parent)
+ self.__current = None # Store weakref to current item
+ self.__selectionModel = None # Store sync selection model
+ self.__syncInProgress = False # True during model synchronization
+
+ self.__highlightManager = _SceneSelectionHighlightManager(self)
+
+ def getHighlightMode(self):
+ """Returns current selection highlight mode.
+
+ Either NONE or BOUNDING_BOX.
+
+ :rtype: HighlightMode
+ """
+ if self.__highlightManager.isEnabled():
+ return HighlightMode.BOUNDING_BOX
+ else:
+ return HighlightMode.NONE
+
+ def setHighlightMode(self, mode):
+ """Set selection highlighting mode
+
+ :param HighlightMode mode: The mode to use
+ """
+ assert isinstance(mode, HighlightMode)
+ self.__highlightManager.setEnabled(mode == HighlightMode.BOUNDING_BOX)
+
+ def getCurrentItem(self):
+ """Returns the current item in the scene or None.
+
+ :rtype: Union[~silx.gui.plot3d.items.Item3D, None]
+ """
+ return None if self.__current is None else self.__current()
+
+ def setCurrentItem(self, item):
+ """Set the current item in the scene.
+
+ :param Union[Item3D, None] item:
+ The new item to select or None to clear the selection.
+ :raise ValueError: If the item is not the widget's scene
+ """
+ previous = self.getCurrentItem()
+ if previous is not None:
+ previous.sigItemChanged.disconnect(self.__currentChanged)
+
+ if item is None:
+ self.__current = None
+
+ elif isinstance(item, items.Item3D):
+ parent = self.parent()
+ assert isinstance(parent, SceneWidget)
+
+ sceneGroup = parent.getSceneGroup()
+ if item is sceneGroup or item.root() is sceneGroup:
+ item.sigItemChanged.connect(self.__currentChanged)
+ self.__current = weakref.ref(item)
+ else:
+ raise ValueError(
+ 'Item is not in this SceneWidget: %s' % str(item))
+
+ else:
+ raise ValueError(
+ 'Not an Item3D: %s' % str(item))
+
+ current = self.getCurrentItem()
+ if current is not previous:
+ self.sigCurrentChanged.emit(current, previous)
+ self.__updateSelectionModel()
+
+ def __currentChanged(self, event):
+ """Handle updates of the selected item"""
+ if event == items.Item3DChangedType.ROOT_ITEM:
+ item = self.sender()
+ if item.root() != self.getSceneGroup():
+ self.setSelectedItem(None)
+
+ # Synchronization with QItemSelectionModel
+
+ def _getSyncSelectionModel(self):
+ """Returns the QItemSelectionModel this selection is synchronized with.
+
+ :rtype: Union[QItemSelectionModel, None]
+ """
+ return self.__selectionModel
+
+ def _setSyncSelectionModel(self, selectionModel):
+ """Synchronizes this selection object with a selection model.
+
+ :param Union[QItemSelectionModel, None] selectionModel:
+ :raise ValueError: If the selection model does not correspond
+ to the same :class:`SceneWidget`
+ """
+ if (not isinstance(selectionModel, qt.QItemSelectionModel) or
+ not isinstance(selectionModel.model(), SceneModel) or
+ selectionModel.model().sceneWidget() is not self.parent()):
+ raise ValueError("Expecting a QItemSelectionModel "
+ "attached to the same SceneWidget")
+
+ # Disconnect from previous selection model
+ previousSelectionModel = self._getSyncSelectionModel()
+ if previousSelectionModel is not None:
+ previousSelectionModel.selectionChanged.disconnect(
+ self.__selectionModelSelectionChanged)
+
+ self.__selectionModel = selectionModel
+
+ if selectionModel is not None:
+ # Connect to new selection model
+ selectionModel.selectionChanged.connect(
+ self.__selectionModelSelectionChanged)
+ self.__updateSelectionModel()
+
+ def __selectionModelSelectionChanged(self, selected, deselected):
+ """Handle QItemSelectionModel selection updates.
+
+ :param QItemSelection selected:
+ :param QItemSelection deselected:
+ """
+ if self.__syncInProgress:
+ return
+
+ indices = selected.indexes()
+ if not indices:
+ item = None
+
+ else: # Select the first selected item
+ index = indices[0]
+ itemRow = index.internalPointer()
+ if isinstance(itemRow, Item3DRow):
+ item = itemRow.item()
+ else:
+ item = None
+
+ self.setCurrentItem(item)
+
+ def __updateSelectionModel(self):
+ """Sync selection model when current item has been updated"""
+ selectionModel = self._getSyncSelectionModel()
+ if selectionModel is None:
+ return
+
+ currentItem = self.getCurrentItem()
+
+ if currentItem is None:
+ selectionModel.clear()
+
+ else:
+ # visit the model to find selectable index corresponding to item
+ model = selectionModel.model()
+ for index in visitQAbstractItemModel(model):
+ itemRow = index.internalPointer()
+ if (isinstance(itemRow, Item3DRow) and
+ itemRow.item() is currentItem and
+ index.flags() & qt.Qt.ItemIsSelectable):
+ # This is the item we are looking for: select it in the model
+ self.__syncInProgress = True
+ selectionModel.select(
+ index, qt.QItemSelectionModel.Clear |
+ qt.QItemSelectionModel.Select |
+ qt.QItemSelectionModel.Current)
+ self.__syncInProgress = False
+ break
+
+
+class SceneWidget(Plot3DWidget):
+ """Widget displaying data sets in 3D"""
+
+ def __init__(self, parent=None):
+ super(SceneWidget, self).__init__(parent)
+ self._model = None # Store lazy-loaded model
+ self._selection = None # Store lazy-loaded SceneSelection
+ self._items = []
+
+ self._textColor = 1., 1., 1., 1.
+ self._foregroundColor = 1., 1., 1., 1.
+ self._highlightColor = 0.7, 0.7, 0., 1.
+
+ self._sceneGroup = items.GroupWithAxesItem(parent=self)
+ self._sceneGroup.setLabel('Data')
+
+ self.viewport.scene.children.append(self._sceneGroup._getScenePrimitive())
+
+ def model(self):
+ """Returns the model corresponding the scene of this widget
+
+ :rtype: SceneModel
+ """
+ if self._model is None:
+ # Lazy-loading of the model
+ self._model = SceneModel(parent=self)
+ return self._model
+
+ def selection(self):
+ """Returns the object managing selection in the scene
+
+ :rtype: SceneSelection
+ """
+ if self._selection is None:
+ # Lazy-loading of the SceneSelection
+ self._selection = SceneSelection(parent=self)
+ return self._selection
+
+ def getSceneGroup(self):
+ """Returns the root group of the scene
+
+ :rtype: GroupItem
+ """
+ return self._sceneGroup
+
+ # Interactive modes
+
+ def _handleSelectionChanged(self, current, previous):
+ """Handle change of selection to update interactive mode"""
+ if self.getInteractiveMode() == 'panSelectedPlane':
+ if isinstance(current, items.PlaneMixIn):
+ # Update pan plane to use new selected plane
+ self.setInteractiveMode('panSelectedPlane')
+
+ else: # Switch to rotate scene if new selection is not a plane
+ self.setInteractiveMode('rotate')
+
+ def setInteractiveMode(self, mode):
+ """Set the interactive mode.
+
+ 'panSelectedPlane' mode set plane panning if a plane is selected,
+ otherwise it fall backs to 'rotate'.
+
+ :param str mode:
+ The interactive mode: 'rotate', 'pan', 'panSelectedPlane' or None
+ """
+ if self.getInteractiveMode() == 'panSelectedPlane':
+ self.selection().sigCurrentChanged.disconnect(
+ self._handleSelectionChanged)
+
+ if mode == 'panSelectedPlane':
+ selected = self.selection().getCurrentItem()
+
+ if isinstance(selected, items.PlaneMixIn):
+ mode = interaction.PanPlaneZoomOnWheelControl(
+ self.viewport,
+ selected._getPlane(),
+ mode='position',
+ orbitAroundCenter=False,
+ scaleTransform=self._sceneScale)
+
+ self.selection().sigCurrentChanged.connect(
+ self._handleSelectionChanged)
+
+ else: # No selected plane, fallback to rotate scene
+ mode = 'rotate'
+
+ super(SceneWidget, self).setInteractiveMode(mode)
+
+ def getInteractiveMode(self):
+ """Returns the interactive mode in use.
+
+ :rtype: str
+ """
+ if isinstance(self.eventHandler, interaction.PanPlaneZoomOnWheelControl):
+ return 'panSelectedPlane'
+ else:
+ return super(SceneWidget, self).getInteractiveMode()
+
+ # Add/remove items
+
+ def add3DScalarField(self, data, copy=True, index=None):
+ """Add 3D scalar data volume to :class:`SceneWidget` content.
+
+ Dataset order is zyx (i.e., first dimension is z).
+
+ :param data: 3D array
+ :type data: 3D numpy.ndarray of float32 with shape at least (2, 2, 2)
+ :param bool copy:
+ True (default) to make a copy,
+ False to avoid copy (DO NOT MODIFY data afterwards)
+ :param int index: The index at which to place the item.
+ By default it is appended to the end of the list.
+ :return: The newly created scalar volume item
+ :rtype: items.ScalarField3D
+ """
+ volume = items.ScalarField3D()
+ volume.setData(data, copy=copy)
+ self.addItem(volume, index)
+ return volume
+
+ def add3DScatter(self, x, y, z, value, copy=True, index=None):
+ """Add 3D scatter data to :class:`SceneWidget` content.
+
+ :param numpy.ndarray x: Array of X coordinates (single value not accepted)
+ :param y: Points Y coordinate (array-like or single value)
+ :param z: Points Z coordinate (array-like or single value)
+ :param value: Points values (array-like or single value)
+ :param bool copy:
+ True (default) to copy the data,
+ False to use provided data (do not modify!)
+ :param int index: The index at which to place the item.
+ By default it is appended to the end of the list.
+ :return: The newly created 3D scatter item
+ :rtype: items.Scatter3D
+ """
+ scatter3d = items.Scatter3D()
+ scatter3d.setData(x=x, y=y, z=z, value=value, copy=copy)
+ self.addItem(scatter3d, index)
+ return scatter3d
+
+ def add2DScatter(self, x, y, value, copy=True, index=None):
+ """Add 2D scatter data to :class:`SceneWidget` content.
+
+ Provided arrays must have the same length.
+
+ :param numpy.ndarray x: X coordinates (array-like)
+ :param numpy.ndarray y: Y coordinates (array-like)
+ :param value: Points value: array-like or single scalar
+ :param bool copy: True (default) to copy the data,
+ False to use as is (do not modify!).
+ :param int index: The index at which to place the item.
+ By default it is appended to the end of the list.
+ :return: The newly created 2D scatter item
+ :rtype: items.Scatter2D
+ """
+ scatter2d = items.Scatter2D()
+ scatter2d.setData(x=x, y=y, value=value, copy=copy)
+ self.addItem(scatter2d, index)
+ return scatter2d
+
+ def addImage(self, data, copy=True, index=None):
+ """Add a 2D data or RGB(A) image to :class:`SceneWidget` content.
+
+ 2D data is casted to float32.
+ RGBA supported formats are: float32 in [0, 1] and uint8.
+
+ :param numpy.ndarray data: Image as a 2D data array or
+ RGBA image as a 3D array (height, width, channels)
+ :param bool copy: True (default) to copy the data,
+ False to use as is (do not modify!).
+ :param int index: The index at which to place the item.
+ By default it is appended to the end of the list.
+ :return: The newly created image item
+ :rtype: items.ImageData or items.ImageRgba
+ :raise ValueError: For arrays of unsupported dimensions
+ """
+ data = numpy.array(data, copy=False)
+ if data.ndim == 2:
+ image = items.ImageData()
+ elif data.ndim == 3:
+ image = items.ImageRgba()
+ else:
+ raise ValueError("Unsupported array dimensions: %d" % data.ndim)
+ image.setData(data, copy=copy)
+ self.addItem(image, index)
+ return image
+
+ def addItem(self, item, index=None):
+ """Add an item to :class:`SceneWidget` content
+
+ :param Item3D item: The item to add
+ :param int index: The index at which to place the item.
+ By default it is appended to the end of the list.
+ :raise ValueError: If the item is already in the :class:`SceneWidget`.
+ """
+ return self.getSceneGroup().addItem(item, index)
+
+ def removeItem(self, item):
+ """Remove an item from :class:`SceneWidget` content.
+
+ :param Item3D item: The item to remove from the scene
+ :raises ValueError: If the item does not belong to the group
+ """
+ return self.getSceneGroup().removeItem(item)
+
+ def getItems(self):
+ """Returns the list of :class:`SceneWidget` items.
+
+ Only items in the top-level group are returned.
+
+ :rtype: tuple
+ """
+ return self.getSceneGroup().getItems()
+
+ def clearItems(self):
+ """Remove all item from :class:`SceneWidget`."""
+ return self.getSceneGroup().clear()
+
+ # Colors
+
+ def getTextColor(self):
+ """Return color used for text
+
+ :rtype: QColor"""
+ return qt.QColor.fromRgbF(*self._textColor)
+
+ def setTextColor(self, color):
+ """Set the text color.
+
+ :param color: RGB color: name, #RRGGBB or RGB values
+ :type color:
+ QColor, str or array-like of 3 or 4 float in [0., 1.] or uint8
+ """
+ color = rgba(color)
+ if color != self._textColor:
+ self._textColor = color
+
+ # Update text color
+ # TODO make entry point in Item3D for this
+ bbox = self._sceneGroup._getScenePrimitive()
+ bbox.tickColor = color
+
+ self.sigStyleChanged.emit('textColor')
+
+ def getForegroundColor(self):
+ """Return color used for bounding box
+
+ :rtype: QColor
+ """
+ return qt.QColor.fromRgbF(*self._foregroundColor)
+
+ def setForegroundColor(self, color):
+ """Set the foreground color.
+
+ :param color: RGB color: name, #RRGGBB or RGB values
+ :type color:
+ QColor, str or array-like of 3 or 4 float in [0., 1.] or uint8
+ """
+ color = rgba(color)
+ if color != self._foregroundColor:
+ self._foregroundColor = color
+
+ # Update scene items
+ selected = self.selection().getCurrentItem()
+ for item in self.getSceneGroup().visit(included=True):
+ if item is not selected:
+ item._setForegroundColor(color)
+
+ self.sigStyleChanged.emit('foregroundColor')
+
+ def getHighlightColor(self):
+ """Return color used for highlighted item bounding box
+
+ :rtype: QColor
+ """
+ return qt.QColor.fromRgbF(*self._highlightColor)
+
+ def setHighlightColor(self, color):
+ """Set highlighted item color.
+
+ :param color: RGB color: name, #RRGGBB or RGB values
+ :type color:
+ QColor, str or array-like of 3 or 4 float in [0., 1.] or uint8
+ """
+ color = rgba(color)
+ if color != self._highlightColor:
+ self._highlightColor = color
+
+ selected = self.selection().getCurrentItem()
+ if selected is not None:
+ selected._setForegroundColor(color)
+
+ self.sigStyleChanged.emit('highlightColor')
diff --git a/silx/gui/plot3d/SceneWindow.py b/silx/gui/plot3d/SceneWindow.py
new file mode 100644
index 0000000..5121a17
--- /dev/null
+++ b/silx/gui/plot3d/SceneWindow.py
@@ -0,0 +1,192 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module provides a QMainWindow with a 3D SceneWidget and toolbars.
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "29/11/2017"
+
+
+from ...gui import qt, icons
+
+from .actions.mode import InteractiveModeAction
+from .SceneWidget import SceneWidget
+from .tools import OutputToolBar, InteractiveModeToolBar, ViewpointToolBar
+from .tools.GroupPropertiesWidget import GroupPropertiesWidget
+
+from .ParamTreeView import ParamTreeView
+
+# Imported here for convenience
+from . import items # noqa
+
+
+__all__ = ['items', 'SceneWidget', 'SceneWindow']
+
+
+class _PanPlaneAction(InteractiveModeAction):
+ """QAction to set plane pan interaction on a Plot3DWidget
+
+ :param parent: See :class:`QAction`
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
+ """
+ def __init__(self, parent, plot3d=None):
+ super(_PanPlaneAction, self).__init__(
+ parent, 'panSelectedPlane', plot3d)
+ self.setIcon(icons.getQIcon('3d-plane-pan'))
+ self.setText('Pan plane')
+ self.setCheckable(True)
+ self.setToolTip(
+ 'Pan selected plane. Press <b>Ctrl</b> to rotate the scene.')
+
+ def _planeChanged(self, event):
+ """Handle plane updates"""
+ if event in (items.ItemChangedType.VISIBLE,
+ items.ItemChangedType.POSITION):
+ plane = self.sender()
+
+ isPlaneInteractive = \
+ plane._getPlane().plane.isPlane and plane.isVisible()
+
+ if isPlaneInteractive != self.isEnabled():
+ self.setEnabled(isPlaneInteractive)
+ mode = 'panSelectedPlane' if isPlaneInteractive else 'rotate'
+ self.getPlot3DWidget().setInteractiveMode(mode)
+
+ def _selectionChanged(self, current, previous):
+ """Handle selected object change"""
+ if isinstance(previous, items.PlaneMixIn):
+ previous.sigItemChanged.disconnect(self._planeChanged)
+
+ if isinstance(current, items.PlaneMixIn):
+ current.sigItemChanged.connect(self._planeChanged)
+ self.setEnabled(True)
+ self.getPlot3DWidget().setInteractiveMode('panSelectedPlane')
+ else:
+ self.setEnabled(False)
+
+ def setPlot3DWidget(self, widget):
+ previous = self.getPlot3DWidget()
+ if isinstance(previous, SceneWidget):
+ previous.selection().sigCurrentChanged.disconnect(
+ self._selectionChanged)
+ self._selectionChanged(
+ None, previous.selection().getCurrentItem())
+
+ super(_PanPlaneAction, self).setPlot3DWidget(widget)
+
+ if isinstance(widget, SceneWidget):
+ self._selectionChanged(widget.selection().getCurrentItem(), None)
+ widget.selection().sigCurrentChanged.connect(
+ self._selectionChanged)
+
+
+class SceneWindow(qt.QMainWindow):
+ """OpenGL 3D scene widget with toolbars."""
+
+ def __init__(self, parent=None):
+ super(SceneWindow, self).__init__(parent)
+ if parent is not None:
+ # behave as a widget
+ self.setWindowFlags(qt.Qt.Widget)
+
+ self._sceneWidget = SceneWidget()
+ self.setCentralWidget(self._sceneWidget)
+
+ self._interactiveModeToolBar = InteractiveModeToolBar(parent=self)
+ panPlaneAction = _PanPlaneAction(self, plot3d=self._sceneWidget)
+ self._interactiveModeToolBar.addAction(panPlaneAction)
+
+ self._viewpointToolBar = ViewpointToolBar(parent=self)
+ self._outputToolBar = OutputToolBar(parent=self)
+
+ for toolbar in (self._interactiveModeToolBar,
+ self._viewpointToolBar,
+ self._outputToolBar):
+ toolbar.setPlot3DWidget(self._sceneWidget)
+ self.addToolBar(toolbar)
+ self.addActions(toolbar.actions())
+
+ self._paramTreeView = ParamTreeView()
+ self._paramTreeView.setModel(self._sceneWidget.model())
+
+ selectionModel = self._paramTreeView.selectionModel()
+ self._sceneWidget.selection()._setSyncSelectionModel(
+ selectionModel)
+
+ paramDock = qt.QDockWidget()
+ paramDock.setWindowTitle('Object parameters')
+ paramDock.setWidget(self._paramTreeView)
+ self.addDockWidget(qt.Qt.RightDockWidgetArea, paramDock)
+
+ self._sceneGroupResetWidget = GroupPropertiesWidget()
+ self._sceneGroupResetWidget.setGroup(
+ self._sceneWidget.getSceneGroup())
+
+ resetDock = qt.QDockWidget()
+ resetDock.setWindowTitle('Global parameters')
+ resetDock.setWidget(self._sceneGroupResetWidget)
+ self.addDockWidget(qt.Qt.RightDockWidgetArea, resetDock)
+ self.tabifyDockWidget(paramDock, resetDock)
+
+ paramDock.raise_()
+
+ def getSceneWidget(self):
+ """Returns the SceneWidget of this window.
+
+ :rtype: ~silx.gui.plot3d.SceneWidget.SceneWidget
+ """
+ return self._sceneWidget
+
+ def getParamTreeView(self):
+ """Returns the :class:`ParamTreeView` of this window.
+
+ :rtype: ParamTreeView
+ """
+ return self._paramTreeView
+
+ def getInteractiveModeToolBar(self):
+ """Returns the interactive mode toolbar.
+
+ :rtype: InteractiveModeToolBar
+ """
+ return self._interactiveModeToolBar
+
+ def getViewpointToolBar(self):
+ """Returns the viewpoint toolbar.
+
+ :rtype: ViewpointToolBar
+ """
+ return self._viewpointToolBar
+
+ def getOutputToolBar(self):
+ """Returns the output toolbar.
+
+ :rtype: OutputToolBar
+ """
+ return self._outputToolBar
diff --git a/silx/third_party/_local/__init__.py b/silx/gui/plot3d/_model/__init__.py
index 03973e5..4b16e32 100644
--- a/silx/third_party/_local/__init__.py
+++ b/silx/gui/plot3d/_model/__init__.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2016 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,14 +23,13 @@
#
# ###########################################################################*/
"""
-Package containing external modules which can be available as it is as an
-external python library.
+This package provides :class:`SceneWidget` content and parameters model.
+"""
-They are stored here to reduce python library dependancies.
+from __future__ import absolute_import
-This package can be removed if all dependancies are available in the target
-system as python libraries.
-"""
-__authors__ = ["Valentin Valls"]
+__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "26/04/2017"
+__date__ = "11/01/2018"
+
+from .model import SceneModel, visitQAbstractItemModel # noqa
diff --git a/silx/gui/plot3d/_model/core.py b/silx/gui/plot3d/_model/core.py
new file mode 100644
index 0000000..e8e0820
--- /dev/null
+++ b/silx/gui/plot3d/_model/core.py
@@ -0,0 +1,372 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This module provides base classes to implement models for 3D scene content.
+"""
+
+from __future__ import absolute_import, division
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "11/01/2018"
+
+
+import collections
+import weakref
+
+from ....utils.weakref import WeakMethodProxy
+from ... import qt
+
+
+class BaseRow(qt.QObject):
+ """Base class for rows of the tree model.
+
+ The root node parent MUST be set to the QAbstractItemModel it belongs to.
+ By default item is enabled.
+
+ :param children: Iterable of BaseRow to start with (not signaled)
+ """
+
+ def __init__(self, children=()):
+ self.__modelRef = None
+ self.__parentRef = None
+ super(BaseRow, self).__init__()
+ self.__children = []
+ for row in children:
+ assert isinstance(row, BaseRow)
+ row.setParent(self)
+ self.__children.append(row)
+ self.__flags = collections.defaultdict(lambda: qt.Qt.ItemIsEnabled)
+ self.__tooltip = None
+
+ def setParent(self, parent):
+ """Override :meth:`QObject.setParent` to cache model and parent"""
+ self.__parentRef = None if parent is None else weakref.ref(parent)
+
+ if isinstance(parent, qt.QAbstractItemModel):
+ model = parent
+ elif isinstance(parent, BaseRow):
+ model = parent.model()
+ else:
+ model = None
+
+ self._updateModel(model)
+
+ super(BaseRow, self).setParent(parent)
+
+ def parent(self):
+ """Override :meth:`QObject.setParent` to use cached parent
+
+ :rtype: Union[QObject, None]"""
+ return self.__parentRef() if self.__parentRef is not None else None
+
+ def _updateModel(self, model):
+ """Update the model this row belongs to"""
+ if model != self.model():
+ self.__modelRef = weakref.ref(model) if model is not None else None
+ for child in self.children():
+ child._updateModel(model)
+
+ def model(self):
+ """Return the model this node belongs to or None if not in a model.
+
+ :rtype: Union[QAbstractItemModel, None]
+ """
+ return self.__modelRef() if self.__modelRef is not None else None
+
+ def index(self, column=0):
+ """Return corresponding index in the model or None if not in a model.
+
+ :param int column: The column to make the index for
+ :rtype: Union[QModelIndex, None]
+ """
+ parent = self.parent()
+ model = self.model()
+
+ if model is None: # Not in a model
+ return None
+ elif parent is model: # Root node
+ return qt.QModelIndex()
+ else:
+ index = parent.index()
+ row = parent.children().index(self)
+ return model.index(row, column, index)
+
+ def columnCount(self):
+ """Returns number of columns (default: 2)
+
+ :rtype: int
+ """
+ return 2
+
+ def children(self):
+ """Returns the list of children nodes
+
+ :rtype: tuple of Node
+ """
+ return tuple(self.__children)
+
+ def rowCount(self):
+ """Returns number of rows
+
+ :rtype: int
+ """
+ return len(self.__children)
+
+ def addRow(self, row, index=None):
+ """Add a node to the children
+
+ :param BaseRow row: The node to add
+ :param int index: The index at which to insert it or
+ None to append
+ """
+ if index is None:
+ index = self.rowCount()
+ assert index <= self.rowCount()
+
+ model = self.model()
+
+ if model is not None:
+ parent = self.index()
+ model.beginInsertRows(parent, index, index)
+
+ self.__children.insert(index, row)
+ row.setParent(self)
+
+ if model is not None:
+ model.endInsertRows()
+
+ def removeRow(self, row):
+ """Remove a row from the children list.
+
+ It removes either a node or a row index.
+
+ :param row: BaseRow object or index of row to remove
+ :type row: Union[BaseRow, int]
+ """
+ if isinstance(row, BaseRow):
+ row = self.__children.index(row)
+ else:
+ row = int(row)
+ assert row < self.rowCount()
+
+ model = self.model()
+
+ if model is not None:
+ index = self.index()
+ model.beginRemoveRows(index, row, row)
+
+ node = self.__children.pop(row)
+ node.setParent(None)
+
+ if model is not None:
+ model.endRemoveRows()
+
+ def data(self, column, role):
+ """Returns data for given column and role
+
+ :param int column: Column index for this row
+ :param int role: The role to get
+ :return: Corresponding data (Default: None)
+ """
+ if role == qt.Qt.ToolTipRole and self.__tooltip is not None:
+ return self.__tooltip
+ else:
+ return None
+
+ def setData(self, column, value, role):
+ """Set data for given column and role
+
+ :param int column: Column index for this row
+ :param value: The data to set
+ :param int role: The role to set
+ :return: True on success, False on failure
+ :rtype: bool
+ """
+ return False
+
+ def setToolTip(self, tooltip):
+ """Set the tooltip of the whole row.
+
+ If None there is no tooltip.
+
+ :param Union[str, None] tooltip:
+ """
+ self.__tooltip = tooltip
+
+ def setFlags(self, flags, column=None):
+ """Set the static flags to return.
+
+ Default is ItemIsEnabled for all columns.
+
+ :param int column: The column for which to set the flags
+ :param flags: Item flags
+ """
+ if column is None:
+ self.__flags = collections.defaultdict(lambda: flags)
+ else:
+ self.__flags[column] = flags
+
+ def flags(self, column):
+ """Returns flags for given column
+
+ :rtype: int
+ """
+ return self.__flags[column]
+
+
+class StaticRow(BaseRow):
+ """Row with static data.
+
+ :param tuple display: List of data for DisplayRole for each column
+ :param dict roles: Optional mapping of roles to list of data.
+ :param children: Iterable of BaseRow to start with (not signaled)
+ """
+
+ def __init__(self, display=('', None), roles=None, children=()):
+ super(StaticRow, self).__init__(children)
+ self._dataByRoles = {} if roles is None else roles
+ self._dataByRoles[qt.Qt.DisplayRole] = display
+
+ def data(self, column, role):
+ if role in self._dataByRoles:
+ data = self._dataByRoles[role]
+ if column < len(data):
+ return data[column]
+ return super(StaticRow, self).data(column, role)
+
+ def columnCount(self):
+ return len(self._dataByRoles[qt.Qt.DisplayRole])
+
+
+class ProxyRow(BaseRow):
+ """Provides a node to proxy a data accessible through functions.
+
+ Warning: Only weak reference are kept on fget and fset.
+
+ :param str name: The name of this node
+ :param callable fget: A callable returning the data
+ :param callable fset:
+ An optional callable setting the data with data as a single argument.
+ :param notify:
+ An optional signal emitted when data has changed.
+ :param callable toModelData:
+ An optional callable to convert from fget
+ callable to data returned by the model.
+ :param callable fromModelData:
+ An optional callable converting data provided to the model to
+ data for fset.
+ :param editorHint: Data to provide as UserRole for editor selection/setup
+ """
+
+ def __init__(self,
+ name='',
+ fget=None,
+ fset=None,
+ notify=None,
+ toModelData=None,
+ fromModelData=None,
+ editorHint=None):
+
+ super(ProxyRow, self).__init__()
+ self.__name = name
+ self.__editorHint = editorHint
+
+ assert fget is not None
+ self._fget = WeakMethodProxy(fget)
+ self._fset = WeakMethodProxy(fset) if fset is not None else None
+ if fset is not None:
+ self.setFlags(qt.Qt.ItemIsEnabled | qt.Qt.ItemIsEditable, 1)
+ self._toModelData = toModelData
+ self._fromModelData = fromModelData
+
+ if notify is not None:
+ notify.connect(self._notified) # TODO support sigItemChanged flags
+
+ def _notified(self, *args, **kwargs):
+ """Send update to the model upon signal notifications"""
+ index = self.index(column=1)
+ model = self.model()
+ if model is not None:
+ model.dataChanged.emit(index, index)
+
+ def data(self, column, role):
+ if column == 0:
+ if role == qt.Qt.DisplayRole:
+ return self.__name
+
+ elif column == 1:
+ if role == qt.Qt.UserRole: # EditorHint
+ return self.__editorHint
+ elif role == qt.Qt.DisplayRole or (role == qt.Qt.EditRole and
+ self._fset is not None):
+ data = self._fget()
+ if self._toModelData is not None:
+ data = self._toModelData(data)
+ return data
+
+ return super(ProxyRow, self).data(column, role)
+
+ def setData(self, column, value, role):
+ if role == qt.Qt.EditRole and self._fset is not None:
+ if self._fromModelData is not None:
+ value = self._fromModelData(value)
+ self._fset(value)
+ return True
+
+ return super(ProxyRow, self).setData(column, value, role)
+
+
+class ColorProxyRow(ProxyRow):
+ """Provides a proxy to a QColor property.
+
+ The color is returned through the decorative role.
+
+ See :class:`ProxyRow`
+ """
+
+ def data(self, column, role):
+ if column == 1: # Show color as decoration, not text
+ if role == qt.Qt.DisplayRole:
+ return None
+ if role == qt.Qt.DecorationRole:
+ role = qt.Qt.DisplayRole
+ return super(ColorProxyRow, self).data(column, role)
+
+
+class AngleDegreeRow(ProxyRow):
+ """ProxyRow patching display of column 1 to add degree symbol
+
+ See :class:`ProxyRow`
+ """
+
+ def __init__(self, *args, **kwargs):
+ super(AngleDegreeRow, self).__init__(*args, **kwargs)
+
+ def data(self, column, role):
+ if column == 1 and role == qt.Qt.DisplayRole:
+ return u'%g°' % super(AngleDegreeRow, self).data(column, role)
+ else:
+ return super(AngleDegreeRow, self).data(column, role)
diff --git a/silx/gui/plot3d/_model/items.py b/silx/gui/plot3d/_model/items.py
new file mode 100644
index 0000000..7009ea1
--- /dev/null
+++ b/silx/gui/plot3d/_model/items.py
@@ -0,0 +1,1388 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This module provides base classes to implement models for 3D scene content
+"""
+
+from __future__ import absolute_import, division
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "11/01/2018"
+
+
+import functools
+import weakref
+
+import numpy
+
+from silx.third_party import six
+
+from ..._utils import convertArrayToQImage
+from ...plot.Colormap import preferredColormaps
+from ... import qt, icons
+from .. import items
+from ..items.volume import Isosurface, CutPlane
+
+
+from .core import AngleDegreeRow, BaseRow, ColorProxyRow, ProxyRow, StaticRow
+
+
+class _DirectionalLightProxy(qt.QObject):
+ """Proxy to handle directional light with angles rather than vector.
+ """
+
+ sigAzimuthAngleChanged = qt.Signal()
+ """Signal sent when the azimuth angle has changed."""
+
+ sigAltitudeAngleChanged = qt.Signal()
+ """Signal sent when altitude angle has changed."""
+
+ def __init__(self, light):
+ super(_DirectionalLightProxy, self).__init__()
+ self._light = light
+ light.addListener(self._directionUpdated)
+ self._azimuth = 0.
+ self._altitude = 0.
+
+ def getAzimuthAngle(self):
+ """Returns the signed angle in the horizontal plane.
+
+ Unit: degrees.
+ The 0 angle corresponds to the axis perpendicular to the screen.
+
+ :rtype: float
+ """
+ return self._azimuth
+
+ def getAltitudeAngle(self):
+ """Returns the signed vertical angle from the horizontal plane.
+
+ Unit: degrees.
+ Range: [-90, +90]
+
+ :rtype: float
+ """
+ return self._altitude
+
+ def setAzimuthAngle(self, angle):
+ """Set the horizontal angle.
+
+ :param float angle: Angle from -z axis in zx plane in degrees.
+ """
+ if angle != self._azimuth:
+ self._azimuth = angle
+ self._updateLight()
+ self.sigAzimuthAngleChanged.emit()
+
+ def setAltitudeAngle(self, angle):
+ """Set the horizontal angle.
+
+ :param float angle: Angle from -z axis in zy plane in degrees.
+ """
+ if angle != self._altitude:
+ self._altitude = angle
+ self._updateLight()
+ self.sigAltitudeAngleChanged.emit()
+
+ def _directionUpdated(self, *args, **kwargs):
+ """Handle light direction update in the scene"""
+ # Invert direction to manipulate the 'source' pointing to
+ # the center of the viewport
+ x, y, z = - self._light.direction
+
+ # Horizontal plane is plane xz
+ azimuth = numpy.degrees(numpy.arctan2(x, z))
+ altitude = numpy.degrees(numpy.pi/2. - numpy.arccos(y))
+
+ if (abs(azimuth - self.getAzimuthAngle()) > 0.01 and
+ abs(abs(altitude) - 90.) >= 0.001): # Do not update when at zenith
+ self.setAzimuthAngle(azimuth)
+
+ if abs(altitude - self.getAltitudeAngle()) > 0.01:
+ self.setAltitudeAngle(altitude)
+
+ def _updateLight(self):
+ """Update light direction in the scene"""
+ azimuth = numpy.radians(self._azimuth)
+ delta = numpy.pi/2. - numpy.radians(self._altitude)
+ z = - numpy.sin(delta) * numpy.cos(azimuth)
+ x = - numpy.sin(delta) * numpy.sin(azimuth)
+ y = - numpy.cos(delta)
+ self._light.direction = x, y, z
+
+
+class Settings(StaticRow):
+ """Subtree for :class:`SceneWidget` style parameters.
+
+ :param SceneWidget sceneWidget: The widget to control
+ """
+
+ def __init__(self, sceneWidget):
+ background = ColorProxyRow(
+ name='Background',
+ fget=sceneWidget.getBackgroundColor,
+ fset=sceneWidget.setBackgroundColor,
+ notify=sceneWidget.sigStyleChanged)
+
+ foreground = ColorProxyRow(
+ name='Foreground',
+ fget=sceneWidget.getForegroundColor,
+ fset=sceneWidget.setForegroundColor,
+ notify=sceneWidget.sigStyleChanged)
+
+ text = ColorProxyRow(
+ name='Text',
+ fget=sceneWidget.getTextColor,
+ fset=sceneWidget.setTextColor,
+ notify=sceneWidget.sigStyleChanged)
+
+ highlight = ColorProxyRow(
+ name='Highlight',
+ fget=sceneWidget.getHighlightColor,
+ fset=sceneWidget.setHighlightColor,
+ notify=sceneWidget.sigStyleChanged)
+
+ axesIndicator = ProxyRow(
+ name='Axes Indicator',
+ fget=sceneWidget.isOrientationIndicatorVisible,
+ fset=sceneWidget.setOrientationIndicatorVisible,
+ notify=sceneWidget.sigStyleChanged)
+
+ # Light direction
+
+ self._lightProxy = _DirectionalLightProxy(sceneWidget.viewport.light)
+
+ azimuthNode = ProxyRow(
+ name='Azimuth',
+ fget=self._lightProxy.getAzimuthAngle,
+ fset=self._lightProxy.setAzimuthAngle,
+ notify=self._lightProxy.sigAzimuthAngleChanged,
+ editorHint=(-90, 90))
+
+ altitudeNode = ProxyRow(
+ name='Altitude',
+ fget=self._lightProxy.getAltitudeAngle,
+ fset=self._lightProxy.setAltitudeAngle,
+ notify=self._lightProxy.sigAltitudeAngleChanged,
+ editorHint=(-90, 90))
+
+ lightDirection = StaticRow(('Light Direction', None),
+ children=(azimuthNode, altitudeNode))
+
+ # Settings row
+ children = (background, foreground, text, highlight,
+ axesIndicator, lightDirection)
+ super(Settings, self).__init__(('Settings', None), children=children)
+
+
+class Item3DRow(StaticRow):
+ """Represents an :class:`Item3D` with checkable visibility
+
+ :param Item3D item: The scene item to represent.
+ :param str name: The optional name of the item
+ """
+
+ def __init__(self, item, name=None):
+ if name is None:
+ name = item.getLabel()
+ super(Item3DRow, self).__init__((name, None))
+
+ self.setFlags(
+ self.flags(0) | qt.Qt.ItemIsUserCheckable | qt.Qt.ItemIsSelectable,
+ 0)
+ self.setFlags(self.flags(1) | qt.Qt.ItemIsSelectable, 1)
+
+ self._item = weakref.ref(item)
+ item.sigItemChanged.connect(self._itemChanged)
+
+ def _itemChanged(self, event):
+ """Handle visibility change"""
+ if event == items.ItemChangedType.VISIBLE:
+ model = self.model()
+ if model is not None:
+ index = self.index(column=1)
+ model.dataChanged.emit(index, index)
+
+ def item(self):
+ """Returns the :class:`Item3D` item or None"""
+ return self._item()
+
+ def data(self, column, role):
+ if column == 0 and role == qt.Qt.CheckStateRole:
+ item = self.item()
+ if item is not None and item.isVisible():
+ return qt.Qt.Checked
+ else:
+ return qt.Qt.Unchecked
+ elif column == 0 and role == qt.Qt.DecorationRole:
+ return icons.getQIcon('item-3dim')
+ else:
+ return super(Item3DRow, self).data(column, role)
+
+ def setData(self, column, value, role):
+ if column == 0 and role == qt.Qt.CheckStateRole:
+ item = self.item()
+ if item is not None:
+ item.setVisible(value == qt.Qt.Checked)
+ return True
+ else:
+ return False
+ return super(Item3DRow, self).setData(column, value, role)
+
+
+class DataItem3DBoundingBoxRow(ProxyRow):
+ """Represents :class:`DataItem3D` bounding box visibility
+
+ :param DataItem3D item: The item for which to display/control bounding box
+ """
+
+ def __init__(self, item):
+ super(DataItem3DBoundingBoxRow, self).__init__(
+ name='Bounding box',
+ fget=item.isBoundingBoxVisible,
+ fset=item.setBoundingBoxVisible,
+ notify=item.sigItemChanged)
+
+
+class MatrixProxyRow(ProxyRow):
+ """Proxy for a row of a DataItem3D 3x3 matrix transform
+
+ :param DataItem3D item:
+ :param int index: Matrix row index
+ """
+
+ def __init__(self, item, index):
+ self._item = weakref.ref(item)
+ self._index = index
+
+ super(MatrixProxyRow, self).__init__(
+ name='',
+ fget=self._getMatrixRow,
+ fset=self._setMatrixRow,
+ notify=item.sigItemChanged)
+
+ def _getMatrixRow(self):
+ """Returns the matrix row.
+
+ :rtype: QVector3D
+ """
+ item = self._item()
+ if item is not None:
+ matrix = item.getMatrix()
+ return qt.QVector3D(*matrix[self._index, :])
+ else:
+ return None
+
+ def _setMatrixRow(self, row):
+ """Set the row of the matrix
+
+ :param QVector3D row: Row values to set
+ """
+ item = self._item()
+ if item is not None:
+ matrix = item.getMatrix()
+ matrix[self._index, :] = row.x(), row.y(), row.z()
+ item.setMatrix(matrix)
+
+ def data(self, column, role):
+ data = super(MatrixProxyRow, self).data(column, role)
+
+ if column == 1 and role == qt.Qt.DisplayRole:
+ # Convert QVector3D to text
+ data = "%g; %g; %g" % (data.x(), data.y(), data.z())
+
+ return data
+
+
+class DataItem3DTransformRow(StaticRow):
+ """Represents :class:`DataItem3D` transform parameters
+
+ :param DataItem3D item: The item for which to display/control transform
+ """
+
+ _ROTATION_CENTER_OPTIONS = 'Origin', 'Lower', 'Center', 'Upper'
+
+ def __init__(self, item):
+ super(DataItem3DTransformRow, self).__init__(('Transform', None))
+ self._item = weakref.ref(item)
+
+ translation = ProxyRow(name='Translation',
+ fget=item.getTranslation,
+ fset=self._setTranslation,
+ notify=item.sigItemChanged,
+ toModelData=lambda data: qt.QVector3D(*data))
+ self.addRow(translation)
+
+ # Here to keep a reference
+ self._xSetCenter = functools.partial(self._setCenter, index=0)
+ self._ySetCenter = functools.partial(self._setCenter, index=1)
+ self._zSetCenter = functools.partial(self._setCenter, index=2)
+
+ rotateCenter = StaticRow(
+ ('Center', None),
+ children=(
+ ProxyRow(name='X axis',
+ fget=item.getRotationCenter,
+ fset=self._xSetCenter,
+ notify=item.sigItemChanged,
+ toModelData=functools.partial(
+ self._centerToModelData, index=0),
+ editorHint=self._ROTATION_CENTER_OPTIONS),
+ ProxyRow(name='Y axis',
+ fget=item.getRotationCenter,
+ fset=self._ySetCenter,
+ notify=item.sigItemChanged,
+ toModelData=functools.partial(
+ self._centerToModelData, index=1),
+ editorHint=self._ROTATION_CENTER_OPTIONS),
+ ProxyRow(name='Z axis',
+ fget=item.getRotationCenter,
+ fset=self._zSetCenter,
+ notify=item.sigItemChanged,
+ toModelData=functools.partial(
+ self._centerToModelData, index=2),
+ editorHint=self._ROTATION_CENTER_OPTIONS),
+ ))
+
+ rotate = StaticRow(
+ ('Rotation', None),
+ children=(
+ AngleDegreeRow(name='Angle',
+ fget=item.getRotation,
+ fset=self._setAngle,
+ notify=item.sigItemChanged,
+ toModelData=lambda data: data[0]),
+ ProxyRow(name='Axis',
+ fget=item.getRotation,
+ fset=self._setAxis,
+ notify=item.sigItemChanged,
+ toModelData=lambda data: qt.QVector3D(*data[1])),
+ rotateCenter
+ ))
+ self.addRow(rotate)
+
+ scale = ProxyRow(name='Scale',
+ fget=item.getScale,
+ fset=self._setScale,
+ notify=item.sigItemChanged,
+ toModelData=lambda data: qt.QVector3D(*data))
+ self.addRow(scale)
+
+ matrix = StaticRow(
+ ('Matrix', None),
+ children=(MatrixProxyRow(item, 0),
+ MatrixProxyRow(item, 1),
+ MatrixProxyRow(item, 2)))
+ self.addRow(matrix)
+
+ def item(self):
+ """Returns the :class:`Item3D` item or None"""
+ return self._item()
+
+ @staticmethod
+ def _centerToModelData(center, index):
+ """Convert rotation center information from scene to model.
+
+ :param center: The center info from the scene
+ :param int index: dimension to convert
+ """
+ value = center[index]
+ if isinstance(value, six.string_types):
+ return value.title()
+ elif value == 0.:
+ return 'Origin'
+ else:
+ return six.text_type(value)
+
+ def _setCenter(self, value, index):
+ """Set one dimension of the rotation center.
+
+ :param value: Value received through the model.
+ :param int index: dimension to set
+ """
+ item = self.item()
+ if item is not None:
+ if value == 'Origin':
+ value = 0.
+ elif value not in self._ROTATION_CENTER_OPTIONS:
+ value = float(value)
+ else:
+ value = value.lower()
+
+ center = list(item.getRotationCenter())
+ center[index] = value
+ item.setRotationCenter(*center)
+
+ def _setAngle(self, angle):
+ """Set rotation angle.
+
+ :param float angle:
+ """
+ item = self.item()
+ if item is not None:
+ _, axis = item.getRotation()
+ item.setRotation(angle, axis)
+
+ def _setAxis(self, axis):
+ """Set rotation axis.
+
+ :param QVector3D axis:
+ """
+ item = self.item()
+ if item is not None:
+ angle, _ = item.getRotation()
+ item.setRotation(angle, (axis.x(), axis.y(), axis.z()))
+
+ def _setTranslation(self, translation):
+ """Set translation transform.
+
+ :param QVector3D translation:
+ """
+ item = self.item()
+ if item is not None:
+ item.setTranslation(translation.x(), translation.y(), translation.z())
+
+ def _setScale(self, scale):
+ """Set scale transform.
+
+ :param QVector3D scale:
+ """
+ item = self.item()
+ if item is not None:
+ item.setScale(scale.x(), scale.y(), scale.z())
+
+
+class GroupItemRow(Item3DRow):
+ """Represents a :class:`GroupItem` with transforms and children
+
+ :param GroupItem item: The scene group to represent.
+ :param str name: The optional name of the group
+ """
+
+ _CHILDREN_ROW_OFFSET = 2
+ """Number of rows for group parameters. Children are added after"""
+
+ def __init__(self, item, name=None):
+ super(GroupItemRow, self).__init__(item, name)
+ self.addRow(DataItem3DBoundingBoxRow(item))
+ self.addRow(DataItem3DTransformRow(item))
+
+ item.sigItemAdded.connect(self._itemAdded)
+ item.sigItemRemoved.connect(self._itemRemoved)
+
+ for child in item.getItems():
+ self.addRow(nodeFromItem(child))
+
+ def _itemAdded(self, item):
+ """Handle item addition to the group and add it to the model.
+
+ :param Item3D item: added item
+ """
+ group = self.item()
+ if group is None:
+ return
+
+ row = group.getItems().index(item)
+ self.addRow(nodeFromItem(item), row + self._CHILDREN_ROW_OFFSET)
+
+ def _itemRemoved(self, item):
+ """Handle item removal from the group and remove it from the model.
+
+ :param Item3D item: removed item
+ """
+ group = self.item()
+ if group is None:
+ return
+
+ # Find item
+ for row in self.children():
+ if row.item() is item:
+ self.removeRow(row)
+ break # Got it
+ else:
+ raise RuntimeError("Model does not correspond to scene content")
+
+
+class InterpolationRow(ProxyRow):
+ """Represents :class:`InterpolationMixIn` property.
+
+ :param Item3D item: Scene item with interpolation property
+ """
+
+ def __init__(self, item):
+ modes = [mode.title() for mode in item.INTERPOLATION_MODES]
+ super(InterpolationRow, self).__init__(
+ name='Interpolation',
+ fget=item.getInterpolation,
+ fset=item.setInterpolation,
+ notify=item.sigItemChanged,
+ toModelData=lambda mode: mode.title(),
+ fromModelData=lambda mode: mode.lower(),
+ editorHint=modes)
+
+
+class _ColormapBaseProxyRow(ProxyRow):
+ """Base class for colormap model row
+
+ This class handle synchronization and signals from the item and the colormap
+ """
+
+ _sigColormapChanged = qt.Signal()
+ """Signal used internally to notify colormap (or data) update"""
+
+ def __init__(self, item, *args, **kwargs):
+ self._dataRange = None
+ self._item = weakref.ref(item)
+ self._colormap = item.getColormap()
+
+ ProxyRow.__init__(self, *args, **kwargs)
+
+ self._colormap.sigChanged.connect(self._colormapChanged)
+ item.sigItemChanged.connect(self._itemChanged)
+ self._sigColormapChanged.connect(self._modelUpdated)
+
+ def item(self):
+ """Returns the :class:`ColormapMixIn` item or None"""
+ return self._item()
+
+ def _getColormapRange(self):
+ """Returns the range of the colormap for the current data.
+
+ :return: Colormap range (min, max)
+ """
+ if self._dataRange is None:
+ item = self.item()
+ if item is not None and self._colormap is not None:
+ if hasattr(item, 'getDataRange'):
+ data = item.getDataRange()
+ else:
+ data = item.getData(copy=False)
+
+ self._dataRange = self._colormap.getColormapRange(data)
+
+ else: # Fallback
+ self._dataRange = 1, 100
+ return self._dataRange
+
+ def _modelUpdated(self, *args, **kwargs):
+ """Emit dataChanged in the model"""
+ topLeft = self.index(column=0)
+ bottomRight = self.index(column=1)
+ model = self.model()
+ if model is not None:
+ model.dataChanged.emit(topLeft, bottomRight)
+
+ def _colormapChanged(self):
+ self._sigColormapChanged.emit()
+
+ def _itemChanged(self, event):
+ """Handle change of colormap or data in the item.
+
+ :param ItemChangedType event:
+ """
+ if event == items.ItemChangedType.COLORMAP:
+ self._sigColormapChanged.emit()
+ if self._colormap is not None:
+ self._colormap.sigChanged.disconnect(self._colormapChanged)
+
+ item = self.item()
+ if item is not None:
+ self._colormap = item.getColormap()
+ self._colormap.sigChanged.connect(self._colormapChanged)
+ else:
+ self._colormap = None
+
+ elif event == items.ItemChangedType.DATA:
+ self._dataRange = None
+ self._sigColormapChanged.emit()
+
+
+class _ColormapBoundRow(_ColormapBaseProxyRow):
+ """ProxyRow for colormap min or max
+
+ :param ColormapMixIn item: The item to handle
+ :param str name: Name of the raw
+ :param int index: 0 for Min and 1 of Max
+ """
+
+ def __init__(self, item, name, index):
+ self._index = index
+ _ColormapBaseProxyRow.__init__(
+ self,
+ item,
+ name=name,
+ fget=self._getBound,
+ fset=self._setBound)
+
+ self.setToolTip('Colormap %s bound:\n'
+ 'Check to set bound manually, '
+ 'uncheck for autoscale' % name.lower())
+
+ def _getRawBound(self):
+ """Proxy to get raw colormap bound
+
+ :rtype: float or None
+ """
+ if self._colormap is None:
+ return None
+ elif self._index == 0:
+ return self._colormap.getVMin()
+ else: # self._index == 1
+ return self._colormap.getVMax()
+
+ def _getBound(self):
+ """Proxy to get colormap effective bound value
+
+ :rtype: float
+ """
+ if self._colormap is not None:
+ bound = self._getRawBound()
+
+ if bound is None:
+ bound = self._getColormapRange()[self._index]
+ return bound
+ else:
+ return 1. # Fallback
+
+ def _setBound(self, value):
+ """Proxy to set colormap bound.
+
+ :param float value:
+ """
+ if self._colormap is not None:
+ if self._index == 0:
+ min_ = value
+ max_ = self._colormap.getVMax()
+ else: # self._index == 1
+ min_ = self._colormap.getVMin()
+ max_ = value
+
+ if max_ is not None and min_ is not None and min_ > max_:
+ min_, max_ = max_, min_
+ self._colormap.setVRange(min_, max_)
+
+ def flags(self, column):
+ if column == 0:
+ return qt.Qt.ItemIsEnabled | qt.Qt.ItemIsUserCheckable
+
+ elif column == 1:
+ if self._getRawBound() is not None:
+ flags = qt.Qt.ItemIsEditable | qt.Qt.ItemIsEnabled
+ else:
+ flags = qt.Qt.NoItemFlags # Disabled if autoscale
+ return flags
+
+ else: # Never event
+ return super(_ColormapBoundRow, self).flags(column)
+
+ def data(self, column, role):
+ if column == 0 and role == qt.Qt.CheckStateRole:
+ if self._getRawBound() is None:
+ return qt.Qt.Unchecked
+ else:
+ return qt.Qt.Checked
+
+ else:
+ return super(_ColormapBoundRow, self).data(column, role)
+
+ def setData(self, column, value, role):
+ if column == 0 and role == qt.Qt.CheckStateRole:
+ if self._colormap is not None:
+ bound = self._getBound() if value == qt.Qt.Checked else None
+ self._setBound(bound)
+ return True
+ else:
+ return False
+
+ return super(_ColormapBoundRow, self).setData(column, value, role)
+
+
+class ColormapRow(_ColormapBaseProxyRow):
+ """Represents :class:`ColormapMixIn` property.
+
+ :param Item3D item: Scene item with colormap property
+ """
+
+ def __init__(self, item):
+ super(ColormapRow, self).__init__(
+ item,
+ name='Colormap',
+ fget=self._get)
+
+ self._colormapImage = None
+
+ self._colormapsMapping = {}
+ for cmap in preferredColormaps():
+ self._colormapsMapping[cmap.title()] = cmap
+
+ self.addRow(ProxyRow(
+ name='Name',
+ fget=self._getName,
+ fset=self._setName,
+ notify=self._sigColormapChanged,
+ editorHint=list(self._colormapsMapping.keys())))
+
+ norms = [norm.title() for norm in self._colormap.NORMALIZATIONS]
+ self.addRow(ProxyRow(
+ name='Normalization',
+ fget=self._getNormalization,
+ fset=self._setNormalization,
+ notify=self._sigColormapChanged,
+ editorHint=norms))
+
+ self.addRow(_ColormapBoundRow(item, name='Min.', index=0))
+ self.addRow(_ColormapBoundRow(item, name='Max.', index=1))
+
+ self._sigColormapChanged.connect(self._updateColormapImage)
+
+ def _get(self):
+ """Getter for ProxyRow subclass"""
+ return None
+
+ def _getName(self):
+ """Proxy for :meth:`Colormap.getName`"""
+ if self._colormap is not None:
+ return self._colormap.getName().title()
+ else:
+ return ''
+
+ def _setName(self, name):
+ """Proxy for :meth:`Colormap.setName`"""
+ # Convert back from titled to name if possible
+ if self._colormap is not None:
+ name = self._colormapsMapping.get(name, name)
+ self._colormap.setName(name)
+
+ def _getNormalization(self):
+ """Proxy for :meth:`Colormap.getNormalization`"""
+ if self._colormap is not None:
+ return self._colormap.getNormalization().title()
+ else:
+ return ''
+
+ def _setNormalization(self, normalization):
+ """Proxy for :meth:`Colormap.setNormalization`"""
+ if self._colormap is not None:
+ return self._colormap.setNormalization(normalization.lower())
+
+ def _updateColormapImage(self, *args, **kwargs):
+ """Notify colormap update to update the image in the tree"""
+ if self._colormapImage is not None:
+ self._colormapImage = None
+ model = self.model()
+ if model is not None:
+ index = self.index(column=1)
+ model.dataChanged.emit(index, index)
+
+ def data(self, column, role):
+ if column == 1 and role == qt.Qt.DecorationRole:
+ if self._colormapImage is None:
+ image = numpy.zeros((16, 130, 3), dtype=numpy.uint8)
+ image[1:-1, 1:-1] = self._colormap.getNColors(image.shape[1] - 2)[:, :3]
+ self._colormapImage = convertArrayToQImage(image)
+ return self._colormapImage
+
+ return super(ColormapRow, self).data(column, role)
+
+
+class SymbolRow(ProxyRow):
+ """Represents :class:`SymbolMixIn` symbol property.
+
+ :param Item3D item: Scene item with symbol property
+ """
+
+ def __init__(self, item):
+ names = [item.getSymbolName(s) for s in item.getSupportedSymbols()]
+ super(SymbolRow, self).__init__(
+ name='Marker',
+ fget=item.getSymbolName,
+ fset=item.setSymbol,
+ notify=item.sigItemChanged,
+ editorHint=names)
+
+
+class SymbolSizeRow(ProxyRow):
+ """Represents :class:`SymbolMixIn` symbol size property.
+
+ :param Item3D item: Scene item with symbol size property
+ """
+
+ def __init__(self, item):
+ super(SymbolSizeRow, self).__init__(
+ name='Marker size',
+ fget=item.getSymbolSize,
+ fset=item.setSymbolSize,
+ notify=item.sigItemChanged,
+ editorHint=(1, 20)) # TODO link with OpenGL max point size
+
+
+class PlaneRow(ProxyRow):
+ """Represents :class:`PlaneMixIn` property.
+
+ :param Item3D item: Scene item with plane equation property
+ """
+
+ def __init__(self, item):
+ super(PlaneRow, self).__init__(
+ name='Equation',
+ fget=item.getParameters,
+ fset=item.setParameters,
+ notify=item.sigItemChanged,
+ toModelData=lambda data: qt.QVector4D(*data),
+ fromModelData=lambda data: (data.x(), data.y(), data.z(), data.w()))
+ self._item = weakref.ref(item)
+
+ def data(self, column, role):
+ if column == 1 and role == qt.Qt.DisplayRole:
+ item = self._item()
+ if item is not None:
+ params = item.getParameters()
+ return ('%gx %+gy %+gz %+g = 0' %
+ (params[0], params[1], params[2], params[3]))
+ return super(PlaneRow, self).data(column, role)
+
+
+class RemoveIsosurfaceRow(BaseRow):
+ """Class for Isosurface Delete button
+
+ :param Isosurface isosurface: The isosurface item to attach the button to.
+ """
+
+ def __init__(self, isosurface):
+ super(RemoveIsosurfaceRow, self).__init__()
+ self._isosurface = weakref.ref(isosurface)
+
+ def createEditor(self):
+ """Specific editor factory provided to the model"""
+ editor = qt.QWidget()
+ layout = qt.QHBoxLayout(editor)
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.setSpacing(0)
+
+ removeBtn = qt.QToolButton()
+ removeBtn.setText('Delete')
+ removeBtn.setToolButtonStyle(qt.Qt.ToolButtonTextOnly)
+ layout.addWidget(removeBtn)
+ removeBtn.clicked.connect(self._removeClicked)
+
+ layout.addStretch(1)
+ return editor
+
+ def isosurface(self):
+ """Returns the controlled isosurface
+
+ :rtype: Isosurface
+ """
+ return self._isosurface()
+
+ def data(self, column, role):
+ if column == 0 and role == qt.Qt.UserRole: # editor hint
+ return self.createEditor
+
+ return super(RemoveIsosurfaceRow, self).data(column, role)
+
+ def flags(self, column):
+ flags = super(RemoveIsosurfaceRow, self).flags(column)
+ if column == 0:
+ flags |= qt.Qt.ItemIsEditable
+ return flags
+
+ def _removeClicked(self):
+ """Handle Delete button clicked"""
+ isosurface = self.isosurface()
+ if isosurface is not None:
+ scalarField3D = isosurface.parent()
+ if scalarField3D is not None:
+ scalarField3D.removeIsosurface(isosurface)
+
+
+class IsosurfaceRow(Item3DRow):
+ """Represents an :class:`Isosurface` item.
+
+ :param Isosurface item: Isosurface item
+ """
+
+ _LEVEL_SLIDER_RANGE = 0, 1000
+ """Range given as editor hint"""
+
+ def __init__(self, item):
+ super(IsosurfaceRow, self).__init__(item, name=item.getLevel())
+
+ self.setFlags(self.flags(1) | qt.Qt.ItemIsEditable, 1)
+
+ item.sigItemChanged.connect(self._levelChanged)
+
+ self.addRow(ProxyRow(
+ name='Level',
+ fget=self._getValueForLevelSlider,
+ fset=self._setLevelFromSliderValue,
+ notify=item.sigItemChanged,
+ editorHint=self._LEVEL_SLIDER_RANGE))
+
+ self.addRow(ColorProxyRow(
+ name='Color',
+ fget=self._rgbColor,
+ fset=self._setRgbColor,
+ notify=item.sigItemChanged))
+
+ self.addRow(ProxyRow(
+ name='Opacity',
+ fget=self._opacity,
+ fset=self._setOpacity,
+ notify=item.sigItemChanged,
+ editorHint=(0, 255)))
+
+ self.addRow(RemoveIsosurfaceRow(item))
+
+ def _getValueForLevelSlider(self):
+ """Convert iso level to slider value.
+
+ :rtype: int
+ """
+ item = self.item()
+ if item is not None:
+ scalarField3D = item.parent()
+ if scalarField3D is not None:
+ dataRange = scalarField3D.getDataRange()
+ if dataRange is not None:
+ dataMin, dataMax = dataRange[0], dataRange[-1]
+ offset = (item.getLevel() - dataMin) / (dataMax - dataMin)
+
+ sliderMin, sliderMax = self._LEVEL_SLIDER_RANGE
+ value = sliderMin + (sliderMax - sliderMin) * offset
+ return value
+ return 0
+
+ def _setLevelFromSliderValue(self, value):
+ """Convert slider value to isolevel.
+
+ :param int value:
+ """
+ item = self.item()
+ if item is not None:
+ scalarField3D = item.parent()
+ if scalarField3D is not None:
+ dataRange = scalarField3D.getDataRange()
+ if dataRange is not None:
+ sliderMin, sliderMax = self._LEVEL_SLIDER_RANGE
+ offset = (value - sliderMin) / (sliderMax - sliderMin)
+
+ dataMin, dataMax = dataRange[0], dataRange[-1]
+ level = dataMin + (dataMax - dataMin) * offset
+ item.setLevel(level)
+
+ def _rgbColor(self):
+ """Proxy to get the isosurface's RGB color without transparency
+
+ :rtype: QColor
+ """
+ item = self.item()
+ if item is None:
+ return None
+ else:
+ color = item.getColor()
+ color.setAlpha(255)
+ return color
+
+ def _setRgbColor(self, color):
+ """Proxy to set the isosurface's RGB color without transparency
+
+ :param QColor color:
+ """
+ item = self.item()
+ if item is not None:
+ color.setAlpha(item.getColor().alpha())
+ item.setColor(color)
+
+ def _opacity(self):
+ """Proxy to get the isosurface's transparency
+
+ :rtype: int
+ """
+ item = self.item()
+ return 255 if item is None else item.getColor().alpha()
+
+ def _setOpacity(self, opacity):
+ """Proxy to set the isosurface's transparency.
+
+ :param int opacity:
+ """
+ item = self.item()
+ if item is not None:
+ color = item.getColor()
+ color.setAlpha(opacity)
+ item.setColor(color)
+
+ def _levelChanged(self, event):
+ """Handle isosurface level changed and notify model
+
+ :param ItemChangedType event:
+ """
+ if event == items.Item3DChangedType.ISO_LEVEL:
+ model = self.model()
+ if model is not None:
+ index = self.index(column=1)
+ model.dataChanged.emit(index, index)
+
+ def data(self, column, role):
+ if column == 0: # Show color as decoration, not text
+ if role == qt.Qt.DisplayRole:
+ return None
+ elif role == qt.Qt.DecorationRole:
+ return self._rgbColor()
+
+ elif column == 1 and role in (qt.Qt.DisplayRole, qt.Qt.EditRole):
+ item = self.item()
+ return None if item is None else item.getLevel()
+
+ return super(IsosurfaceRow, self).data(column, role)
+
+ def setData(self, column, value, role):
+ if column == 1 and role == qt.Qt.EditRole:
+ item = self.item()
+ if item is not None:
+ item.setLevel(value)
+ return True
+
+ return super(IsosurfaceRow, self).setData(column, value, role)
+
+
+class AddIsosurfaceRow(BaseRow):
+ """Class for Isosurface create button
+
+ :param ScalarField3D scalarField3D:
+ The ScalarField3D item to attach the button to.
+ """
+
+ def __init__(self, scalarField3D):
+ super(AddIsosurfaceRow, self).__init__()
+ self._scalarField3D = weakref.ref(scalarField3D)
+
+ def createEditor(self):
+ """Specific editor factory provided to the model"""
+ editor = qt.QWidget()
+ layout = qt.QHBoxLayout(editor)
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.setSpacing(0)
+
+ addBtn = qt.QToolButton()
+ addBtn.setText('+')
+ addBtn.setToolButtonStyle(qt.Qt.ToolButtonTextOnly)
+ layout.addWidget(addBtn)
+ addBtn.clicked.connect(self._addClicked)
+
+ layout.addStretch(1)
+ return editor
+
+ def scalarField3D(self):
+ """Returns the controlled ScalarField3D
+
+ :rtype: ScalarField3D
+ """
+ return self._scalarField3D()
+
+ def data(self, column, role):
+ if column == 0 and role == qt.Qt.UserRole: # editor hint
+ return self.createEditor
+
+ return super(AddIsosurfaceRow, self).data(column, role)
+
+ def flags(self, column):
+ flags = super(AddIsosurfaceRow, self).flags(column)
+ if column == 0:
+ flags |= qt.Qt.ItemIsEditable
+ return flags
+
+ def _addClicked(self):
+ """Handle Delete button clicked"""
+ scalarField3D = self.scalarField3D()
+ if scalarField3D is not None:
+ dataRange = scalarField3D.getDataRange()
+ if dataRange is None:
+ dataRange = 0., 1.
+
+ scalarField3D.addIsosurface(
+ numpy.mean((dataRange[0], dataRange[-1])),
+ '#0000FF')
+
+
+class ScalarField3DIsoSurfacesRow(StaticRow):
+ """Represents :class:`ScalarFieldView`'s isosurfaces
+
+ :param ScalarFieldView scalarField3D: ScalarFieldView to control
+ """
+
+ def __init__(self, scalarField3D):
+ super(ScalarField3DIsoSurfacesRow, self).__init__(
+ ('Isosurfaces', None))
+ self._scalarField3D = weakref.ref(scalarField3D)
+
+ scalarField3D.sigIsosurfaceAdded.connect(self._isosurfaceAdded)
+ scalarField3D.sigIsosurfaceRemoved.connect(self._isosurfaceRemoved)
+
+ for item in scalarField3D.getIsosurfaces():
+ self.addRow(nodeFromItem(item))
+
+ self.addRow(AddIsosurfaceRow(scalarField3D))
+
+ def scalarField3D(self):
+ """Returns the controlled ScalarField3D
+
+ :rtype: ScalarField3D
+ """
+ return self._scalarField3D()
+
+ def _isosurfaceAdded(self, item):
+ """Handle isosurface addition
+
+ :param Isosurface item: added isosurface
+ """
+ scalarField3D = self.scalarField3D()
+ if scalarField3D is None:
+ return
+
+ row = scalarField3D.getIsosurfaces().index(item)
+ self.addRow(nodeFromItem(item), row)
+
+ def _isosurfaceRemoved(self, item):
+ """Handle isosurface removal
+
+ :param Isosurface item: removed isosurface
+ """
+ scalarField3D = self.scalarField3D()
+ if scalarField3D is None:
+ return
+
+ # Find item
+ for row in self.children():
+ if row.item() is item:
+ self.removeRow(row)
+ break # Got it
+ else:
+ raise RuntimeError("Model does not correspond to scene content")
+
+
+class Scatter2DPropertyMixInRow(object):
+ """Mix-in class that enable/disable row according to Scatter2D mode.
+
+ :param Scatter2D item:
+ :param str propertyName: Name of the Scatter2D property of this row
+ """
+
+ def __init__(self, item, propertyName):
+ assert propertyName in ('lineWidth', 'symbol', 'symbolSize')
+ self.__propertyName = propertyName
+
+ self.__isEnabled = item.isPropertyEnabled(propertyName)
+ self.__updateFlags()
+
+ item.sigItemChanged.connect(self.__itemChanged)
+
+ def data(self, column, role):
+ if column == 1 and not self.__isEnabled:
+ # Discard data and editorHint if disabled
+ return None
+ else:
+ return super(Scatter2DPropertyMixInRow, self).data(column, role)
+
+ def __updateFlags(self):
+ """Update model flags"""
+ if self.__isEnabled:
+ self.setFlags(qt.Qt.ItemIsEnabled, 0)
+ self.setFlags(qt.Qt.ItemIsEnabled | qt.Qt.ItemIsEditable, 1)
+ else:
+ self.setFlags(qt.Qt.NoItemFlags)
+
+ def __itemChanged(self, event):
+ """Set flags to enable/disable the row"""
+ if event == items.ItemChangedType.VISUALIZATION_MODE:
+ item = self.sender()
+ if item is not None: # This occurs with PySide/python2.7
+ self.__isEnabled = item.isPropertyEnabled(self.__propertyName)
+ self.__updateFlags()
+
+ # Notify model
+ model = self.model()
+ if model is not None:
+ begin = self.index(column=0)
+ end = self.index(column=1)
+ model.dataChanged.emit(begin, end)
+
+
+class Scatter2DSymbolRow(Scatter2DPropertyMixInRow, SymbolRow):
+ """Specific class for Scatter2D symbol.
+
+ It is enabled/disabled according to visualization mode.
+
+ :param Scatter2D item:
+ """
+
+ def __init__(self, item):
+ SymbolRow.__init__(self, item)
+ Scatter2DPropertyMixInRow.__init__(self, item, 'symbol')
+
+
+class Scatter2DSymbolSizeRow(Scatter2DPropertyMixInRow, SymbolSizeRow):
+ """Specific class for Scatter2D symbol size.
+
+ It is enabled/disabled according to visualization mode.
+
+ :param Scatter2D item:
+ """
+
+ def __init__(self, item):
+ SymbolSizeRow.__init__(self, item)
+ Scatter2DPropertyMixInRow.__init__(self, item, 'symbolSize')
+
+
+class Scatter2DLineWidth(Scatter2DPropertyMixInRow, ProxyRow):
+ """Specific class for Scatter2D symbol size.
+
+ It is enabled/disabled according to visualization mode.
+
+ :param Scatter2D item:
+ """
+
+ def __init__(self, item):
+ # TODO link editorHint with OpenGL max line width
+ ProxyRow.__init__(self,
+ name='Line width',
+ fget=item.getLineWidth,
+ fset=item.setLineWidth,
+ notify=item.sigItemChanged,
+ editorHint=(1, 10))
+ Scatter2DPropertyMixInRow.__init__(self, item, 'lineWidth')
+
+
+def initScatter2DNode(node, item):
+ """Specific node init for Scatter2D to set order of parameters
+
+ :param Item3DRow node: The model node to setup
+ :param Scatter2D item: The Scatter2D the node is representing
+ """
+ node.addRow(ProxyRow(
+ name='Mode',
+ fget=item.getVisualization,
+ fset=item.setVisualization,
+ notify=item.sigItemChanged,
+ editorHint=[m.title() for m in item.supportedVisualizations()],
+ toModelData=lambda data: data.title(),
+ fromModelData=lambda data: data.lower()))
+
+ node.addRow(ProxyRow(
+ name='Height map',
+ fget=item.isHeightMap,
+ fset=item.setHeightMap,
+ notify=item.sigItemChanged))
+
+ node.addRow(ColormapRow(item))
+
+ node.addRow(Scatter2DSymbolRow(item))
+ node.addRow(Scatter2DSymbolSizeRow(item))
+
+ node.addRow(Scatter2DLineWidth(item))
+
+
+def initScalarField3DNode(node, item):
+ """Specific node init for ScalarField3D
+
+ :param Item3DRow node: The model node to setup
+ :param ScalarField3D item: The ScalarField3D the node is representing
+ """
+ node.addRow(nodeFromItem(item.getCutPlanes()[0])) # Add cut plane
+ node.addRow(ScalarField3DIsoSurfacesRow(item))
+
+
+def initScalarField3DCutPlaneNode(node, item):
+ """Specific node init for ScalarField3D CutPlane
+
+ :param Item3DRow node: The model node to setup
+ :param CutPlane item: The CutPlane the node is representing
+ """
+ node.addRow(PlaneRow(item))
+
+ node.addRow(ColormapRow(item))
+
+ node.addRow(ProxyRow(
+ name='Values<=Min',
+ fget=item.getDisplayValuesBelowMin,
+ fset=item.setDisplayValuesBelowMin,
+ notify=item.sigItemChanged))
+
+ node.addRow(InterpolationRow(item))
+
+
+NODE_SPECIFIC_INIT = [ # class, init(node, item)
+ (items.Scatter2D, initScatter2DNode),
+ (items.ScalarField3D, initScalarField3DNode),
+ (CutPlane, initScalarField3DCutPlaneNode),
+]
+"""List of specific node init for different item class"""
+
+
+def nodeFromItem(item):
+ """Create :class:`Item3DRow` subclass corresponding to item
+
+ :param Item3D item: The item fow which to create the node
+ :rtype: Item3DRow
+ """
+ assert isinstance(item, items.Item3D)
+
+ # Item with specific model row class
+ if isinstance(item, (items.GroupItem, items.GroupWithAxesItem)):
+ return GroupItemRow(item)
+ elif isinstance(item, Isosurface):
+ return IsosurfaceRow(item)
+
+ # Create Item3DRow and populate it
+ node = Item3DRow(item)
+
+ if isinstance(item, items.DataItem3D):
+ node.addRow(DataItem3DBoundingBoxRow(item))
+ node.addRow(DataItem3DTransformRow(item))
+
+ # Specific extra init
+ for cls, specificInit in NODE_SPECIFIC_INIT:
+ if isinstance(item, cls):
+ specificInit(node, item)
+ break
+
+ else: # Generic case: handle mixins
+ for cls in item.__class__.__mro__:
+ if cls is items.ColormapMixIn:
+ node.addRow(ColormapRow(item))
+
+ elif cls is items.InterpolationMixIn:
+ node.addRow(InterpolationRow(item))
+
+ elif cls is items.SymbolMixIn:
+ node.addRow(SymbolRow(item))
+ node.addRow(SymbolSizeRow(item))
+
+ elif cls is items.PlaneMixIn:
+ node.addRow(PlaneRow(item))
+
+ return node
diff --git a/silx/gui/plot3d/_model/model.py b/silx/gui/plot3d/_model/model.py
new file mode 100644
index 0000000..186838f
--- /dev/null
+++ b/silx/gui/plot3d/_model/model.py
@@ -0,0 +1,184 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+This module provides the :class:`SceneWidget` content and parameters model.
+"""
+
+from __future__ import absolute_import, division
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "11/01/2018"
+
+
+import weakref
+
+from ... import qt
+
+from .core import BaseRow
+from .items import Settings, nodeFromItem
+
+
+def visitQAbstractItemModel(model, parent=qt.QModelIndex()):
+ """Iterate over indices in the model starting from parent
+
+ It iterates column by column and row by row
+ (i.e., from left to right and from top to bottom).
+ Parent are returned before their children.
+ It only iterates through the children for the first column of a row.
+
+ :param QAbstractItemModel model: The model to visit
+ :param QModelIndex parent:
+ Index from which to start visiting the model.
+ Default: start from the root
+ """
+ assert isinstance(model, qt.QAbstractItemModel)
+ assert isinstance(parent, qt.QModelIndex)
+ assert parent.model() is model or not parent.isValid()
+
+ for row in range(model.rowCount(parent)):
+ for column in range(model.columnCount(parent)):
+ index = model.index(row, column, parent)
+ yield index
+
+ index = model.index(row, 0, parent)
+ for index in visitQAbstractItemModel(model, index):
+ yield index
+
+
+class Root(BaseRow):
+ """Root node of :class:`SceneWidget` parameters.
+
+ It has two children:
+ - Settings
+ - Scene group
+ """
+
+ def __init__(self, model, sceneWidget):
+ super(Root, self).__init__()
+ self._sceneWidget = weakref.ref(sceneWidget)
+ self.setParent(model) # Needed for Root
+
+ def children(self):
+ sceneWidget = self._sceneWidget()
+ if sceneWidget is None:
+ return ()
+ else:
+ return super(Root, self).children()
+
+
+class SceneModel(qt.QAbstractItemModel):
+ """Model of a :class:`SceneWidget`.
+
+ :param SceneWidget parent: The SceneWidget this model represents.
+ """
+
+ def __init__(self, parent):
+ self._sceneWidget = weakref.ref(parent)
+
+ super(SceneModel, self).__init__(parent)
+ self._root = Root(self, parent)
+ self._root.addRow(Settings(parent))
+ self._root.addRow(nodeFromItem(parent.getSceneGroup()))
+
+ def sceneWidget(self):
+ """Returns the :class:`SceneWidget` this model represents.
+
+ In case the widget has already been deleted, it returns None
+
+ :rtype: SceneWidget
+ """
+ return self._sceneWidget()
+
+ def _itemFromIndex(self, index):
+ """Returns the corresponding :class:`Node` or :class:`Item3D`.
+
+ :param QModelIndex index:
+ :rtype: Node or Item3D
+ """
+ return index.internalPointer() if index.isValid() else self._root
+
+ def index(self, row, column, parent=qt.QModelIndex()):
+ """See :meth:`QAbstractItemModel.index`"""
+ if column >= self.columnCount(parent) or row >= self.rowCount(parent):
+ return qt.QModelIndex()
+
+ item = self._itemFromIndex(parent)
+ return self.createIndex(row, column, item.children()[row])
+
+ def parent(self, index):
+ """See :meth:`QAbstractItemModel.parent`"""
+ if not index.isValid():
+ return qt.QModelIndex()
+
+ item = self._itemFromIndex(index)
+ parent = item.parent()
+
+ ancestor = parent.parent()
+
+ if ancestor is not self: # root node
+ children = ancestor.children()
+ row = children.index(parent)
+ return self.createIndex(row, 0, parent)
+
+ return qt.QModelIndex()
+
+ def rowCount(self, parent=qt.QModelIndex()):
+ """See :meth:`QAbstractItemModel.rowCount`"""
+ item = self._itemFromIndex(parent)
+ return item.rowCount()
+
+ def columnCount(self, parent=qt.QModelIndex()):
+ """See :meth:`QAbstractItemModel.columnCount`"""
+ item = self._itemFromIndex(parent)
+ return item.columnCount()
+
+ def data(self, index, role=qt.Qt.DisplayRole):
+ """See :meth:`QAbstractItemModel.data`"""
+ item = self._itemFromIndex(index)
+ column = index.column()
+ return item.data(column, role)
+
+ def setData(self, index, value, role=qt.Qt.EditRole):
+ """See :meth:`QAbstractItemModel.setData`"""
+ item = self._itemFromIndex(index)
+ column = index.column()
+ if item.setData(column, value, role):
+ self.dataChanged.emit(index, index)
+ return True
+ return False
+
+ def flags(self, index):
+ """See :meth:`QAbstractItemModel.flags`"""
+ item = self._itemFromIndex(index)
+ column = index.column()
+ return item.flags(column)
+
+ def headerData(self, section, orientation, role=qt.Qt.DisplayRole):
+ """See :meth:`QAbstractItemModel.headerData`"""
+ if orientation == qt.Qt.Horizontal and role == qt.Qt.DisplayRole:
+ return 'Item' if section == 0 else 'Value'
+ else:
+ return None
diff --git a/silx/gui/plot3d/actions/Plot3DAction.py b/silx/gui/plot3d/actions/Plot3DAction.py
index a1faaea..94b9572 100644
--- a/silx/gui/plot3d/actions/Plot3DAction.py
+++ b/silx/gui/plot3d/actions/Plot3DAction.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -44,7 +44,8 @@ class Plot3DAction(qt.QAction):
"""QAction associated to a Plot3DWidget
:param parent: See :class:`QAction`
- :param Plot3DWidget plot3d: Plot3DWidget the action is associated with
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
"""
def __init__(self, parent, plot3d=None):
@@ -55,7 +56,8 @@ class Plot3DAction(qt.QAction):
def setPlot3DWidget(self, widget):
"""Set the Plot3DWidget this action is associated with
- :param Plot3DWidget widget: The Plot3DWidget to use
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget widget:
+ The Plot3DWidget to use
"""
self._plot3d = None if widget is None else weakref.ref(widget)
@@ -64,6 +66,6 @@ class Plot3DAction(qt.QAction):
If no widget is associated, it returns None.
- :rtype: qt.QWidget
+ :rtype: QWidget
"""
return None if self._plot3d is None else self._plot3d()
diff --git a/silx/gui/plot3d/actions/io.py b/silx/gui/plot3d/actions/io.py
index 18f91b4..5126000 100644
--- a/silx/gui/plot3d/actions/io.py
+++ b/silx/gui/plot3d/actions/io.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -54,7 +54,8 @@ class CopyAction(Plot3DAction):
"""QAction to provide copy of a Plot3DWidget
:param parent: See :class:`QAction`
- :param Plot3DWidget plot3d: Plot3DWidget the action is associated with
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
"""
def __init__(self, parent, plot3d=None):
@@ -81,7 +82,8 @@ class SaveAction(Plot3DAction):
"""QAction to provide save snapshot of a Plot3DWidget
:param parent: See :class:`QAction`
- :param Plot3DWidget plot3d: Plot3DWidget the action is associated with
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
"""
def __init__(self, parent, plot3d=None):
@@ -135,7 +137,8 @@ class PrintAction(Plot3DAction):
"""QAction to provide printing of a Plot3DWidget
:param parent: See :class:`QAction`
- :param Plot3DWidget plot3d: Plot3DWidget the action is associated with
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
"""
def __init__(self, parent, plot3d=None):
@@ -152,7 +155,7 @@ class PrintAction(Plot3DAction):
def getPrinter(self):
"""Return the QPrinter instance used for printing.
- :rtype: qt.QPrinter
+ :rtype: QPrinter
"""
# TODO This is a hack to sync with silx plot PrintAction
# This needs to be centralized
@@ -201,6 +204,8 @@ class VideoAction(Plot3DAction):
The scene is rotated 360 degrees around a vertical axis.
:param parent: Action parent see :class:`QAction`.
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
"""
PNG_SERIE_FILTER = 'Serie of PNG files (*.png)'
diff --git a/silx/gui/plot3d/actions/mode.py b/silx/gui/plot3d/actions/mode.py
index a06b9a8..b591290 100644
--- a/silx/gui/plot3d/actions/mode.py
+++ b/silx/gui/plot3d/actions/mode.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -48,7 +48,8 @@ class InteractiveModeAction(Plot3DAction):
:param parent: See :class:`QAction`
:param str interaction: The interactive mode this action controls
- :param Plot3DWidget plot3d: Plot3DWidget the action is associated with
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
"""
def __init__(self, parent, interaction, plot3d=None):
@@ -100,7 +101,8 @@ class RotateArcballAction(InteractiveModeAction):
"""QAction to set arcball rotation interaction on a Plot3DWidget
:param parent: See :class:`QAction`
- :param Plot3DWidget plot3d: Plot3DWidget the action is associated with
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
"""
def __init__(self, parent, plot3d=None):
@@ -108,14 +110,15 @@ class RotateArcballAction(InteractiveModeAction):
self.setIcon(getQIcon('rotate-3d'))
self.setText('Rotate')
- self.setToolTip('Rotate the view')
+ self.setToolTip('Rotate the view. Press <b>Ctrl</b> to pan.')
class PanAction(InteractiveModeAction):
"""QAction to set pan interaction on a Plot3DWidget
:param parent: See :class:`QAction`
- :param Plot3DWidget plot3d: Plot3DWidget the action is associated with
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
"""
def __init__(self, parent, plot3d=None):
@@ -123,4 +126,4 @@ class PanAction(InteractiveModeAction):
self.setIcon(getQIcon('pan'))
self.setText('Pan')
- self.setToolTip('Pan the view')
+ self.setToolTip('Pan the view. Press <b>Ctrl</b> to rotate.')
diff --git a/silx/gui/plot3d/actions/viewpoint.py b/silx/gui/plot3d/actions/viewpoint.py
index 6aa7400..d764c40 100644
--- a/silx/gui/plot3d/actions/viewpoint.py
+++ b/silx/gui/plot3d/actions/viewpoint.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -45,11 +45,144 @@ from .Plot3DAction import Plot3DAction
_logger = logging.getLogger(__name__)
-class RotateViewport(Plot3DAction):
+class _SetViewpointAction(Plot3DAction):
+ """Base class for actions setting a Plot3DWidget viewpoint
+
+ :param parent: See :class:`QAction`
+ :param str face: The name of the predefined viewpoint
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
+ """
+ def __init__(self, parent, face, plot3d=None):
+ super(_SetViewpointAction, self).__init__(parent, plot3d)
+ assert face in ('side', 'front', 'back', 'left', 'right', 'top', 'bottom')
+ self._face = face
+
+ self.setIconVisibleInMenu(True)
+ self.setCheckable(False)
+ self.triggered[bool].connect(self._triggered)
+
+ def _triggered(self, checked=False):
+ plot3d = self.getPlot3DWidget()
+ if plot3d is None:
+ _logger.error(
+ 'Cannot start/stop rotation, no associated Plot3DWidget')
+ else:
+ plot3d.viewport.camera.extrinsic.reset(face=self._face)
+ plot3d.centerScene()
+
+
+class FrontViewpointAction(_SetViewpointAction):
+ """QAction to set Plot3DWidget viewpoint to look from the front
+
+ :param parent: See :class:`QAction`
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
+ """
+ def __init__(self, parent, plot3d=None):
+ super(FrontViewpointAction, self).__init__(parent, 'front', plot3d)
+
+ self.setIcon(getQIcon('cube-front'))
+ self.setText('Front')
+ self.setToolTip('View along the -Z axis')
+
+
+class BackViewpointAction(_SetViewpointAction):
+ """QAction to set Plot3DWidget viewpoint to look from the back
+
+ :param parent: See :class:`QAction`
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
+ """
+ def __init__(self, parent, plot3d=None):
+ super(BackViewpointAction, self).__init__(parent, 'back', plot3d)
+
+ self.setIcon(getQIcon('cube-back'))
+ self.setText('Back')
+ self.setToolTip('View along the +Z axis')
+
+
+class LeftViewpointAction(_SetViewpointAction):
+ """QAction to set Plot3DWidget viewpoint to look from the left
+
+ :param parent: See :class:`QAction`
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
+ """
+ def __init__(self, parent, plot3d=None):
+ super(LeftViewpointAction, self).__init__(parent, 'left', plot3d)
+
+ self.setIcon(getQIcon('cube-left'))
+ self.setText('Left')
+ self.setToolTip('View along the +X axis')
+
+
+class RightViewpointAction(_SetViewpointAction):
+ """QAction to set Plot3DWidget viewpoint to look from the right
+
+ :param parent: See :class:`QAction`
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
+ """
+ def __init__(self, parent, plot3d=None):
+ super(RightViewpointAction, self).__init__(parent, 'right', plot3d)
+
+ self.setIcon(getQIcon('cube-right'))
+ self.setText('Right')
+ self.setToolTip('View along the -X axis')
+
+
+class TopViewpointAction(_SetViewpointAction):
+ """QAction to set Plot3DWidget viewpoint to look from the top
+
+ :param parent: See :class:`QAction`
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
+ """
+ def __init__(self, parent, plot3d=None):
+ super(TopViewpointAction, self).__init__(parent, 'top', plot3d)
+
+ self.setIcon(getQIcon('cube-top'))
+ self.setText('Top')
+ self.setToolTip('View along the -Y axis')
+
+
+class BottomViewpointAction(_SetViewpointAction):
+ """QAction to set Plot3DWidget viewpoint to look from the bottom
+
+ :param parent: See :class:`QAction`
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
+ """
+ def __init__(self, parent, plot3d=None):
+ super(BottomViewpointAction, self).__init__(parent, 'bottom', plot3d)
+
+ self.setIcon(getQIcon('cube-bottom'))
+ self.setText('Bottom')
+ self.setToolTip('View along the +Y axis')
+
+
+class SideViewpointAction(_SetViewpointAction):
+ """QAction to set Plot3DWidget viewpoint to look from the side
+
+ :param parent: See :class:`QAction`
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
+ """
+ def __init__(self, parent, plot3d=None):
+ super(SideViewpointAction, self).__init__(parent, 'side', plot3d)
+
+ self.setIcon(getQIcon('cube'))
+ self.setText('Side')
+ self.setToolTip('Side view')
+
+
+class RotateViewpoint(Plot3DAction):
"""QAction to rotate the scene of a Plot3DWidget
:param parent: See :class:`QAction`
- :param Plot3DWidget plot3d: Plot3DWidget the action is associated with
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget plot3d:
+ Plot3DWidget the action is associated with
"""
_TIMEOUT_MS = 50
@@ -59,7 +192,7 @@ class RotateViewport(Plot3DAction):
"""Rotation speed of the animation"""
def __init__(self, parent, plot3d=None):
- super(RotateViewport, self).__init__(parent, plot3d)
+ super(RotateViewpoint, self).__init__(parent, plot3d)
self._previousTime = None
diff --git a/silx/gui/plot3d/items/__init__.py b/silx/gui/plot3d/items/__init__.py
new file mode 100644
index 0000000..b50ea5a
--- /dev/null
+++ b/silx/gui/plot3d/items/__init__.py
@@ -0,0 +1,43 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This package provides classes that describes :class:`.SceneWidget` content.
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "15/11/2017"
+
+
+from .core import DataItem3D, Item3D, GroupItem, GroupWithAxesItem # noqa
+from .core import ItemChangedType, Item3DChangedType # noqa
+from .mixins import (ColormapMixIn, InterpolationMixIn, # noqa
+ PlaneMixIn, SymbolMixIn) # noqa
+from .clipplane import ClipPlane # noqa
+from .image import ImageData, ImageRgba # noqa
+from .mesh import Mesh # noqa
+from .scatter import Scatter2D, Scatter3D # noqa
+from .volume import ScalarField3D # noqa
diff --git a/silx/gui/plot3d/items/clipplane.py b/silx/gui/plot3d/items/clipplane.py
new file mode 100644
index 0000000..a5ba0e6
--- /dev/null
+++ b/silx/gui/plot3d/items/clipplane.py
@@ -0,0 +1,50 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module provides a scene clip plane class.
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "15/11/2017"
+
+
+from ..scene import primitives
+
+from .core import Item3D
+from .mixins import PlaneMixIn
+
+
+class ClipPlane(Item3D, PlaneMixIn):
+ """Represents a clipping plane that clips following items within the group.
+
+ For now only on clip plane is allowed at once in a scene.
+ """
+
+ def __init__(self, parent=None):
+ plane = primitives.ClipPlane()
+ Item3D.__init__(self, parent=parent, primitive=plane)
+ PlaneMixIn.__init__(self, plane=plane)
diff --git a/silx/gui/plot3d/items/core.py b/silx/gui/plot3d/items/core.py
new file mode 100644
index 0000000..e549e59
--- /dev/null
+++ b/silx/gui/plot3d/items/core.py
@@ -0,0 +1,622 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module provides the base class for items of the :class:`.SceneWidget`.
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "15/11/2017"
+
+from collections import defaultdict
+
+import numpy
+
+from silx.third_party import enum, six
+
+from ... import qt
+from ...plot.items import ItemChangedType
+from .. import scene
+from ..scene import axes, primitives, transform
+
+
+@enum.unique
+class Item3DChangedType(enum.Enum):
+ """Type of modification provided by :attr:`Item3D.sigItemChanged` signal."""
+
+ INTERPOLATION = 'interpolationChanged'
+ """Item3D image interpolation changed flag."""
+
+ TRANSFORM = 'transformChanged'
+ """Item3D transform changed flag."""
+
+ HEIGHT_MAP = 'heightMapChanged'
+ """Item3D height map changed flag."""
+
+ ISO_LEVEL = 'isoLevelChanged'
+ """Isosurface level changed flag."""
+
+ LABEL = 'labelChanged'
+ """Item's label changed flag."""
+
+ BOUNDING_BOX_VISIBLE = 'boundingBoxVisibleChanged'
+ """Item's bounding box visibility changed"""
+
+ ROOT_ITEM = 'rootItemChanged'
+ """Item's root changed flag."""
+
+
+class Item3D(qt.QObject):
+ """Base class representing an item in the scene.
+
+ :param parent: The View widget this item belongs to.
+ :param primitive: An optional primitive to use as scene primitive
+ """
+
+ _LABEL_INDICES = defaultdict(int)
+ """Store per class label indices"""
+
+ sigItemChanged = qt.Signal(object)
+ """Signal emitted when an item's property has changed.
+
+ It provides a flag describing which property of the item has changed.
+ See :class:`ItemChangedType` and :class:`Item3DChangedType`
+ for flags description.
+ """
+
+ def __init__(self, parent, primitive=None):
+ qt.QObject.__init__(self, parent)
+
+ if primitive is None:
+ primitive = scene.Group()
+
+ self._primitive = primitive
+
+ self.__syncForegroundColor()
+
+ labelIndex = self._LABEL_INDICES[self.__class__]
+ self._label = six.text_type(self.__class__.__name__)
+ if labelIndex != 0:
+ self._label += u' %d' % labelIndex
+ self._LABEL_INDICES[self.__class__] += 1
+
+ if isinstance(parent, Item3D):
+ parent.sigItemChanged.connect(self.__parentItemChanged)
+
+ def setParent(self, parent):
+ """Override set parent to handle root item change"""
+ previousParent = self.parent()
+ if isinstance(previousParent, Item3D):
+ previousParent.sigItemChanged.disconnect(self.__parentItemChanged)
+
+ super(Item3D, self).setParent(parent)
+
+ if isinstance(parent, Item3D):
+ parent.sigItemChanged.connect(self.__parentItemChanged)
+
+ self._updated(Item3DChangedType.ROOT_ITEM)
+
+ def __parentItemChanged(self, event):
+ """Handle updates of the parent if it is an Item3D
+
+ :param Item3DChangedType event:
+ """
+ if event == Item3DChangedType.ROOT_ITEM:
+ self._updated(Item3DChangedType.ROOT_ITEM)
+
+ def root(self):
+ """Returns the root of the scene this item belongs to.
+
+ The root is the up-most Item3D in the scene tree hierarchy.
+
+ :rtype: Union[Item3D, None]
+ """
+ root = None
+ ancestor = self.parent()
+ while isinstance(ancestor, Item3D):
+ root = ancestor
+ ancestor = ancestor.parent()
+
+ return root
+
+ def _getScenePrimitive(self):
+ """Return the group containing the item rendering"""
+ return self._primitive
+
+ def _updated(self, event=None):
+ """Handle MixIn class updates.
+
+ :param event: The event to send to :attr:`sigItemChanged` signal.
+ """
+ if event == Item3DChangedType.ROOT_ITEM:
+ self.__syncForegroundColor()
+
+ if event is not None:
+ self.sigItemChanged.emit(event)
+
+ # Label
+
+ def getLabel(self):
+ """Returns the label associated to this item.
+
+ :rtype: str
+ """
+ return self._label
+
+ def setLabel(self, label):
+ """Set the label associated to this item.
+
+ :param str label:
+ """
+ label = six.text_type(label)
+ if label != self._label:
+ self._label = label
+ self._updated(Item3DChangedType.LABEL)
+
+ # Visibility
+
+ def isVisible(self):
+ """Returns True if item is visible, else False
+
+ :rtype: bool
+ """
+ return self._getScenePrimitive().visible
+
+ def setVisible(self, visible=True):
+ """Set the visibility of the item in the scene.
+
+ :param bool visible: True (default) to show the item, False to hide
+ """
+ visible = bool(visible)
+ primitive = self._getScenePrimitive()
+ if visible != primitive.visible:
+ primitive.visible = visible
+ self._updated(ItemChangedType.VISIBLE)
+
+ # Foreground color
+
+ def _setForegroundColor(self, color):
+ """Set the foreground color of the item.
+
+ The default implementation does nothing, override it in subclass.
+
+ :param color: RGBA color
+ :type color: tuple of 4 float in [0., 1.]
+ """
+ if hasattr(super(Item3D, self), '_setForegroundColor'):
+ super(Item3D, self)._setForegroundColor(color)
+
+ def __syncForegroundColor(self):
+ """Retrieve foreground color from parent and update this item"""
+ # Look-up for SceneWidget to get its foreground color
+ root = self.root()
+ if root is not None:
+ widget = root.parent()
+ if isinstance(widget, qt.QWidget):
+ self._setForegroundColor(
+ widget.getForegroundColor().getRgbF())
+
+
+class DataItem3D(Item3D):
+ """Base class representing a data item with transform in the scene.
+
+ :param parent: The View widget this item belongs to.
+ :param Union[GroupBBox, None] group:
+ The scene group to use for rendering
+ """
+
+ def __init__(self, parent, group=None):
+ if group is None:
+ group = primitives.GroupBBox()
+
+ # Set-up bounding box
+ group.boxVisible = False
+ group.axesVisible = False
+ else:
+ assert isinstance(group, primitives.GroupBBox)
+
+ Item3D.__init__(self, parent=parent, primitive=group)
+
+ # Transformations
+ self._translate = transform.Translate()
+ self._rotateForwardTranslation = transform.Translate()
+ self._rotate = transform.Rotate()
+ self._rotateBackwardTranslation = transform.Translate()
+ self._translateFromRotationCenter = transform.Translate()
+ self._matrix = transform.Matrix()
+ self._scale = transform.Scale()
+ # Group transforms to do to data before rotation
+ # This is useful to handle rotation center relative to bbox
+ self._transformObjectToRotate = transform.TransformList(
+ [self._matrix, self._scale])
+ self._transformObjectToRotate.addListener(self._updateRotationCenter)
+
+ self._rotationCenter = 0., 0., 0.
+
+ self._getScenePrimitive().transforms = [
+ self._translate,
+ self._rotateForwardTranslation,
+ self._rotate,
+ self._rotateBackwardTranslation,
+ self._transformObjectToRotate]
+
+ def _updated(self, event=None):
+ """Handle MixIn class updates.
+
+ :param event: The event to send to :attr:`sigItemChanged` signal.
+ """
+ if event == ItemChangedType.DATA:
+ self._updateRotationCenter()
+ super(DataItem3D, self)._updated(event)
+
+ # Transformations
+
+ def setScale(self, sx=1., sy=1., sz=1.):
+ """Set the scale of the item in the scene.
+
+ :param float sx: Scale factor along the X axis
+ :param float sy: Scale factor along the Y axis
+ :param float sz: Scale factor along the Z axis
+ """
+ scale = numpy.array((sx, sy, sz), dtype=numpy.float32)
+ if not numpy.all(numpy.equal(scale, self.getScale())):
+ self._scale.scale = scale
+ self._updated(Item3DChangedType.TRANSFORM)
+
+ def getScale(self):
+ """Returns the scales provided by :meth:`setScale`.
+
+ :rtype: numpy.ndarray
+ """
+ return self._scale.scale
+
+ def setTranslation(self, x=0., y=0., z=0.):
+ """Set the translation of the origin of the item in the scene.
+
+ :param float x: Offset of the data origin on the X axis
+ :param float y: Offset of the data origin on the Y axis
+ :param float z: Offset of the data origin on the Z axis
+ """
+ translation = numpy.array((x, y, z), dtype=numpy.float32)
+ if not numpy.all(numpy.equal(translation, self.getTranslation())):
+ self._translate.translation = translation
+ self._updated(Item3DChangedType.TRANSFORM)
+
+ def getTranslation(self):
+ """Returns the offset set by :meth:`setTranslation`.
+
+ :rtype: numpy.ndarray
+ """
+ return self._translate.translation
+
+ _ROTATION_CENTER_TAGS = 'lower', 'center', 'upper'
+
+ def _updateRotationCenter(self, *args, **kwargs):
+ """Update rotation center relative to bounding box"""
+ center = []
+ for index, position in enumerate(self.getRotationCenter()):
+ # Patch position relative to bounding box
+ if position in self._ROTATION_CENTER_TAGS:
+ bounds = self._getScenePrimitive().bounds(
+ transformed=False, dataBounds=True)
+ bounds = self._transformObjectToRotate.transformBounds(bounds)
+
+ if bounds is None:
+ position = 0.
+ elif position == 'lower':
+ position = bounds[0, index]
+ elif position == 'center':
+ position = 0.5 * (bounds[0, index] + bounds[1, index])
+ elif position == 'upper':
+ position = bounds[1, index]
+
+ center.append(position)
+
+ if not numpy.all(numpy.equal(
+ center, self._rotateForwardTranslation.translation)):
+ self._rotateForwardTranslation.translation = center
+ self._rotateBackwardTranslation.translation = \
+ - self._rotateForwardTranslation.translation
+ self._updated(Item3DChangedType.TRANSFORM)
+
+ def setRotationCenter(self, x=0., y=0., z=0.):
+ """Set the center of rotation of the item.
+
+ Position of the rotation center is either a float
+ for an absolute position or one of the following
+ string to define a position relative to the item's bounding box:
+ 'lower', 'center', 'upper'
+
+ :param x: rotation center position on the X axis
+ :rtype: float or str
+ :param y: rotation center position on the Y axis
+ :rtype: float or str
+ :param z: rotation center position on the Z axis
+ :rtype: float or str
+ """
+ center = []
+ for position in (x, y, z):
+ if isinstance(position, six.string_types):
+ assert position in self._ROTATION_CENTER_TAGS
+ else:
+ position = float(position)
+ center.append(position)
+ center = tuple(center)
+
+ if center != self._rotationCenter:
+ self._rotationCenter = center
+ self._updateRotationCenter()
+
+ def getRotationCenter(self):
+ """Returns the rotation center set by :meth:`setRotationCenter`.
+
+ :rtype: 3-tuple of float or str
+ """
+ return self._rotationCenter
+
+ def setRotation(self, angle=0., axis=(0., 0., 1.)):
+ """Set the rotation of the item in the scene
+
+ :param float angle: The rotation angle in degrees.
+ :param axis: The (x, y, z) coordinates of the rotation axis.
+ """
+ axis = numpy.array(axis, dtype=numpy.float32)
+ assert axis.ndim == 1
+ assert axis.size == 3
+ if (self._rotate.angle != angle or
+ not numpy.all(numpy.equal(axis, self._rotate.axis))):
+ self._rotate.setAngleAxis(angle, axis)
+ self._updated(Item3DChangedType.TRANSFORM)
+
+ def getRotation(self):
+ """Returns the rotation set by :meth:`setRotation`.
+
+ :return: (angle, axis)
+ :rtype: 2-tuple (float, numpy.ndarray)
+ """
+ return self._rotate.angle, self._rotate.axis
+
+ def setMatrix(self, matrix=None):
+ """Set the transform matrix
+
+ :param numpy.ndarray matrix: 3x3 transform matrix
+ """
+ matrix4x4 = numpy.identity(4, dtype=numpy.float32)
+
+ if matrix is not None:
+ matrix = numpy.array(matrix, dtype=numpy.float32)
+ assert matrix.shape == (3, 3)
+ matrix4x4[:3, :3] = matrix
+
+ if not numpy.all(numpy.equal(matrix4x4, self._matrix.getMatrix())):
+ self._matrix.setMatrix(matrix4x4)
+ self._updated(Item3DChangedType.TRANSFORM)
+
+ def getMatrix(self):
+ """Returns the matrix set by :meth:`setMatrix`
+
+ :return: 3x3 matrix
+ :rtype: numpy.ndarray"""
+ return self._matrix.getMatrix(copy=True)[:3, :3]
+
+ # Bounding box
+
+ def _setForegroundColor(self, color):
+ """Set the color of the bounding box
+
+ :param color: RGBA color as 4 floats in [0, 1]
+ """
+ self._getScenePrimitive().color = color
+ super(DataItem3D, self)._setForegroundColor(color)
+
+ def isBoundingBoxVisible(self):
+ """Returns item's bounding box visibility.
+
+ :rtype: bool
+ """
+ return self._getScenePrimitive().boxVisible
+
+ def setBoundingBoxVisible(self, visible):
+ """Set item's bounding box visibility.
+
+ :param bool visible:
+ True to show the bounding box, False (default) to hide it
+ """
+ visible = bool(visible)
+ primitive = self._getScenePrimitive()
+ if visible != primitive.boxVisible:
+ primitive.boxVisible = visible
+ self._updated(Item3DChangedType.BOUNDING_BOX_VISIBLE)
+
+
+class _BaseGroupItem(DataItem3D):
+ """Base class for group of items sharing a common transform."""
+
+ sigItemAdded = qt.Signal(object)
+ """Signal emitted when a new item is added to the group.
+
+ The newly added item is provided by this signal
+ """
+
+ sigItemRemoved = qt.Signal(object)
+ """Signal emitted when an item is removed from the group.
+
+ The removed item is provided by this signal.
+ """
+
+ def __init__(self, parent=None, group=None):
+ """Base class representing a group of items in the scene.
+
+ :param parent: The View widget this item belongs to.
+ :param Union[GroupBBox, None] group:
+ The scene group to use for rendering
+ """
+ DataItem3D.__init__(self, parent=parent, group=group)
+ self._items = []
+
+ def addItem(self, item, index=None):
+ """Add an item to the group
+
+ :param Item3D item: The item to add
+ :param int index: The index at which to place the item.
+ By default it is appended to the end of the list.
+ :raise ValueError: If the item is already in the group.
+ """
+ assert isinstance(item, Item3D)
+ assert item.parent() in (None, self)
+
+ if item in self.getItems():
+ raise ValueError("Item3D already in group: %s" % item)
+
+ item.setParent(self)
+ if index is None:
+ self._getScenePrimitive().children.append(
+ item._getScenePrimitive())
+ self._items.append(item)
+ else:
+ self._getScenePrimitive().children.insert(
+ index, item._getScenePrimitive())
+ self._items.insert(index, item)
+ self.sigItemAdded.emit(item)
+
+ def getItems(self):
+ """Returns the list of items currently present in the group.
+
+ :rtype: tuple
+ """
+ return tuple(self._items)
+
+ def removeItem(self, item):
+ """Remove an item from the scene.
+
+ :param Item3D item: The item to remove from the scene
+ :raises ValueError: If the item does not belong to the group
+ """
+ if item not in self.getItems():
+ raise ValueError("Item3D not in group: %s" % str(item))
+
+ self._getScenePrimitive().children.remove(item._getScenePrimitive())
+ self._items.remove(item)
+ item.setParent(None)
+ self.sigItemRemoved.emit(item)
+
+ def clearItems(self):
+ """Remove all item from the group."""
+ for item in self.getItems():
+ self.removeItem(item)
+
+ def visit(self, included=True):
+ """Generator visiting the group content.
+
+ It traverses the group sub-tree in a top-down left-to-right way.
+
+ :param bool included: True (default) to include self in visit
+ """
+ if included:
+ yield self
+ for child in self.getItems():
+ yield child
+ if hasattr(child, 'visit'):
+ for item in child.visit(included=False):
+ yield item
+
+
+class GroupItem(_BaseGroupItem):
+ """Group of items sharing a common transform."""
+
+ def __init__(self, parent=None):
+ super(GroupItem, self).__init__(parent=parent)
+
+
+class GroupWithAxesItem(_BaseGroupItem):
+ """
+ Group of items sharing a common transform surrounded with labelled axes.
+ """
+
+ def __init__(self, parent=None):
+ """Class representing a group of items in the scene with labelled axes.
+
+ :param parent: The View widget this item belongs to.
+ """
+ super(GroupWithAxesItem, self).__init__(parent=parent,
+ group=axes.LabelledAxes())
+
+ # Axes labels
+
+ def setAxesLabels(self, xlabel=None, ylabel=None, zlabel=None):
+ """Set the text labels of the axes.
+
+ :param str xlabel: Label of the X axis, None to leave unchanged.
+ :param str ylabel: Label of the Y axis, None to leave unchanged.
+ :param str zlabel: Label of the Z axis, None to leave unchanged.
+ """
+ labelledAxes = self._getScenePrimitive()
+ if xlabel is not None:
+ labelledAxes.xlabel = xlabel
+
+ if ylabel is not None:
+ labelledAxes.ylabel = ylabel
+
+ if zlabel is not None:
+ labelledAxes.zlabel = zlabel
+
+ class _Labels(tuple):
+ """Return type of :meth:`getAxesLabels`"""
+
+ def getXLabel(self):
+ """Label of the X axis (str)"""
+ return self[0]
+
+ def getYLabel(self):
+ """Label of the Y axis (str)"""
+ return self[1]
+
+ def getZLabel(self):
+ """Label of the Z axis (str)"""
+ return self[2]
+
+ def getAxesLabels(self):
+ """Returns the text labels of the axes
+
+ >>> group = GroupWithAxesItem()
+ >>> group.setAxesLabels(xlabel='X')
+
+ You can get the labels either as a 3-tuple:
+
+ >>> xlabel, ylabel, zlabel = group.getAxesLabels()
+
+ Or as an object with methods getXLabel, getYLabel and getZLabel:
+
+ >>> labels = group.getAxesLabels()
+ >>> labels.getXLabel()
+ ... 'X'
+
+ :return: object describing the labels
+ """
+ labelledAxes = self._getScenePrimitive()
+ return self._Labels((labelledAxes.xlabel,
+ labelledAxes.ylabel,
+ labelledAxes.zlabel))
diff --git a/silx/gui/plot3d/items/image.py b/silx/gui/plot3d/items/image.py
new file mode 100644
index 0000000..9e8bf1e
--- /dev/null
+++ b/silx/gui/plot3d/items/image.py
@@ -0,0 +1,126 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module provides 2D data and RGB(A) image item class.
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "15/11/2017"
+
+import numpy
+
+from ..scene import primitives
+from .core import DataItem3D, ItemChangedType
+from .mixins import ColormapMixIn, InterpolationMixIn
+
+
+class ImageData(DataItem3D, ColormapMixIn, InterpolationMixIn):
+ """Description of a 2D image data.
+
+ :param parent: The View widget this item belongs to.
+ """
+
+ def __init__(self, parent=None):
+ DataItem3D.__init__(self, parent=parent)
+ ColormapMixIn.__init__(self)
+ InterpolationMixIn.__init__(self)
+
+ self._data = numpy.zeros((0, 0), dtype=numpy.float32)
+
+ self._image = primitives.ImageData(self._data)
+ self._getScenePrimitive().children.append(self._image)
+
+ # Connect scene primitive to mix-in class
+ ColormapMixIn._setSceneColormap(self, self._image.colormap)
+ InterpolationMixIn._setPrimitive(self, self._image)
+
+ def setData(self, data, copy=True):
+ """Set the image data to display.
+
+ The data will be casted to float32.
+
+ :param numpy.ndarray data: The image data
+ :param bool copy: True (default) to copy the data,
+ False to use as is (do not modify!).
+ """
+ self._image.setData(data, copy=copy)
+ ColormapMixIn._setRangeFromData(self, self.getData(copy=False))
+ self._updated(ItemChangedType.DATA)
+
+ def getData(self, copy=True):
+ """Get the image data.
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :rtype: numpy.ndarray
+ :return: The image data
+ """
+ return self._image.getData(copy=copy)
+
+
+class ImageRgba(DataItem3D, InterpolationMixIn):
+ """Description of a 2D data RGB(A) image.
+
+ :param parent: The View widget this item belongs to.
+ """
+
+ def __init__(self, parent=None):
+ DataItem3D.__init__(self, parent=parent)
+ InterpolationMixIn.__init__(self)
+
+ self._data = numpy.zeros((0, 0, 3), dtype=numpy.float32)
+
+ self._image = primitives.ImageRgba(self._data)
+ self._getScenePrimitive().children.append(self._image)
+
+ # Connect scene primitive to mix-in class
+ InterpolationMixIn._setPrimitive(self, self._image)
+
+ def setData(self, data, copy=True):
+ """Set the RGB(A) image data to display.
+
+ Supported array format: float32 in [0, 1], uint8.
+
+ :param numpy.ndarray data:
+ The RGBA image data as an array of shape (H, W, Channels)
+ :param bool copy: True (default) to copy the data,
+ False to use as is (do not modify!).
+ """
+ self._image.setData(data, copy=copy)
+ self._updated(ItemChangedType.DATA)
+
+ def getData(self, copy=True):
+ """Get the image data.
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :rtype: numpy.ndarray
+ :return: The image data
+ """
+ return self._image.getData(copy=copy)
diff --git a/silx/gui/plot3d/items/mesh.py b/silx/gui/plot3d/items/mesh.py
new file mode 100644
index 0000000..8535728
--- /dev/null
+++ b/silx/gui/plot3d/items/mesh.py
@@ -0,0 +1,145 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module provides regular mesh item class.
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "15/11/2017"
+
+import numpy
+
+from ..scene import primitives
+from .core import DataItem3D, ItemChangedType
+
+
+class Mesh(DataItem3D):
+ """Description of mesh.
+
+ :param parent: The View widget this item belongs to.
+ """
+
+ def __init__(self, parent=None):
+ DataItem3D.__init__(self, parent=parent)
+ self._mesh = None
+
+ def setData(self,
+ position,
+ color,
+ normal=None,
+ mode='triangles',
+ copy=True):
+ """Set mesh geometry data.
+
+ Supported drawing modes are:
+
+ - For points: 'points'
+ - For lines: 'lines', 'line_strip', 'loop'
+ - For triangles: 'triangles', 'triangle_strip', 'fan'
+
+ :param numpy.ndarray position:
+ Position (x, y, z) of each vertex as a (N, 3) array
+ :param numpy.ndarray color: Colors for each point or a single color
+ :param numpy.ndarray normal: Normals for each point or None (default)
+ :param str mode: The drawing mode.
+ :param bool copy: True (default) to copy the data,
+ False to use as is (do not modify!).
+ """
+ self._getScenePrimitive().children = [] # Remove any previous mesh
+
+ if position is None or len(position) == 0:
+ self._mesh = 0
+ else:
+ self._mesh = primitives.Mesh3D(
+ position, color, normal, mode=mode, copy=copy)
+ self._getScenePrimitive().children.append(self._mesh)
+
+ self.sigItemChanged.emit(ItemChangedType.DATA)
+
+ def getData(self, copy=True):
+ """Get the mesh geometry.
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :return: The positions, colors, normals and mode
+ :rtype: tuple of numpy.ndarray
+ """
+ return (self.getPositionData(copy=copy),
+ self.getColorData(copy=copy),
+ self.getNormalData(copy=copy),
+ self.getDrawMode())
+
+ def getPositionData(self, copy=True):
+ """Get the mesh vertex positions.
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :return: The (x, y, z) positions as a (N, 3) array
+ :rtype: numpy.ndarray
+ """
+ if self._mesh is None:
+ return numpy.empty((0, 3), dtype=numpy.float32)
+ else:
+ return self._mesh.getAttribute('position', copy=copy)
+
+ def getColorData(self, copy=True):
+ """Get the mesh vertex colors.
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :return: The RGBA colors as a (N, 4) array or a single color
+ :rtype: numpy.ndarray
+ """
+ if self._mesh is None:
+ return numpy.empty((0, 4), dtype=numpy.float32)
+ else:
+ return self._mesh.getAttribute('color', copy=copy)
+
+ def getNormalData(self, copy=True):
+ """Get the mesh vertex normals.
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get internal representation (do not modify!).
+ :return: The normals as a (N, 3) array, a single normal or None
+ :rtype: numpy.ndarray or None
+ """
+ if self._mesh is None:
+ return None
+ else:
+ return self._mesh.getAttribute('normal', copy=copy)
+
+ def getDrawMode(self):
+ """Get mesh rendering mode.
+
+ :return: The drawing mode of this primitive
+ :rtype: str
+ """
+ return self._mesh.drawMode
diff --git a/silx/gui/plot3d/items/mixins.py b/silx/gui/plot3d/items/mixins.py
new file mode 100644
index 0000000..41ad3c3
--- /dev/null
+++ b/silx/gui/plot3d/items/mixins.py
@@ -0,0 +1,302 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module provides mix-in classes for :class:`Item3D`.
+"""
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "15/11/2017"
+
+
+import collections
+import numpy
+
+from silx.math.combo import min_max
+
+from ...plot.items.core import ItemMixInBase
+from ...plot.items.core import ColormapMixIn as _ColormapMixIn
+from ...plot.items.core import SymbolMixIn as _SymbolMixIn
+from ...plot.Colors import rgba
+
+from ..scene import primitives
+from .core import Item3DChangedType, ItemChangedType
+
+
+class InterpolationMixIn(ItemMixInBase):
+ """Mix-in class for image interpolation mode
+
+ :param str mode: 'linear' (default) or 'nearest'
+ :param primitive:
+ scene object for which to sync interpolation mode.
+ This object MUST have an interpolation property that is updated.
+ """
+
+ NEAREST_INTERPOLATION = 'nearest'
+ """Nearest interpolation mode (see :meth:`setInterpolation`)"""
+
+ LINEAR_INTERPOLATION = 'linear'
+ """Linear interpolation mode (see :meth:`setInterpolation`)"""
+
+ INTERPOLATION_MODES = NEAREST_INTERPOLATION, LINEAR_INTERPOLATION
+ """Supported interpolation modes for :meth:`setInterpolation`"""
+
+ def __init__(self, mode=NEAREST_INTERPOLATION, primitive=None):
+ self.__primitive = primitive
+ self._syncPrimitiveInterpolation()
+
+ self.__interpolationMode = None
+ self.setInterpolation(mode)
+
+ def _setPrimitive(self, primitive):
+
+ """Set the scene object for which to sync interpolation"""
+ self.__primitive = primitive
+ self._syncPrimitiveInterpolation()
+
+ def _syncPrimitiveInterpolation(self):
+ """Synchronize scene object's interpolation"""
+ if self.__primitive is not None:
+ self.__primitive.interpolation = self.getInterpolation()
+
+ def setInterpolation(self, mode):
+ """Set image interpolation mode
+
+ :param str mode: 'nearest' or 'linear'
+ """
+ mode = str(mode)
+ assert mode in self.INTERPOLATION_MODES
+ if mode != self.__interpolationMode:
+ self.__interpolationMode = mode
+ self._syncPrimitiveInterpolation()
+ self._updated(Item3DChangedType.INTERPOLATION)
+
+ def getInterpolation(self):
+ """Returns the interpolation mode set by :meth:`setInterpolation`
+
+ :rtype: str
+ """
+ return self.__interpolationMode
+
+
+class ColormapMixIn(_ColormapMixIn):
+ """Mix-in class for Item3D object with a colormap
+
+ :param sceneColormap:
+ The plot3d scene colormap to sync with Colormap object.
+ """
+
+ def __init__(self, sceneColormap=None):
+ super(ColormapMixIn, self).__init__()
+
+ self._dataRange = None
+ self.__sceneColormap = sceneColormap
+ self._syncSceneColormap()
+
+ self.sigItemChanged.connect(self.__colormapUpdated)
+
+ def __colormapUpdated(self, event):
+ """Handle colormap updates"""
+ if event == ItemChangedType.COLORMAP:
+ self._syncSceneColormap()
+
+ def _setRangeFromData(self, data=None):
+ """Compute the data range the colormap should use from provided data.
+
+ :param data: Data set from which to compute the range or None
+ """
+ if data is None or len(data) == 0:
+ dataRange = None
+ else:
+ dataRange = min_max(data, min_positive=True, finite=True)
+ if dataRange.minimum is None: # Only non-finite data
+ dataRange = None
+
+ if dataRange is not None:
+ min_positive = dataRange.min_positive
+ if min_positive is None:
+ min_positive = float('nan')
+ dataRange = dataRange.minimum, min_positive, dataRange.maximum
+
+ self._dataRange = dataRange
+
+ if self.getColormap().isAutoscale():
+ self._syncSceneColormap()
+
+ def _setSceneColormap(self, sceneColormap):
+ """Set the scene colormap to sync with Colormap object.
+
+ :param sceneColormap:
+ The plot3d scene colormap to sync with Colormap object.
+ """
+ self.__sceneColormap = sceneColormap
+ self._syncSceneColormap()
+
+ def _getSceneColormap(self):
+ """Returns scene colormap that is sync"""
+ return self.__sceneColormap
+
+ def _syncSceneColormap(self):
+ """Synchronizes scene's colormap with Colormap object"""
+ if self.__sceneColormap is not None:
+ colormap = self.getColormap()
+
+ self.__sceneColormap.colormap = colormap.getNColors()
+ self.__sceneColormap.norm = colormap.getNormalization()
+ range_ = colormap.getColormapRange(data=self._dataRange)
+ self.__sceneColormap.range_ = range_
+
+
+class SymbolMixIn(_SymbolMixIn):
+ """Mix-in class for symbol and symbolSize properties for Item3D"""
+
+ _DEFAULT_SYMBOL = 'o'
+ _DEFAULT_SYMBOL_SIZE = 7.0
+ _SUPPORTED_SYMBOLS = collections.OrderedDict((
+ ('o', 'Circle'),
+ ('d', 'Diamond'),
+ ('s', 'Square'),
+ ('+', 'Plus'),
+ ('x', 'Cross'),
+ ('*', 'Star'),
+ ('|', 'Vertical Line'),
+ ('_', 'Horizontal Line'),
+ ('.', 'Point'),
+ (',', 'Pixel')))
+
+ def _getSceneSymbol(self):
+ """Returns a symbol name and size suitable for scene primitives.
+
+ :return: (symbol, size)
+ """
+ symbol = self.getSymbol()
+ size = self.getSymbolSize()
+ if symbol == ',': # pixel
+ return 's', 1.
+ elif symbol == '.': # point
+ # Size as in plot OpenGL backend, mimic matplotlib
+ return 'o', numpy.ceil(0.5 * size) + 1.
+ else:
+ return symbol, size
+
+
+class PlaneMixIn(ItemMixInBase):
+ """Mix-in class for plane items (based on PlaneInGroup primitive)"""
+
+ def __init__(self, plane):
+ assert isinstance(plane, primitives.PlaneInGroup)
+ self.__plane = plane
+ self.__plane.alpha = 1.
+ self.__plane.addListener(self._planeChanged)
+ self.__plane.plane.addListener(self._planePositionChanged)
+
+ def _getPlane(self):
+ """Returns plane primitive
+
+ :rtype: primitives.PlaneInGroup
+ """
+ return self.__plane
+
+ def _planeChanged(self, source, *args, **kwargs):
+ """Handle events from the plane primitive"""
+ # Sync visibility
+ if source.visible != self.isVisible():
+ self.setVisible(source.visible)
+
+ def _planePositionChanged(self, source, *args, **kwargs):
+ """Handle update of cut plane position and normal"""
+ if self.__plane.visible: # TODO send even if hidden? or send also when showing if moved while hidden
+ self._updated(ItemChangedType.POSITION)
+
+ # Plane position
+
+ def moveToCenter(self):
+ """Move cut plane to center of data set"""
+ self.__plane.moveToCenter()
+
+ def isValid(self):
+ """Returns whether the cut plane is defined or not (bool)"""
+ return self.__plane.isValid
+
+ def getNormal(self):
+ """Returns the normal of the plane (as a unit vector)
+
+ :return: Normal (nx, ny, nz), vector is 0 if no plane is defined
+ :rtype: numpy.ndarray
+ """
+ return self.__plane.plane.normal
+
+ def setNormal(self, normal):
+ """Set the normal of the plane
+
+ :param normal: 3-tuple of float: nx, ny, nz
+ """
+ self.__plane.plane.normal = normal
+
+ def getPoint(self):
+ """Returns a point on the plane
+
+ :return: (x, y, z)
+ :rtype: numpy.ndarray
+ """
+ return self.__plane.plane.point
+
+ def setPoint(self, point):
+ """Set a point contained in the plane.
+
+ Warning: The plane might not intersect the bounding box of the data.
+
+ :param point: (x, y, z) position
+ :type point: 3-tuple of float
+ """
+ self.__plane.plane.point = point # TODO rework according to PR #1303
+
+ def getParameters(self):
+ """Returns the plane equation parameters: a*x + b*y + c*z + d = 0
+
+ :return: Plane equation parameters: (a, b, c, d)
+ :rtype: numpy.ndarray
+ """
+ return self.__plane.plane.parameters
+
+ def setParameters(self, parameters):
+ """Set the plane equation parameters: a*x + b*y + c*z + d = 0
+
+ Warning: The plane might not intersect the bounding box of the data.
+ The given parameters will be normalized.
+
+ :param parameters: (a, b, c, d) equation parameters
+ """
+ self.__plane.plane.parameters = parameters
+
+ # Border stroke
+
+ def _setForegroundColor(self, color):
+ """Set the color of the plane border.
+
+ :param color: RGBA color as 4 floats in [0, 1]
+ """
+ self.__plane.color = rgba(color)
+ if hasattr(super(PlaneMixIn, self), '_setForegroundColor'):
+ super(PlaneMixIn, self)._setForegroundColor(color)
diff --git a/silx/gui/plot3d/items/scatter.py b/silx/gui/plot3d/items/scatter.py
new file mode 100644
index 0000000..5eea455
--- /dev/null
+++ b/silx/gui/plot3d/items/scatter.py
@@ -0,0 +1,474 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module provides 2D and 3D scatter data item class.
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "15/11/2017"
+
+import collections
+import logging
+import sys
+import numpy
+
+from ..scene import function, primitives, utils
+
+from .core import DataItem3D, Item3DChangedType, ItemChangedType
+from .mixins import ColormapMixIn, SymbolMixIn
+
+
+_logger = logging.getLevelName(__name__)
+
+
+class Scatter3D(DataItem3D, ColormapMixIn, SymbolMixIn):
+ """Description of a 3D scatter plot.
+
+ :param parent: The View widget this item belongs to.
+ """
+
+ # TODO supports different size for each point
+
+ def __init__(self, parent=None):
+ DataItem3D.__init__(self, parent=parent)
+ ColormapMixIn.__init__(self)
+ SymbolMixIn.__init__(self)
+
+ noData = numpy.zeros((0, 1), dtype=numpy.float32)
+ symbol, size = self._getSceneSymbol()
+ self._scatter = primitives.Points(
+ x=noData, y=noData, z=noData, value=noData, size=size)
+ self._scatter.marker = symbol
+ self._getScenePrimitive().children.append(self._scatter)
+
+ # Connect scene primitive to mix-in class
+ ColormapMixIn._setSceneColormap(self, self._scatter.colormap)
+
+ def _updated(self, event=None):
+ """Handle mix-in class updates"""
+ if event in (ItemChangedType.SYMBOL, ItemChangedType.SYMBOL_SIZE):
+ symbol, size = self._getSceneSymbol()
+ self._scatter.marker = symbol
+ self._scatter.setAttribute('size', size, copy=True)
+
+ super(Scatter3D, self)._updated(event)
+
+ def setData(self, x, y, z, value, copy=True):
+ """Set the data of the scatter plot
+
+ :param numpy.ndarray x: Array of X coordinates (single value not accepted)
+ :param y: Points Y coordinate (array-like or single value)
+ :param z: Points Z coordinate (array-like or single value)
+ :param value: Points values (array-like or single value)
+ :param bool copy:
+ True (default) to copy the data,
+ False to use provided data (do not modify!)
+ """
+ self._scatter.setAttribute('x', x, copy=copy)
+ self._scatter.setAttribute('y', y, copy=copy)
+ self._scatter.setAttribute('z', z, copy=copy)
+ self._scatter.setAttribute('value', value, copy=copy)
+
+ ColormapMixIn._setRangeFromData(self, self.getValues(copy=False))
+ self._updated(ItemChangedType.DATA)
+
+ def getData(self, copy=True):
+ """Returns data as provided to :meth:`setData`.
+
+ :param bool copy: True to get a copy,
+ False to return internal data (do not modify!)
+ :return: (x, y, z, value)
+ """
+ return (self.getXData(copy),
+ self.getYData(copy),
+ self.getZData(copy),
+ self.getValues(copy))
+
+ def getXData(self, copy=True):
+ """Returns X data coordinates.
+
+ :param bool copy: True to get a copy,
+ False to return internal array (do not modify!)
+ :return: X coordinates
+ :rtype: numpy.ndarray
+ """
+ return self._scatter.getAttribute('x', copy=copy)
+
+ def getYData(self, copy=True):
+ """Returns Y data coordinates.
+
+ :param bool copy: True to get a copy,
+ False to return internal array (do not modify!)
+ :return: Y coordinates
+ :rtype: numpy.ndarray
+ """
+ return self._scatter.getAttribute('y', copy=copy)
+
+ def getZData(self, copy=True):
+ """Returns Z data coordinates.
+
+ :param bool copy: True to get a copy,
+ False to return internal array (do not modify!)
+ :return: Z coordinates
+ :rtype: numpy.ndarray
+ """
+ return self._scatter.getAttribute('z', copy=copy)
+
+ def getValues(self, copy=True):
+ """Returns data values.
+
+ :param bool copy: True to get a copy,
+ False to return internal array (do not modify!)
+ :return: data values
+ :rtype: numpy.ndarray
+ """
+ return self._scatter.getAttribute('value', copy=copy)
+
+
+class Scatter2D(DataItem3D, ColormapMixIn, SymbolMixIn):
+ """2D scatter data with settable visualization mode.
+
+ :param parent: The View widget this item belongs to.
+ """
+
+ _VISUALIZATION_PROPERTIES = {
+ 'points': ('symbol', 'symbolSize'),
+ 'lines': ('lineWidth',),
+ 'solid': (),
+ }
+ """Dict {visualization mode: property names used in this mode}"""
+
+ def __init__(self, parent=None):
+ DataItem3D.__init__(self, parent=parent)
+ ColormapMixIn.__init__(self)
+ SymbolMixIn.__init__(self)
+
+ self._visualizationMode = 'points'
+ self._heightMap = False
+ self._lineWidth = 1.
+
+ self._x = numpy.zeros((0,), dtype=numpy.float32)
+ self._y = numpy.zeros((0,), dtype=numpy.float32)
+ self._value = numpy.zeros((0,), dtype=numpy.float32)
+
+ self._cachedLinesIndices = None
+ self._cachedTrianglesIndices = None
+
+ # Connect scene primitive to mix-in class
+ ColormapMixIn._setSceneColormap(self, function.Colormap())
+
+ def _updated(self, event=None):
+ """Handle mix-in class updates"""
+ if event in (ItemChangedType.SYMBOL, ItemChangedType.SYMBOL_SIZE):
+ symbol, size = self._getSceneSymbol()
+ for child in self._getScenePrimitive().children:
+ if isinstance(child, primitives.Points):
+ child.marker = symbol
+ child.setAttribute('size', size, copy=True)
+
+ elif event == ItemChangedType.VISIBLE:
+ # TODO smart update?, need dirty flags
+ self._updateScene()
+
+ super(Scatter2D, self)._updated(event)
+
+ def supportedVisualizations(self):
+ """Returns the list of supported visualization modes.
+
+ See :meth:`setVisualizationModes`
+
+ :rtype: tuple of str
+ """
+ return tuple(self._VISUALIZATION_PROPERTIES.keys())
+
+ def setVisualization(self, mode):
+ """Set the visualization mode of the data.
+
+ Supported visualization modes are:
+
+ - 'points': For scatter plot representation
+ - 'lines': For Delaunay tesselation-based wireframe representation
+ - 'solid': For Delaunay tesselation-based solid surface representation
+
+ :param str mode: Mode of representation to use
+ """
+ mode = str(mode)
+ assert mode in self.supportedVisualizations()
+
+ if mode != self.getVisualization():
+ self._visualizationMode = mode
+ self._updateScene()
+ self._updated(ItemChangedType.VISUALIZATION_MODE)
+
+ def getVisualization(self):
+ """Returns the current visualization mode.
+
+ See :meth:`setVisualization`
+
+ :rtype: str
+ """
+ return self._visualizationMode
+
+ def isPropertyEnabled(self, name, visualization=None):
+ """Returns true if the property is used with visualization mode.
+
+ :param str name: The name of the property to check, in:
+ 'lineWidth', 'symbol', 'symbolSize'
+ :param str visualization:
+ The visualization mode for which to get the info.
+ By default, it is the current visualization mode.
+ :return:
+ """
+ assert name in ('lineWidth', 'symbol', 'symbolSize')
+ if visualization is None:
+ visualization = self.getVisualization()
+ assert visualization in self.supportedVisualizations()
+ return name in self._VISUALIZATION_PROPERTIES[visualization]
+
+ def setHeightMap(self, heightMap):
+ """Set whether to display the data has a height map or not.
+
+ When displayed as a height map, the data values are used as
+ z coordinates.
+
+ :param bool heightMap:
+ True to display a height map,
+ False to display as 2D data with z=0
+ """
+ heightMap = bool(heightMap)
+ if heightMap != self.isHeightMap():
+ self._heightMap = heightMap
+ self._updateScene()
+ self._updated(Item3DChangedType.HEIGHT_MAP)
+
+ def isHeightMap(self):
+ """Returns True if data is displayed as a height map.
+
+ :rtype: bool
+ """
+ return self._heightMap
+
+ def getLineWidth(self):
+ """Return the curve line width in pixels (float)"""
+ return self._lineWidth
+
+ def setLineWidth(self, width):
+ """Set the width in pixel of the curve line
+
+ See :meth:`getLineWidth`.
+
+ :param float width: Width in pixels
+ """
+ width = float(width)
+ assert width >= 1.
+ if width != self._lineWidth:
+ self._lineWidth = width
+ for child in self._getScenePrimitive().children:
+ if hasattr(child, 'lineWidth'):
+ child.lineWidth = width
+ self._updated(ItemChangedType.LINE_WIDTH)
+
+ def setData(self, x, y, value, copy=True):
+ """Set the data represented by this item.
+
+ Provided arrays must have the same length.
+
+ :param numpy.ndarray x: X coordinates (array-like)
+ :param numpy.ndarray y: Y coordinates (array-like)
+ :param value: Points value: array-like or single scalar
+ :param bool copy:
+ True (default) to make a copy of the data,
+ False to avoid copy if possible (do not modify the arrays).
+ """
+ x = numpy.array(
+ x, copy=copy, dtype=numpy.float32, order='C').reshape(-1)
+ y = numpy.array(
+ y, copy=copy, dtype=numpy.float32, order='C').reshape(-1)
+ assert len(x) == len(y)
+
+ if isinstance(value, collections.Iterable):
+ value = numpy.array(
+ value, copy=copy, dtype=numpy.float32, order='C').reshape(-1)
+ assert len(value) == len(x)
+ else: # Single scalar
+ value = numpy.array((float(value),), dtype=numpy.float32)
+
+ self._x = x
+ self._y = y
+ self._value = value
+
+ # Reset cache
+ self._cachedLinesIndices = None
+ self._cachedTrianglesIndices = None
+
+ # Store data range info
+ ColormapMixIn._setRangeFromData(self, self.getValues(copy=False))
+
+ self._updateScene()
+
+ self._updated(ItemChangedType.DATA)
+
+ def getData(self, copy=True):
+ """Returns data as provided to :meth:`setData`.
+
+ :param bool copy: True to get a copy,
+ False to return internal data (do not modify!)
+ :return: (x, y, value)
+ """
+ return (self.getXData(copy=copy),
+ self.getYData(copy=copy),
+ self.getValues(copy=copy))
+
+ def getXData(self, copy=True):
+ """Returns X data coordinates.
+
+ :param bool copy: True to get a copy,
+ False to return internal array (do not modify!)
+ :return: X coordinates
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(self._x, copy=copy)
+
+ def getYData(self, copy=True):
+ """Returns Y data coordinates.
+
+ :param bool copy: True to get a copy,
+ False to return internal array (do not modify!)
+ :return: Y coordinates
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(self._y, copy=copy)
+
+ def getValues(self, copy=True):
+ """Returns data values.
+
+ :param bool copy: True to get a copy,
+ False to return internal array (do not modify!)
+ :return: data values
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(self._value, copy=copy)
+
+ def _updateScene(self):
+ self._getScenePrimitive().children = [] # Remove previous primitives
+
+ if not self.isVisible():
+ return # Update when visible
+
+ x, y, value = self.getData(copy=False)
+ if len(x) == 0:
+ return # Nothing to display
+
+ mode = self.getVisualization()
+ heightMap = self.isHeightMap()
+
+ if mode == 'points':
+ z = value if heightMap else 0.
+ symbol, size = self._getSceneSymbol()
+ primitive = primitives.Points(
+ x=x, y=y, z=z, value=value,
+ size=size,
+ colormap=self._getSceneColormap())
+ primitive.marker = symbol
+
+ else:
+ # TODO run delaunay in a thread
+ # Compute lines/triangles indices if not cached
+ if self._cachedTrianglesIndices is None:
+ coordinates = numpy.array((x, y)).T
+
+ if len(coordinates) > 3:
+ # Enough points to try a Delaunay tesselation
+
+ # Lazy loading of Delaunay
+ from silx.third_party.scipy_spatial import Delaunay as _Delaunay
+
+ try:
+ tri = _Delaunay(coordinates)
+ except RuntimeError:
+ _logger.error("Delaunay tesselation failed: %s",
+ sys.exc_info()[1])
+ return None
+
+ self._cachedTrianglesIndices = numpy.ravel(
+ tri.simplices.astype(numpy.uint32))
+
+ else:
+ # 3 or less points: Draw one triangle
+ self._cachedTrianglesIndices = \
+ numpy.arange(3, dtype=numpy.uint32) % len(coordinates)
+
+ if mode == 'lines' and self._cachedLinesIndices is None:
+ # Compute line indices
+ self._cachedLinesIndices = utils.triangleToLineIndices(
+ self._cachedTrianglesIndices, unicity=True)
+
+ if mode == 'lines':
+ indices = self._cachedLinesIndices
+ renderMode = 'lines'
+ else:
+ indices = self._cachedTrianglesIndices
+ renderMode = 'triangles'
+
+ # TODO supports x, y instead of copy
+ if heightMap:
+ if len(value) == 1:
+ value = numpy.ones_like(x) * value
+ coordinates = numpy.array((x, y, value), dtype=numpy.float32).T
+ else:
+ coordinates = numpy.array((x, y), dtype=numpy.float32).T
+
+ # TODO option to enable/disable light, cache normals
+ # TODO smooth surface
+ if mode == 'solid':
+ if heightMap:
+ coordinates = coordinates[indices]
+ if len(value) > 1:
+ value = value[indices]
+ triangleNormals = utils.trianglesNormal(coordinates)
+ normal = numpy.empty((len(triangleNormals) * 3, 3),
+ dtype=numpy.float32)
+ normal[0::3, :] = triangleNormals
+ normal[1::3, :] = triangleNormals
+ normal[2::3, :] = triangleNormals
+ indices = None
+ else:
+ normal = (0., 0., 1.)
+ else:
+ normal = None
+
+ primitive = primitives.ColormapMesh3D(
+ coordinates,
+ value.reshape(-1, 1), # Makes it a 2D array
+ normal=normal,
+ colormap=self._getSceneColormap(),
+ indices=indices,
+ mode=renderMode)
+ primitive.lineWidth = self.getLineWidth()
+ primitive.lineSmooth = False
+
+ self._getScenePrimitive().children = [primitive]
diff --git a/silx/gui/plot3d/items/volume.py b/silx/gui/plot3d/items/volume.py
new file mode 100644
index 0000000..a1f40f7
--- /dev/null
+++ b/silx/gui/plot3d/items/volume.py
@@ -0,0 +1,463 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module provides 3D array item class and its sub-items.
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "15/11/2017"
+
+import logging
+import time
+import numpy
+
+from silx.math.combo import min_max
+from silx.math.marchingcubes import MarchingCubes
+
+from ... import qt
+from ...plot.Colors import rgba
+
+from ..scene import cutplane, primitives, transform
+
+from .core import DataItem3D, Item3D, ItemChangedType, Item3DChangedType
+from .mixins import ColormapMixIn, InterpolationMixIn, PlaneMixIn
+
+
+_logger = logging.getLogger(__name__)
+
+
+class CutPlane(Item3D, ColormapMixIn, InterpolationMixIn, PlaneMixIn):
+ """Class representing a cutting plane in a :class:`ScalarField3D` item.
+
+ :param parent: 3D Data set in which the cut plane is applied.
+ """
+
+ def __init__(self, parent):
+ plane = cutplane.CutPlane(normal=(0, 1, 0))
+
+ Item3D.__init__(self, parent=parent)
+ ColormapMixIn.__init__(self)
+ InterpolationMixIn.__init__(self)
+ PlaneMixIn.__init__(self, plane=plane)
+
+ self._dataRange = None
+
+ self._getScenePrimitive().children = [plane]
+
+ # Connect scene primitive to mix-in class
+ ColormapMixIn._setSceneColormap(self, plane.colormap)
+ InterpolationMixIn._setPrimitive(self, plane)
+
+ parent.sigItemChanged.connect(self._parentChanged)
+
+ def _parentChanged(self, event):
+ """Handle data change in the parent this plane belongs to"""
+ if event == ItemChangedType.DATA:
+ self._getPlane().setData(self.sender().getData(), copy=False)
+
+ # Store data range info as 3-tuple of values
+ self._dataRange = self.sender().getDataRange()
+
+ self.sigItemChanged.emit(ItemChangedType.DATA)
+
+ # Colormap
+
+ def getDisplayValuesBelowMin(self):
+ """Return whether values <= colormap min are displayed or not.
+
+ :rtype: bool
+ """
+ return self._getPlane().colormap.displayValuesBelowMin
+
+ def setDisplayValuesBelowMin(self, display):
+ """Set whether to display values <= colormap min.
+
+ :param bool display: True to show values below min,
+ False to discard them
+ """
+ display = bool(display)
+ if display != self.getDisplayValuesBelowMin():
+ self._getPlane().colormap.displayValuesBelowMin = display
+ self.sigItemChanged.emit(ItemChangedType.ALPHA)
+
+ def getDataRange(self):
+ """Return the range of the data as a 3-tuple of values.
+
+ positive min is NaN if no data is positive.
+
+ :return: (min, positive min, max) or None.
+ """
+ return self._dataRange
+
+
+class Isosurface(Item3D):
+ """Class representing an iso-surface in a :class:`ScalarField3D` item.
+
+ :param parent: The DataItem3D this iso-surface belongs to
+ """
+
+ def __init__(self, parent):
+ Item3D.__init__(self, parent=parent)
+ self._level = float('nan')
+ self._autoLevelFunction = None
+ self._color = rgba('#FFD700FF')
+ self._data = None
+
+ # TODO register to ScalarField3D signal instead?
+ def _setData(self, data, copy=True):
+ """Set the data set from which to build the iso-surface.
+
+ :param numpy.ndarray data: The 3D data set or None
+ :param bool copy: True to make a copy, False to use as is if possible
+ """
+ if data is None:
+ self._data = None
+ else:
+ self._data = numpy.array(data, copy=copy, order='C')
+
+ self._updateScenePrimitive()
+
+ def getLevel(self):
+ """Return the level of this iso-surface (float)"""
+ return self._level
+
+ def setLevel(self, level):
+ """Set the value at which to build the iso-surface.
+
+ Setting this value reset auto-level function
+
+ :param float level: The value at which to build the iso-surface
+ """
+ self._autoLevelFunction = None
+ level = float(level)
+ if level != self._level:
+ self._level = level
+ self._updateScenePrimitive()
+ self._updated(Item3DChangedType.ISO_LEVEL)
+
+ def isAutoLevel(self):
+ """True if iso-level is rebuild for each data set."""
+ return self.getAutoLevelFunction() is not None
+
+ def getAutoLevelFunction(self):
+ """Return the function computing the iso-level (callable or None)"""
+ return self._autoLevelFunction
+
+ def setAutoLevelFunction(self, autoLevel):
+ """Set the function used to compute the iso-level.
+
+ WARNING: The function might get called in a thread.
+
+ :param callable autoLevel:
+ A function taking a 3D numpy.ndarray of float32 and returning
+ a float used as iso-level.
+ Example: numpy.mean(data) + numpy.std(data)
+ """
+ assert callable(autoLevel)
+ self._autoLevelFunction = autoLevel
+ self._updateScenePrimitive()
+
+ def getColor(self):
+ """Return the color of this iso-surface (QColor)"""
+ return qt.QColor.fromRgbF(*self._color)
+
+ def setColor(self, color):
+ """Set the color of the iso-surface
+
+ :param color: RGBA color of the isosurface
+ :type color: QColor, str or array-like of 4 float in [0., 1.]
+ """
+ color = rgba(color)
+ if color != self._color:
+ self._color = color
+ primitive = self._getScenePrimitive()
+ if len(primitive.children) != 0:
+ primitive.children[0].setAttribute('color', self._color)
+ self._updated(ItemChangedType.COLOR)
+
+ def _updateScenePrimitive(self):
+ """Update underlying mesh"""
+ self._getScenePrimitive().children = []
+
+ if self._data is None:
+ if self.isAutoLevel():
+ self._level = float('nan')
+
+ else:
+ if self.isAutoLevel():
+ st = time.time()
+ try:
+ level = float(self.getAutoLevelFunction()(self._data))
+
+ except Exception:
+ module_ = self.getAutoLevelFunction().__module__
+ name = self.getAutoLevelFunction().__name__
+ _logger.error(
+ "Error while executing iso level function %s.%s",
+ module_,
+ name,
+ exc_info=True)
+ level = float('nan')
+
+ else:
+ _logger.info(
+ 'Computed iso-level in %f s.', time.time() - st)
+
+ if level != self._level:
+ self._level = level
+ self._updated(Item3DChangedType.ISO_LEVEL)
+
+ if not numpy.isfinite(self._level):
+ return
+
+ st = time.time()
+ vertices, normals, indices = MarchingCubes(
+ self._data,
+ isolevel=self._level)
+ _logger.info('Computed iso-surface in %f s.', time.time() - st)
+
+ if len(vertices) == 0:
+ return
+ else:
+ mesh = primitives.Mesh3D(vertices,
+ colors=self._color,
+ normals=normals,
+ mode='triangles',
+ indices=indices)
+ self._getScenePrimitive().children = [mesh]
+
+
+class ScalarField3D(DataItem3D):
+ """3D scalar field on a regular grid.
+
+ :param parent: The View widget this item belongs to.
+ """
+
+ def __init__(self, parent=None):
+ DataItem3D.__init__(self, parent=parent)
+
+ # Gives this item the shape of the data, no matter
+ # of the isosurface/cut plane size
+ self._boundedGroup = primitives.BoundedGroup()
+
+ # Store iso-surfaces
+ self._isosurfaces = []
+
+ self._data = None
+ self._dataRange = None
+
+ self._cutPlane = CutPlane(parent=self)
+ self._cutPlane.setVisible(False)
+
+ self._isogroup = primitives.GroupDepthOffset()
+ self._isogroup.transforms = [
+ # Convert from z, y, x from marching cubes to x, y, z
+ transform.Matrix((
+ (0., 0., 1., 0.),
+ (0., 1., 0., 0.),
+ (1., 0., 0., 0.),
+ (0., 0., 0., 1.))),
+ # Offset to match cutting plane coords
+ transform.Translate(0.5, 0.5, 0.5)
+ ]
+
+ self._getScenePrimitive().children = [
+ self._boundedGroup,
+ self._cutPlane._getScenePrimitive(),
+ self._isogroup]
+
+ def setData(self, data, copy=True):
+ """Set the 3D scalar data represented by this item.
+
+ Dataset order is zyx (i.e., first dimension is z).
+
+ :param data: 3D array
+ :type data: 3D numpy.ndarray of float32 with shape at least (2, 2, 2)
+ :param bool copy:
+ True (default) to make a copy,
+ False to avoid copy (DO NOT MODIFY data afterwards)
+ """
+ if data is None:
+ self._data = None
+ self._dataRange = None
+ self._boundedGroup.shape = None
+
+ else:
+ data = numpy.array(data, copy=copy, dtype=numpy.float32, order='C')
+ assert data.ndim == 3
+ assert min(data.shape) >= 2
+
+ self._data = data
+
+ # Store data range info
+ dataRange = min_max(self._data, min_positive=True, finite=True)
+ if dataRange.minimum is None: # Only non-finite data
+ dataRange = None
+
+ if dataRange is not None:
+ min_positive = dataRange.min_positive
+ if min_positive is None:
+ min_positive = float('nan')
+ dataRange = dataRange.minimum, min_positive, dataRange.maximum
+ self._dataRange = dataRange
+
+ self._boundedGroup.shape = self._data.shape
+
+ # Update iso-surfaces
+ for isosurface in self.getIsosurfaces():
+ isosurface._setData(self._data, copy=False)
+
+ self._updated(ItemChangedType.DATA)
+
+ def getData(self, copy=True):
+ """Return 3D dataset.
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get the internal data (DO NOT modify!)
+ :return: The data set (or None if not set)
+ """
+ if self._data is None:
+ return None
+ else:
+ return numpy.array(self._data, copy=copy)
+
+ def getDataRange(self):
+ """Return the range of the data as a 3-tuple of values.
+
+ positive min is NaN if no data is positive.
+
+ :return: (min, positive min, max) or None.
+ """
+ return self._dataRange
+
+ # Cut Plane
+
+ def getCutPlanes(self):
+ """Return an iterable of all :class:`CutPlane` of this item.
+
+ This includes hidden cut planes.
+
+ For now, there is always one cut plane.
+ """
+ return (self._cutPlane,)
+
+ # Handle iso-surfaces
+
+ # TODO rename to sigItemAdded|Removed?
+ sigIsosurfaceAdded = qt.Signal(object)
+ """Signal emitted when a new iso-surface is added to the view.
+
+ The newly added iso-surface is provided by this signal
+ """
+
+ sigIsosurfaceRemoved = qt.Signal(object)
+ """Signal emitted when an iso-surface is removed from the view
+
+ The removed iso-surface is provided by this signal.
+ """
+
+ def addIsosurface(self, level, color):
+ """Add an isosurface to this item.
+
+ :param level:
+ The value at which to build the iso-surface or a callable
+ (e.g., a function) taking a 3D numpy.ndarray as input and
+ returning a float.
+ Example: numpy.mean(data) + numpy.std(data)
+ :type level: float or callable
+ :param color: RGBA color of the isosurface
+ :type color: str or array-like of 4 float in [0., 1.]
+ :return: isosurface object
+ :rtype: ~silx.gui.plot3d.items.volume.Isosurface
+ """
+ isosurface = Isosurface(parent=self)
+ isosurface.setColor(color)
+ if callable(level):
+ isosurface.setAutoLevelFunction(level)
+ else:
+ isosurface.setLevel(level)
+ isosurface._setData(self._data, copy=False)
+ isosurface.sigItemChanged.connect(self._isosurfaceItemChanged)
+
+ self._isosurfaces.append(isosurface)
+
+ self._updateIsosurfaces()
+
+ self.sigIsosurfaceAdded.emit(isosurface)
+ return isosurface
+
+ def getIsosurfaces(self):
+ """Return an iterable of all :class:`.Isosurface` instance of this item"""
+ return tuple(self._isosurfaces)
+
+ def removeIsosurface(self, isosurface):
+ """Remove an iso-surface from this item.
+
+ :param ~silx.gui.plot3d.Plot3DWidget.Isosurface isosurface:
+ The isosurface object to remove
+ """
+ if isosurface not in self.getIsosurfaces():
+ _logger.warning(
+ "Try to remove isosurface that is not in the list: %s",
+ str(isosurface))
+ else:
+ isosurface.sigItemChanged.disconnect(self._isosurfaceItemChanged)
+ self._isosurfaces.remove(isosurface)
+ self._updateIsosurfaces()
+ self.sigIsosurfaceRemoved.emit(isosurface)
+
+ def clearIsosurfaces(self):
+ """Remove all :class:`.Isosurface` instances from this item."""
+ for isosurface in self.getIsosurfaces():
+ self.removeIsosurface(isosurface)
+
+ def _isosurfaceItemChanged(self, event):
+ """Handle update of isosurfaces upon level changed"""
+ if event == Item3DChangedType.ISO_LEVEL:
+ self._updateIsosurfaces()
+
+ def _updateIsosurfaces(self):
+ """Handle updates of iso-surfaces level and add/remove"""
+ # Sorting using minus, this supposes data 'object' to be max values
+ sortedIso = sorted(self.getIsosurfaces(),
+ key=lambda isosurface: - isosurface.getLevel())
+ self._isogroup.children = [iso._getScenePrimitive() for iso in sortedIso]
+
+ def visit(self, included=True):
+ """Generator visiting the ScalarField3D content.
+
+ It first access cut planes and then isosurface
+
+ :param bool included: True (default) to include self in visit
+ """
+ if included:
+ yield self
+ for cutPlane in self.getCutPlanes():
+ yield cutPlane
+ for isosurface in self.getIsosurfaces():
+ yield isosurface
diff --git a/silx/gui/plot3d/scene/__init__.py b/silx/gui/plot3d/scene/__init__.py
index 25a7171..9671725 100644
--- a/silx/gui/plot3d/scene/__init__.py
+++ b/silx/gui/plot3d/scene/__init__.py
@@ -29,6 +29,6 @@ __license__ = "MIT"
__date__ = "08/11/2016"
-from .core import Elem, Group, PrivateGroup # noqa
+from .core import Base, Elem, Group, PrivateGroup # noqa
from .viewport import Viewport # noqa
from .window import Window # noqa
diff --git a/silx/gui/plot3d/scene/axes.py b/silx/gui/plot3d/scene/axes.py
index 520ef3e..e35e5e1 100644
--- a/silx/gui/plot3d/scene/axes.py
+++ b/silx/gui/plot3d/scene/axes.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -87,6 +87,23 @@ class LabelledAxes(primitives.GroupBBox):
# Sync color
self.tickColor = 1., 1., 1., 1.
+ def _updateBoxAndAxes(self):
+ """Update bbox and axes position and size according to children.
+
+ Overridden from GroupBBox
+ """
+ super(LabelledAxes, self)._updateBoxAndAxes()
+
+ bounds = self._group.bounds(dataBounds=True)
+ if bounds is not None:
+ tx, ty, tz = (bounds[1] - bounds[0]) / 2.
+ else:
+ tx, ty, tz = 0.5, 0.5, 0.5
+
+ self._xlabel.transforms[-1].tx = tx
+ self._ylabel.transforms[-1].ty = ty
+ self._zlabel.transforms[-1].tz = tz
+
@property
def tickColor(self):
"""Color of ticks and text labels.
diff --git a/silx/gui/plot3d/scene/camera.py b/silx/gui/plot3d/scene/camera.py
index 8cc279d..acc5899 100644
--- a/silx/gui/plot3d/scene/camera.py
+++ b/silx/gui/plot3d/scene/camera.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -252,8 +252,9 @@ class Camera(transform.Transform):
:param float fovy: Vertical field-of-view in degrees.
:param float near: The near clipping plane Z coord (strictly positive).
:param float far: The far clipping plane Z coord (> near).
- :param size: Viewport's size used to compute the aspect ratio.
- :type size: 2-tuple of float (width, height).
+ :param size:
+ Viewport's size used to compute the aspect ratio (width, height).
+ :type size: 2-tuple of float
:param position: Coordinates of the point of view.
:type position: numpy.ndarray-like of 3 float32.
:param direction: Sight direction vector.
diff --git a/silx/gui/plot3d/scene/cutplane.py b/silx/gui/plot3d/scene/cutplane.py
index 79b4168..08a9899 100644
--- a/silx/gui/plot3d/scene/cutplane.py
+++ b/silx/gui/plot3d/scene/cutplane.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -29,7 +29,7 @@ from __future__ import absolute_import, division, unicode_literals
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "05/10/2016"
+__date__ = "11/01/2018"
import string
import numpy
@@ -53,6 +53,7 @@ class ColormapMesh3D(Geometry):
uniform mat4 transformMat;
//uniform mat3 matrixInvTranspose;
uniform vec3 dataScale;
+ uniform vec3 texCoordsOffset;
varying vec4 vCameraPosition;
varying vec3 vPosition;
@@ -64,7 +65,7 @@ class ColormapMesh3D(Geometry):
vCameraPosition = transformMat * vec4(position, 1.0);
//vNormal = matrixInvTranspose * normalize(normal);
vPosition = position;
- vTexCoords = dataScale * position;
+ vTexCoords = dataScale * position + texCoordsOffset;
vNormal = normal;
gl_Position = matrix * vec4(position, 1.0);
}
@@ -113,6 +114,8 @@ class ColormapMesh3D(Geometry):
normal=normal)
self.isBackfaceVisible = True
+ self.textureOffset = 0., 0., 0.
+ """Offset to add to texture coordinates"""
def setData(self, data, copy=True):
data = numpy.array(data, copy=copy, order='C')
@@ -209,6 +212,7 @@ class ColormapMesh3D(Geometry):
shape = self._data.shape
scales = 1./shape[2], 1./shape[1], 1./shape[0]
gl.glUniform3f(program.uniforms['dataScale'], *scales)
+ gl.glUniform3f(program.uniforms['texCoordsOffset'], *self.textureOffset)
gl.glUniform1i(program.uniforms['data'], self._texture.texUnit)
@@ -275,21 +279,13 @@ class CutPlane(PlaneInGroup):
self._interpolation = interpolation
if self._mesh is not None:
self._mesh.interpolation = interpolation
+ self.notify()
def prepareGL2(self, ctx):
if self.isValid:
contourVertices = self.contourVertices
- if (self.interpolation == 'nearest' and
- contourVertices is not None and len(contourVertices)):
- # Avoid cut plane co-linear with array bin edges
- for index, normal in enumerate(((1., 0., 0.), (0., 1., 0.), (0., 0., 1.))):
- if (numpy.all(numpy.equal(self.plane.normal, normal)) and
- int(self.plane.point[index]) == self.plane.point[index]):
- contourVertices += self.plane.normal * 0.01 # Add an offset
- break
-
if self._mesh is None and self._data is not None:
self._mesh = ColormapMesh3D(contourVertices,
normal=self.plane.normal,
@@ -298,7 +294,7 @@ class CutPlane(PlaneInGroup):
mode='fan',
colormap=self.colormap)
self._mesh.alpha = self._alpha
- self._interpolation = self.interpolation
+ self._mesh.interpolation = self.interpolation
self._children.insert(0, self._mesh)
if self._mesh is not None:
@@ -310,6 +306,23 @@ class CutPlane(PlaneInGroup):
self._mesh.setAttribute('normal', self.plane.normal)
self._mesh.setAttribute('position', contourVertices)
+ needTextureOffset = False
+ if self.interpolation == 'nearest':
+ # If cut plane is co-linear with array bin edges add texture offset
+ planePt = self.plane.point
+ for index, normal in enumerate(((1., 0., 0.),
+ (0., 1., 0.),
+ (0., 0., 1.))):
+ if (numpy.all(numpy.equal(self.plane.normal, normal)) and
+ int(planePt[index]) == planePt[index]):
+ needTextureOffset = True
+ break
+
+ if needTextureOffset:
+ self._mesh.textureOffset = self.plane.normal * 1e-6
+ else:
+ self._mesh.textureOffset = 0., 0., 0.
+
super(CutPlane, self).prepareGL2(ctx)
def renderGL2(self, ctx):
@@ -348,10 +361,11 @@ class CutPlane(PlaneInGroup):
return cachevertices
# Cache is not OK, rebuild it
- boxvertices = bounds[0] + Box._vertices.copy()*(bounds[1] - bounds[0])
- lineindices = Box._lineIndices
+ boxVertices = Box.getVertices(copy=True)
+ boxVertices = bounds[0] + boxVertices * (bounds[1] - bounds[0])
+ lineIndices = Box.getLineIndices(copy=False)
vertices = utils.boxPlaneIntersect(
- boxvertices, lineindices, self.plane.normal, self.plane.point)
+ boxVertices, lineIndices, self.plane.normal, self.plane.point)
self._cache = bounds, vertices if len(vertices) != 0 else None
diff --git a/silx/gui/plot3d/scene/function.py b/silx/gui/plot3d/scene/function.py
index 73cdb72..ba4c4ca 100644
--- a/silx/gui/plot3d/scene/function.py
+++ b/silx/gui/plot3d/scene/function.py
@@ -33,6 +33,7 @@ __date__ = "08/11/2016"
import contextlib
import logging
+import string
import numpy
from ... import _glutils
@@ -296,9 +297,8 @@ class DirectionalLight(event.Notifier, ProgramFunction):
class Colormap(event.Notifier, ProgramFunction):
- # TODO use colors for out-of-bound values, for <=0 with log, for nan
- decl = """
+ _declTemplate = string.Template("""
uniform struct {
sampler2D texture;
bool isLog;
@@ -321,9 +321,17 @@ class Colormap(event.Notifier, ProgramFunction):
value = clamp(cmap.oneOverRange * (value - cmap.min), 0.0, 1.0);
}
+ $discard
+
vec4 color = texture2D(cmap.texture, vec2(value, 0.5));
return color;
}
+ """)
+
+ _discardCode = """
+ if (value == 0.) {
+ discard;
+ }
"""
call = "colormap"
@@ -346,7 +354,10 @@ class Colormap(event.Notifier, ProgramFunction):
super(Colormap, self).__init__()
# Init privates to default
- self._colormap, self._norm, self._range = None, 'linear', (1., 10.)
+ self._colormap = None
+ self._norm = 'linear'
+ self._range = 1., 10.
+ self._displayValuesBelowMin = True
self._texture = None
self._update_texture = True
@@ -363,6 +374,12 @@ class Colormap(event.Notifier, ProgramFunction):
self.range_ = range_
@property
+ def decl(self):
+ """Source code of the function declaration"""
+ return self._declTemplate.substitute(
+ discard="" if self.displayValuesBelowMin else self._discardCode)
+
+ @property
def colormap(self):
"""Color look-up table to use."""
return numpy.array(self._colormap, copy=True)
@@ -420,6 +437,19 @@ class Colormap(event.Notifier, ProgramFunction):
self._range = range_
self.notify()
+ @property
+ def displayValuesBelowMin(self):
+ """True to display values below colormap min, False to discard them.
+ """
+ return self._displayValuesBelowMin
+
+ @displayValuesBelowMin.setter
+ def displayValuesBelowMin(self, displayValuesBelowMin):
+ displayValuesBelowMin = bool(displayValuesBelowMin)
+ if self._displayValuesBelowMin != displayValuesBelowMin:
+ self._displayValuesBelowMin = displayValuesBelowMin
+ self.notify()
+
def setupProgram(self, context, program):
"""Sets-up uniforms of a program using this shader function.
diff --git a/silx/gui/plot3d/scene/interaction.py b/silx/gui/plot3d/scene/interaction.py
index 2911b2c..e5cfb6d 100644
--- a/silx/gui/plot3d/scene/interaction.py
+++ b/silx/gui/plot3d/scene/interaction.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +33,7 @@ __date__ = "25/07/2016"
import logging
import numpy
+from silx.gui import qt
from silx.gui.plot.Interaction import \
StateMachine, State, LEFT_BTN, RIGHT_BTN # , MIDDLE_BTN
@@ -380,16 +381,16 @@ class FocusManager(StateMachine):
"""
class Idle(State):
def onPress(self, x, y, btn):
- for eventHandler in self.machine.eventHandlers:
- requestfocus = eventHandler.handleEvent('press', x, y, btn)
- if requestfocus:
+ for eventHandler in self.machine.currentEventHandler:
+ requestFocus = eventHandler.handleEvent('press', x, y, btn)
+ if requestFocus:
self.goto('focus', eventHandler, btn)
break
def _processEvent(self, *args):
- for eventHandler in self.machine.eventHandlers:
- consumeevent = eventHandler.handleEvent(*args)
- if consumeevent:
+ for eventHandler in self.machine.currentEventHandler:
+ consumeEvent = eventHandler.handleEvent(*args)
+ if consumeEvent:
break
def onMove(self, x, y):
@@ -424,8 +425,10 @@ class FocusManager(StateMachine):
def onWheel(self, x, y, angleInDegrees):
self.eventHandler.handleEvent('wheel', x, y, angleInDegrees)
- def __init__(self, eventHandlers=()):
- self.eventHandlers = list(eventHandlers)
+ def __init__(self, eventHandlers=(), ctrlEventHandlers=None):
+ self.defaultEventHandlers = eventHandlers
+ self.ctrlEventHandlers = ctrlEventHandlers
+ self.currentEventHandler = self.defaultEventHandlers
states = {
'idle': FocusManager.Idle,
@@ -433,31 +436,48 @@ class FocusManager(StateMachine):
}
super(FocusManager, self).__init__(states, 'idle')
+ def onKeyPress(self, key):
+ if key == qt.Qt.Key_Control and self.ctrlEventHandlers is not None:
+ self.currentEventHandler = self.ctrlEventHandlers
+
+ def onKeyRelease(self, key):
+ if key == qt.Qt.Key_Control:
+ self.currentEventHandler = self.defaultEventHandlers
+
def cancel(self):
- for handler in self.eventHandlers:
+ for handler in self.currentEventHandler:
handler.cancel()
# CameraControl ###############################################################
class RotateCameraControl(FocusManager):
- """Combine wheel and rotate state machine."""
+ """Combine wheel and rotate state machine for left button
+ and pan when ctrl is pressed
+ """
def __init__(self, viewport,
orbitAroundCenter=False,
- mode='center', scaleTransform=None):
+ mode='center', scaleTransform=None,
+ selectCB=None):
handlers = (CameraWheel(viewport, mode, scaleTransform),
CameraRotate(viewport, orbitAroundCenter, LEFT_BTN))
- super(RotateCameraControl, self).__init__(handlers)
+ ctrlHandlers = (CameraWheel(viewport, mode, scaleTransform),
+ CameraSelectPan(viewport, LEFT_BTN, selectCB))
+ super(RotateCameraControl, self).__init__(handlers, ctrlHandlers)
class PanCameraControl(FocusManager):
- """Combine wheel, selectPan and rotate state machine."""
+ """Combine wheel, selectPan and rotate state machine for left button
+ and rotate when ctrl is pressed"""
def __init__(self, viewport,
+ orbitAroundCenter=False,
mode='center', scaleTransform=None,
selectCB=None):
handlers = (CameraWheel(viewport, mode, scaleTransform),
CameraSelectPan(viewport, LEFT_BTN, selectCB))
- super(PanCameraControl, self).__init__(handlers)
+ ctrlHandlers = (CameraWheel(viewport, mode, scaleTransform),
+ CameraRotate(viewport, orbitAroundCenter, LEFT_BTN))
+ super(PanCameraControl, self).__init__(handlers, ctrlHandlers)
class CameraControl(FocusManager):
@@ -675,7 +695,11 @@ class PanPlaneRotateCameraControl(FocusManager):
class PanPlaneZoomOnWheelControl(FocusManager):
"""Combine zoom on wheel and pan plane state machines."""
def __init__(self, viewport, plane,
- mode='center', scaleTransform=None):
+ mode='center',
+ orbitAroundCenter=False,
+ scaleTransform=None):
handlers = (CameraWheel(viewport, mode, scaleTransform),
PlanePan(viewport, plane, LEFT_BTN))
- super(PanPlaneZoomOnWheelControl, self).__init__(handlers)
+ ctrlHandlers = (CameraWheel(viewport, mode, scaleTransform),
+ CameraRotate(viewport, orbitAroundCenter, LEFT_BTN))
+ super(PanPlaneZoomOnWheelControl, self).__init__(handlers, ctrlHandlers)
diff --git a/silx/gui/plot3d/scene/primitives.py b/silx/gui/plot3d/scene/primitives.py
index fc38e09..abf7dd4 100644
--- a/silx/gui/plot3d/scene/primitives.py
+++ b/silx/gui/plot3d/scene/primitives.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -47,6 +47,7 @@ from . import event
from . import core
from . import transform
from . import utils
+from .function import Colormap
_logger = logging.getLogger(__name__)
@@ -60,6 +61,7 @@ class Geometry(core.Elem):
lines, line_strip, loop, triangles, triangle_strip, fan
:param indices: Array of vertex indices or None
:param bool copy: True (default) to copy the data, False to use as is.
+ :param str attrib0: Name of the attribute that MUST be an array.
:param attributes: Provide list of attributes as extra parameters.
"""
@@ -91,12 +93,21 @@ class Geometry(core.Elem):
_TRIANGLE_MODES = 'triangles', 'triangle_strip', 'fan'
- def __init__(self, mode, indices=None, copy=True, **attributes):
+ def __init__(self,
+ mode,
+ indices=None,
+ copy=True,
+ attrib0='position',
+ **attributes):
super(Geometry, self).__init__()
+ self._attrib0 = str(attrib0)
+
self._vbos = {} # Store current vbos
self._unsyncAttributes = [] # Store attributes to copy to vbos
self.__bounds = None # Cache object's bounds
+ # Attribute names defining the object bounds
+ self.__boundsAttributeNames = (self._attrib0,)
assert mode in self._MODES
self._mode = mode
@@ -116,9 +127,16 @@ class Geometry(core.Elem):
nbvertices = len(self._indices)
else:
nbvertices = self.nbVertices
- assert nbvertices >= mincheck
- if modulocheck != 0:
- assert (nbvertices % modulocheck) == 0
+
+ if nbvertices != 0:
+ assert nbvertices >= mincheck
+ if modulocheck != 0:
+ assert (nbvertices % modulocheck) == 0
+
+ @property
+ def drawMode(self):
+ """Kind of primitive to render, in :attr:`_MODES` (str)"""
+ return self._mode
@staticmethod
def _glReadyArray(array, copy=True):
@@ -134,10 +152,19 @@ class Geometry(core.Elem):
# Makes sure it is an array
array = numpy.array(array, copy=False)
- # Cast all float to float32
dtype = None
- if numpy.dtype(array.dtype).kind == 'f':
+ if array.dtype.kind == 'f' and array.dtype.itemsize != 4:
+ # Cast to float32
+ _logger.info('Cast array to float32')
dtype = numpy.float32
+ elif array.dtype.itemsize > 4:
+ # Cast (u)int64 to (u)int32
+ if array.dtype.kind == 'i':
+ _logger.info('Cast array to int32')
+ dtype = numpy.int32
+ elif array.dtype.kind == 'u':
+ _logger.info('Cast array to uint32')
+ dtype = numpy.uint32
return numpy.array(array, dtype=dtype, order='C', copy=copy)
@@ -152,6 +179,11 @@ class Geometry(core.Elem):
return len(array)
return None
+ @property
+ def attrib0(self):
+ """Attribute name that MUST be an array (str)"""
+ return self._attrib0
+
def setAttribute(self, name, array, copy=True):
"""Set attribute with provided array.
@@ -169,29 +201,33 @@ class Geometry(core.Elem):
array = self._glReadyArray(array, copy=copy)
if name not in self._ATTR_INFO:
- _logger.info('Not checking attibute %s dimensions', name)
+ _logger.info('Not checking attribute %s dimensions', name)
else:
checks = self._ATTR_INFO[name]
- if (len(array.shape) == 1 and checks['lastDim'] == (1,) and
+ if (array.ndim == 1 and checks['lastDim'] == (1,) and
len(array) > 1):
array = array.reshape((len(array), 1))
# Checks
- assert len(array.shape) in checks['dims'], "Attr %s" % name
+ assert array.ndim in checks['dims'], "Attr %s" % name
assert array.shape[-1] in checks['lastDim'], "Attr %s" % name
+ # Makes sure attrib0 is considered as an array of values
+ if name == self.attrib0 and array.ndim == 1:
+ array.shape = 1, -1
+
# Check length against another attribute array
# Causes problems when updating
# nbVertices = self.nbVertices
- # if len(array.shape) == 2 and nbVertices is not None:
+ # if array.ndim == 2 and nbVertices is not None:
# assert len(array) == nbVertices
self._attributes[name] = array
- if len(array.shape) == 2: # Store this in a VBO
+ if array.ndim == 2: # Store this in a VBO
self._unsyncAttributes.append(name)
- if name == 'position': # Reset bounds
+ if name in self.boundsAttributeNames: # Reset bounds
self.__bounds = None
self.notify()
@@ -238,7 +274,7 @@ class Geometry(core.Elem):
array = self._attributes[name]
assert array is not None
- if len(array.shape) == 1:
+ if array.ndim == 1:
assert len(array) in (1, 2, 3, 4)
gl.glDisableVertexAttribArray(attribute)
_glVertexAttribFunc = getattr(
@@ -273,6 +309,7 @@ class Geometry(core.Elem):
# This might be a costy check
assert indices.max() < self.nbVertices
self._indices = indices
+ self.notify()
def getIndices(self, copy=True):
"""Returns the numpy.ndarray corresponding to the indices.
@@ -287,16 +324,59 @@ class Geometry(core.Elem):
else:
return numpy.array(self._indices, copy=copy)
+ @property
+ def boundsAttributeNames(self):
+ """Tuple of attribute names defining the bounds of the object.
+
+ Attributes name are taken in the given order to compute the
+ (x, y, z) the bounding box, e.g.::
+
+ geometry.boundsAttributeNames = 'position'
+ geometry.boundsAttributeNames = 'x', 'y', 'z'
+ """
+ return self.__boundsAttributeNames
+
+ @boundsAttributeNames.setter
+ def boundsAttributeNames(self, names):
+ self.__boundsAttributeNames = tuple(str(name) for name in names)
+ self.__bounds = None
+ self.notify()
+
def _bounds(self, dataBounds=False):
if self.__bounds is None:
+ if len(self.boundsAttributeNames) == 0:
+ return None # No bounds
+
self.__bounds = numpy.zeros((2, 3), dtype=numpy.float32)
- # Support vertex with to 2 to 4 coordinates
- positions = self._attributes['position']
- self.__bounds[0, :positions.shape[1]] = \
- numpy.nanmin(positions, axis=0)[:3]
- self.__bounds[1, :positions.shape[1]] = \
- numpy.nanmax(positions, axis=0)[:3]
+
+ # Coordinates defined in one or more attributes
+ index = 0
+ for name in self.boundsAttributeNames:
+ if index == 3:
+ _logger.error("Too many attributes defining bounds")
+ break
+
+ attribute = self._attributes[name]
+ assert attribute.ndim in (1, 2)
+ if attribute.ndim == 1: # Single value
+ min_ = attribute
+ max_ = attribute
+ else: # Array of values, compute min/max
+ min_ = numpy.nanmin(attribute, axis=0)
+ max_ = numpy.nanmax(attribute, axis=0)
+
+ toCopy = min(len(min_), 3-index)
+ if toCopy != len(min_):
+ _logger.error("Attribute defining bounds"
+ " has too many dimensions")
+
+ self.__bounds[0, index:index+toCopy] = min_[:toCopy]
+ self.__bounds[1, index:index+toCopy] = max_[:toCopy]
+
+ index += toCopy
+
self.__bounds[numpy.isnan(self.__bounds)] = 0. # Avoid NaNs
+
return self.__bounds.copy()
def prepareGL2(self, ctx):
@@ -593,9 +673,7 @@ class Box(core.PrivateGroup):
(0., 0., 1.), (1., 0., 1.), (1., 1., 1.), (0., 1., 1.)),
dtype=numpy.float32)
- def __init__(self, size=(1., 1., 1.),
- stroke=(1., 1., 1., 1.),
- fill=(1., 1., 1., 0.)):
+ def __init__(self, stroke=(1., 1., 1., 1.), fill=(1., 1., 1., 0.)):
super(Box, self).__init__()
self._fill = Mesh3D(self._vertices,
@@ -613,8 +691,27 @@ class Box(core.PrivateGroup):
self._children = [self._stroke, self._fill]
- self._size = None
- self.size = size
+ self._size = 1., 1., 1.
+
+ @classmethod
+ def getLineIndices(cls, copy=True):
+ """Returns 2D array of Box lines indices
+
+ :param copy: True (default) to get a copy,
+ False to get internal array (Do not modify!)
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(cls._lineIndices, copy=copy)
+
+ @classmethod
+ def getVertices(cls, copy=True):
+ """Returns 2D array of Box corner coordinates.
+
+ :param copy: True (default) to get a copy,
+ False to get internal array (Do not modify!)
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(cls._vertices, copy=copy)
@property
def size(self):
@@ -712,6 +809,23 @@ class Axes(Lines):
super(Axes, self).__init__(self._vertices,
colors=self._colors,
width=3.)
+ self._size = 1., 1., 1.
+
+ @property
+ def size(self):
+ """Size of the axes (sx, sy, sz)"""
+ return self._size
+
+ @size.setter
+ def size(self, size):
+ assert len(size) == 3
+ size = tuple(size)
+ if size != self.size:
+ self._size = size
+ self.setAttribute(
+ 'position',
+ self._vertices * numpy.array(size, dtype=numpy.float32))
+ self.notify()
class BoxWithAxes(Lines):
@@ -752,6 +866,7 @@ class BoxWithAxes(Lines):
indices=self._lineIndices,
colors=colors,
width=2.)
+ self._size = 1., 1., 1.
self.color = color
@property
@@ -769,6 +884,22 @@ class BoxWithAxes(Lines):
colors[len(self._axesColors):, :] = self._color
self.setAttribute('color', colors) # Do the notification
+ @property
+ def size(self):
+ """Size of the axes (sx, sy, sz)"""
+ return self._size
+
+ @size.setter
+ def size(self, size):
+ assert len(size) == 3
+ size = tuple(size)
+ if size != self.size:
+ self._size = size
+ self.setAttribute(
+ 'position',
+ self._vertices * numpy.array(size, dtype=numpy.float32))
+ self.notify()
+
class PlaneInGroup(core.PrivateGroup):
"""A plane using its parent bounds to display a contour.
@@ -788,6 +919,7 @@ class PlaneInGroup(core.PrivateGroup):
self._color = None
self.color = 1., 1., 1., 1. # Set _color
self._width = 2.
+ self._strokeVisible = True
self._plane = utils.Plane(point, normal)
self._plane.addListener(self._planeChanged)
@@ -825,6 +957,17 @@ class PlaneInGroup(core.PrivateGroup):
if self._outline is not None:
self._outline.width = self._width # Sync width
+ @property
+ def strokeVisible(self):
+ """Whether surrounding stroke is visible or not (bool)."""
+ return self._strokeVisible
+
+ @strokeVisible.setter
+ def strokeVisible(self, visible):
+ self._strokeVisible = bool(visible)
+ if self._outline is not None:
+ self._outline.visible = self._strokeVisible
+
# Plane access
@property
@@ -865,10 +1008,11 @@ class PlaneInGroup(core.PrivateGroup):
return cachevertices
# Cache is not OK, rebuild it
- boxvertices = bounds[0] + Box._vertices.copy()*(bounds[1] - bounds[0])
- lineindices = Box._lineIndices
+ boxVertices = Box.getVertices(copy=True)
+ boxVertices = bounds[0] + boxVertices * (bounds[1] - bounds[0])
+ lineIndices = Box.getLineIndices(copy=False)
vertices = utils.boxPlaneIntersect(
- boxvertices, lineindices, self.plane.normal, self.plane.point)
+ boxVertices, lineIndices, self.plane.normal, self.plane.point)
self._cache = bounds, vertices if len(vertices) != 0 else None
@@ -894,6 +1038,7 @@ class PlaneInGroup(core.PrivateGroup):
mode='loop',
colors=self.color)
self._outline.width = self._width
+ self._outline.visible = self._strokeVisible
self._children.append(self._outline)
# Update vertices, TODO only when necessary
@@ -906,303 +1051,362 @@ class PlaneInGroup(core.PrivateGroup):
super(PlaneInGroup, self).renderGL2(ctx)
+class BoundedGroup(core.Group):
+ """Group with data bounds"""
+
+ _shape = None # To provide a default value without overriding __init__
+
+ @property
+ def shape(self):
+ """Data shape (depth, height, width) of this group or None"""
+ return self._shape
+
+ @shape.setter
+ def shape(self, shape):
+ if shape is None:
+ self._shape = None
+ else:
+ depth, height, width = shape
+ self._shape = float(depth), float(height), float(width)
+
+ @property
+ def size(self):
+ """Data size (width, height, depth) of this group or None"""
+ shape = self.shape
+ if shape is None:
+ return None
+ else:
+ return shape[2], shape[1], shape[0]
+
+ @size.setter
+ def size(self, size):
+ if size is None:
+ self.shape = None
+ else:
+ self.shape = size[2], size[1], size[0]
+
+ def _bounds(self, dataBounds=False):
+ if dataBounds and self.size is not None:
+ return numpy.array(((0., 0., 0.), self.size),
+ dtype=numpy.float32)
+ else:
+ return super(BoundedGroup, self)._bounds(dataBounds)
+
+
# Points ######################################################################
-_POINTS_ATTR_INFO = Geometry._ATTR_INFO.copy()
-_POINTS_ATTR_INFO.update(value={'dims': (1, 2), 'lastDim': (1,)},
- size={'dims': (1, 2), 'lastDim': (1,)},
- symbol={'dims': (1, 2), 'lastDim': (1,)})
+class _Points(Geometry):
+ """Base class to render a set of points."""
+
+ DIAMOND = 'd'
+ CIRCLE = 'o'
+ SQUARE = 's'
+ PLUS = '+'
+ X_MARKER = 'x'
+ ASTERISK = '*'
+ H_LINE = '_'
+ V_LINE = '|'
+
+ SUPPORTED_MARKERS = (DIAMOND, CIRCLE, SQUARE, PLUS,
+ X_MARKER, ASTERISK, H_LINE, V_LINE)
+ """List of supported markers:
+
+ - 'd' diamond
+ - 'o' circle
+ - 's' square
+ - '+' cross
+ - 'x' x-cross
+ - '*' asterisk
+ - '_' horizontal line
+ - '|' vertical line
+ """
+ _MARKER_FUNCTIONS = {
+ DIAMOND: """
+ float alphaSymbol(vec2 coord, float size) {
+ vec2 centerCoord = abs(coord - vec2(0.5, 0.5));
+ float f = centerCoord.x + centerCoord.y;
+ return clamp(size * (0.5 - f), 0.0, 1.0);
+ }
+ """,
+ CIRCLE: """
+ float alphaSymbol(vec2 coord, float size) {
+ float radius = 0.5;
+ float r = distance(coord, vec2(0.5, 0.5));
+ return clamp(size * (radius - r), 0.0, 1.0);
+ }
+ """,
+ SQUARE: """
+ float alphaSymbol(vec2 coord, float size) {
+ return 1.0;
+ }
+ """,
+ PLUS: """
+ float alphaSymbol(vec2 coord, float size) {
+ vec2 d = abs(size * (coord - vec2(0.5, 0.5)));
+ if (min(d.x, d.y) < 0.5) {
+ return 1.0;
+ } else {
+ return 0.0;
+ }
+ }
+ """,
+ X_MARKER: """
+ float alphaSymbol(vec2 coord, float size) {
+ vec2 pos = floor(size * coord) + 0.5;
+ vec2 d_x = abs(pos.x + vec2(- pos.y, pos.y - size));
+ if (min(d_x.x, d_x.y) <= 0.5) {
+ return 1.0;
+ } else {
+ return 0.0;
+ }
+ }
+ """,
+ ASTERISK: """
+ float alphaSymbol(vec2 coord, float size) {
+ /* Combining +, x and circle */
+ vec2 d_plus = abs(size * (coord - vec2(0.5, 0.5)));
+ vec2 pos = floor(size * coord) + 0.5;
+ vec2 d_x = abs(pos.x + vec2(- pos.y, pos.y - size));
+ if (min(d_plus.x, d_plus.y) < 0.5) {
+ return 1.0;
+ } else if (min(d_x.x, d_x.y) <= 0.5) {
+ float r = distance(coord, vec2(0.5, 0.5));
+ return clamp(size * (0.5 - r), 0.0, 1.0);
+ } else {
+ return 0.0;
+ }
+ }
+ """,
+ H_LINE: """
+ float alphaSymbol(vec2 coord, float size) {
+ float dy = abs(size * (coord.y - 0.5));
+ if (dy < 0.5) {
+ return 1.0;
+ } else {
+ return 0.0;
+ }
+ }
+ """,
+ V_LINE: """
+ float alphaSymbol(vec2 coord, float size) {
+ float dx = abs(size * (coord.x - 0.5));
+ if (dx < 0.5) {
+ return 1.0;
+ } else {
+ return 0.0;
+ }
+ }
+ """
+ }
-class Points(Geometry):
- """A set of data points with an associated value and size."""
- _shaders = ("""
+ _shaders = (string.Template("""
#version 120
- attribute vec3 position;
- attribute float symbol;
- attribute float value;
+ attribute float x;
+ attribute float y;
+ attribute float z;
+ attribute $valueType value;
attribute float size;
uniform mat4 matrix;
uniform mat4 transformMat;
- uniform vec2 valRange;
-
varying vec4 vCameraPosition;
- varying float vSymbol;
- varying float vNormValue;
+ varying $valueType vValue;
varying float vSize;
void main(void)
{
- vSymbol = symbol;
-
- vNormValue = clamp((value - valRange.x) / (valRange.y - valRange.x),
- 0.0, 1.0);
+ vValue = value;
- bool isValueInRange = value >= valRange.x && value <= valRange.y;
- if (isValueInRange) {
- gl_Position = matrix * vec4(position, 1.0);
- } else {
- gl_Position = vec4(2.0, 0.0, 0.0, 1.0); /* Get clipped */
- }
- vCameraPosition = transformMat * vec4(position, 1.0);
+ vec4 positionVec4 = vec4(x, y, z, 1.0);
+ gl_Position = matrix * positionVec4;
+ vCameraPosition = transformMat * positionVec4;
gl_PointSize = size;
vSize = size;
}
- """,
+ """),
string.Template("""
#version 120
varying vec4 vCameraPosition;
varying float vSize;
- varying float vSymbol;
- varying float vNormValue;
-
- $clippinDecl
-
- /* Circle */
- #define SYMBOL_CIRCLE 1.0
+ varying $valueType vValue;
- float alphaCircle(vec2 coord, float size) {
- float radius = 0.5;
- float r = distance(coord, vec2(0.5, 0.5));
- return clamp(size * (radius - r), 0.0, 1.0);
- }
+ $valueToColorDecl
- /* Half lines */
- #define SYMBOL_H_LINE 2.0
- #define LEFT 1.0
- #define RIGHT 2.0
- #define SYMBOL_V_LINE 3.0
- #define UP 1.0
- #define DOWN 2.0
+ $clippingDecl
- float alphaLine(vec2 coord, float size, float direction)
- {
- vec2 delta = abs(size * (coord - 0.5));
-
- if (direction == SYMBOL_H_LINE) {
- return (delta.y < 0.5) ? 1.0 : 0.0;
- }
- else if (direction == SYMBOL_H_LINE + LEFT) {
- return (coord.x <= 0.5 && delta.y < 0.5) ? 1.0 : 0.0;
- }
- else if (direction == SYMBOL_H_LINE + RIGHT) {
- return (coord.x >= 0.5 && delta.y < 0.5) ? 1.0 : 0.0;
- }
- else if (direction == SYMBOL_V_LINE) {
- return (delta.x < 0.5) ? 1.0 : 0.0;
- }
- else if (direction == SYMBOL_V_LINE + UP) {
- return (coord.y <= 0.5 && delta.x < 0.5) ? 1.0 : 0.0;
- }
- else if (direction == SYMBOL_V_LINE + DOWN) {
- return (coord.y >= 0.5 && delta.x < 0.5) ? 1.0 : 0.0;
- }
- return 1.0;
- }
+ $alphaSymbolDecl
void main(void)
{
$clippingCall(vCameraPosition);
- gl_FragColor = vec4(0.5 * vNormValue + 0.5, 0.0, 0.0, 1.0);
-
- float alpha = 1.0;
- float symbol = floor(vSymbol);
- if (1 == 1) { //symbol == SYMBOL_CIRCLE) {
- alpha = alphaCircle(gl_PointCoord, vSize);
- }
- else if (symbol >= SYMBOL_H_LINE &&
- symbol <= (SYMBOL_V_LINE + DOWN)) {
- alpha = alphaLine(gl_PointCoord, vSize, symbol);
- }
+ float alpha = alphaSymbol(gl_PointCoord, vSize);
if (alpha == 0.0) {
discard;
}
+
+ gl_FragColor = $valueToColorCall(vValue);
gl_FragColor.a *= alpha;
}
"""))
- _ATTR_INFO = _POINTS_ATTR_INFO
+ _ATTR_INFO = {
+ 'x': {'dims': (1, 2), 'lastDim': (1,)},
+ 'y': {'dims': (1, 2), 'lastDim': (1,)},
+ 'z': {'dims': (1, 2), 'lastDim': (1,)},
+ 'size': {'dims': (1, 2), 'lastDim': (1,)},
+ }
- # TODO Add colormap, light?
+ def __init__(self, x, y, z, value, size=1., indices=None):
+ super(_Points, self).__init__('points', indices,
+ x=x,
+ y=y,
+ z=z,
+ value=value,
+ size=size,
+ attrib0='x')
+ self.boundsAttributeNames = 'x', 'y', 'z'
+ self._marker = 'o'
- def __init__(self, vertices, values=0., sizes=1., indices=None,
- symbols=0.,
- minValue=None, maxValue=None):
- super(Points, self).__init__('points', indices,
- position=vertices,
- value=values,
- size=sizes,
- symbol=symbols)
+ @property
+ def marker(self):
+ """The marker symbol used to display the scatter plot (str)
- values = self._attributes['value']
- self._minValue = values.min() if minValue is None else minValue
- self._maxValue = values.max() if maxValue is None else maxValue
+ See :attr:`SUPPORTED_MARKERS` for the list of supported marker string.
+ """
+ return self._marker
+
+ @marker.setter
+ def marker(self, marker):
+ marker = str(marker)
+ assert marker in self.SUPPORTED_MARKERS
+ if marker != self._marker:
+ self._marker = marker
+ self.notify()
- minValue = event.notifyProperty('_minValue')
- maxValue = event.notifyProperty('_maxValue')
+ def _shaderValueDefinition(self):
+ """Type definition, fragment shader declaration, fragment shader call
+ """
+ raise NotImplementedError(
+ "This method must be implemented in subclass")
+
+ def _renderGL2PreDrawHook(self, ctx, program):
+ """Override in subclass to run code before calling gl draw"""
+ pass
def renderGL2(self, ctx):
- fragment = self._shaders[1].substitute(
+ valueType, valueToColorDecl, valueToColorCall = \
+ self._shaderValueDefinition()
+ vertexShader = self._shaders[0].substitute(
+ valueType=valueType)
+ fragmentShader = self._shaders[1].substitute(
clippingDecl=ctx.clipper.fragDecl,
- clippingCall=ctx.clipper.fragCall)
- prog = ctx.glCtx.prog(self._shaders[0], fragment)
- prog.use()
+ clippingCall=ctx.clipper.fragCall,
+ valueType=valueType,
+ valueToColorDecl=valueToColorDecl,
+ valueToColorCall=valueToColorCall,
+ alphaSymbolDecl=self._MARKER_FUNCTIONS[self.marker])
+ program = ctx.glCtx.prog(vertexShader, fragmentShader,
+ attrib0=self.attrib0)
+ program.use()
gl.glEnable(gl.GL_VERTEX_PROGRAM_POINT_SIZE) # OpenGL 2
gl.glEnable(gl.GL_POINT_SPRITE) # OpenGL 2
# gl.glEnable(gl.GL_PROGRAM_POINT_SIZE)
- prog.setUniformMatrix('matrix', ctx.objectToNDC.matrix)
- prog.setUniformMatrix('transformMat',
- ctx.objectToCamera.matrix,
- safe=True)
-
- ctx.clipper.setupProgram(ctx, prog)
-
- gl.glUniform2f(prog.uniforms['valRange'], self.minValue, self.maxValue)
-
- self._draw(prog)
-
-
-class ColorPoints(Geometry):
- """A set of points with an associated color and size."""
+ program.setUniformMatrix('matrix', ctx.objectToNDC.matrix)
+ program.setUniformMatrix('transformMat',
+ ctx.objectToCamera.matrix,
+ safe=True)
- _shaders = ("""
- #version 120
+ ctx.clipper.setupProgram(ctx, program)
- attribute vec3 position;
- attribute float symbol;
- attribute vec4 color;
- attribute float size;
+ self._renderGL2PreDrawHook(ctx, program)
- uniform mat4 matrix;
- uniform mat4 transformMat;
+ self._draw(program)
- varying vec4 vCameraPosition;
- varying float vSymbol;
- varying vec4 vColor;
- varying float vSize;
- void main(void)
- {
- vCameraPosition = transformMat * vec4(position, 1.0);
- vSymbol = symbol;
- vColor = color;
- gl_Position = matrix * vec4(position, 1.0);
- gl_PointSize = size;
- vSize = size;
- }
- """,
- string.Template("""
- #version 120
-
- varying vec4 vCameraPosition;
- varying float vSize;
- varying float vSymbol;
- varying vec4 vColor;
+class Points(_Points):
+ """A set of data points with an associated value and size."""
- $clippingDecl;
+ _ATTR_INFO = _Points._ATTR_INFO.copy()
+ _ATTR_INFO.update({'value': {'dims': (1, 2), 'lastDim': (1,)}})
- /* Circle */
- #define SYMBOL_CIRCLE 1.0
+ def __init__(self, x, y, z, value=0., size=1.,
+ indices=None, colormap=None):
+ super(Points, self).__init__(x=x,
+ y=y,
+ z=z,
+ indices=indices,
+ size=size,
+ value=value)
- float alphaCircle(vec2 coord, float size) {
- float radius = 0.5;
- float r = distance(coord, vec2(0.5, 0.5));
- return clamp(size * (radius - r), 0.0, 1.0);
- }
+ self._colormap = colormap or Colormap() # Default colormap
+ self._colormap.addListener(self._cmapChanged)
- /* Half lines */
- #define SYMBOL_H_LINE 2.0
- #define LEFT 1.0
- #define RIGHT 2.0
- #define SYMBOL_V_LINE 3.0
- #define UP 1.0
- #define DOWN 2.0
+ @property
+ def colormap(self):
+ """The colormap used to render the image"""
+ return self._colormap
- float alphaLine(vec2 coord, float size, float direction)
- {
- vec2 delta = abs(size * (coord - 0.5));
+ def _cmapChanged(self, source, *args, **kwargs):
+ """Broadcast colormap changes"""
+ self.notify(*args, **kwargs)
- if (direction == SYMBOL_H_LINE) {
- return (delta.y < 0.5) ? 1.0 : 0.0;
- }
- else if (direction == SYMBOL_H_LINE + LEFT) {
- return (coord.x <= 0.5 && delta.y < 0.5) ? 1.0 : 0.0;
- }
- else if (direction == SYMBOL_H_LINE + RIGHT) {
- return (coord.x >= 0.5 && delta.y < 0.5) ? 1.0 : 0.0;
- }
- else if (direction == SYMBOL_V_LINE) {
- return (delta.x < 0.5) ? 1.0 : 0.0;
- }
- else if (direction == SYMBOL_V_LINE + UP) {
- return (coord.y <= 0.5 && delta.x < 0.5) ? 1.0 : 0.0;
- }
- else if (direction == SYMBOL_V_LINE + DOWN) {
- return (coord.y >= 0.5 && delta.x < 0.5) ? 1.0 : 0.0;
- }
- return 1.0;
- }
+ def _shaderValueDefinition(self):
+ """Type definition, fragment shader declaration, fragment shader call
+ """
+ return 'float', self.colormap.decl, self.colormap.call
- void main(void)
- {
- $clippingCall(vCameraPosition);
+ def _renderGL2PreDrawHook(self, ctx, program):
+ """Set-up colormap before calling gl draw"""
+ self.colormap.setupProgram(ctx, program)
- gl_FragColor = vColor;
- float alpha = 1.0;
- float symbol = floor(vSymbol);
- if (1 == 1) { //symbol == SYMBOL_CIRCLE) {
- alpha = alphaCircle(gl_PointCoord, vSize);
- }
- else if (symbol >= SYMBOL_H_LINE &&
- symbol <= (SYMBOL_V_LINE + DOWN)) {
- alpha = alphaLine(gl_PointCoord, vSize, symbol);
- }
- if (alpha == 0.0) {
- discard;
- }
- gl_FragColor.a *= alpha;
- }
- """))
+class ColorPoints(_Points):
+ """A set of points with an associated color and size."""
- _ATTR_INFO = _POINTS_ATTR_INFO
+ _ATTR_INFO = _Points._ATTR_INFO.copy()
+ _ATTR_INFO.update({'value': {'dims': (1, 2), 'lastDim': (4,)}})
- def __init__(self, vertices, colors=(1., 1., 1., 1.), sizes=1.,
- indices=None, symbols=0.,
- minValue=None, maxValue=None):
- super(ColorPoints, self).__init__('points', indices,
- position=vertices,
- color=colors,
- size=sizes,
- symbol=symbols)
+ def __init__(self, x, y, z, color=(1., 1., 1., 1.), size=1.,
+ indices=None):
+ super(ColorPoints, self).__init__(x=x,
+ y=y,
+ z=z,
+ indices=indices,
+ size=size,
+ value=color)
- def renderGL2(self, ctx):
- fragment = self._shaders[1].substitute(
- clippingDecl=ctx.clipper.fragDecl,
- clippingCall=ctx.clipper.fragCall)
- prog = ctx.glCtx.prog(self._shaders[0], fragment)
- prog.use()
+ def _shaderValueDefinition(self):
+ """Type definition, fragment shader declaration, fragment shader call
+ """
+ return 'vec4', '', ''
- gl.glEnable(gl.GL_VERTEX_PROGRAM_POINT_SIZE) # OpenGL 2
- gl.glEnable(gl.GL_POINT_SPRITE) # OpenGL 2
- # gl.glEnable(gl.GL_PROGRAM_POINT_SIZE)
+ def setColor(self, color, copy=True):
+ """Set colors
- prog.setUniformMatrix('matrix', ctx.objectToNDC.matrix)
- prog.setUniformMatrix('transformMat',
- ctx.objectToCamera.matrix,
- safe=True)
+ :param color: Single RGBA color or
+ 2D array of color of length number of points
+ :param bool copy: True to copy colors (default),
+ False to use provided array (Do not modify!)
+ """
+ self.setAttribute('value', color, copy=copy)
- ctx.clipper.setupProgram(ctx, prog)
+ def getColor(self, copy=True):
+ """Returns the color or array of colors of the points.
- self._draw(prog)
+ :param copy: True to get a copy (default),
+ False to return internal array (Do not modify!)
+ :return: Color or array of colors
+ :rtype: numpy.ndarray
+ """
+ return self.getAttribute('value', copy=copy)
class GridPoints(Geometry):
@@ -1560,12 +1764,14 @@ class Mesh3D(Geometry):
colors,
normals=None,
mode='triangles',
- indices=None):
+ indices=None,
+ copy=True):
assert mode in self._TRIANGLE_MODES
super(Mesh3D, self).__init__(mode, indices,
position=positions,
normal=normals,
- color=colors)
+ color=colors,
+ copy=copy)
self._culling = None
@@ -1620,6 +1826,435 @@ class Mesh3D(Geometry):
gl.glDisable(gl.GL_CULL_FACE)
+class ColormapMesh3D(Geometry):
+ """A 3D mesh with color computed from a colormap"""
+
+ _shaders = ("""
+ attribute vec3 position;
+ attribute vec3 normal;
+ attribute float value;
+
+ uniform mat4 matrix;
+ uniform mat4 transformMat;
+ //uniform mat3 matrixInvTranspose;
+
+ varying vec4 vCameraPosition;
+ varying vec3 vPosition;
+ varying vec3 vNormal;
+ varying float vValue;
+
+ void main(void)
+ {
+ vCameraPosition = transformMat * vec4(position, 1.0);
+ //vNormal = matrixInvTranspose * normalize(normal);
+ vPosition = position;
+ vNormal = normal;
+ vValue = value;
+ gl_Position = matrix * vec4(position, 1.0);
+ }
+ """,
+ string.Template("""
+ varying vec4 vCameraPosition;
+ varying vec3 vPosition;
+ varying vec3 vNormal;
+ varying float vValue;
+
+ $colormapDecl
+ $clippingDecl
+ $lightingFunction
+
+ void main(void)
+ {
+ $clippingCall(vCameraPosition);
+
+ vec4 color = $colormapCall(vValue);
+ gl_FragColor = $lightingCall(color, vPosition, vNormal);
+ }
+ """))
+
+ def __init__(self,
+ position,
+ value,
+ colormap=None,
+ normal=None,
+ mode='triangles',
+ indices=None):
+ super(ColormapMesh3D, self).__init__(mode, indices,
+ position=position,
+ normal=normal,
+ value=value)
+
+ self._lineWidth = 1.0
+ self._lineSmooth = True
+ self._culling = None
+ self._colormap = colormap or Colormap() # Default colormap
+ self._colormap.addListener(self._cmapChanged)
+
+ lineWidth = event.notifyProperty('_lineWidth', converter=float,
+ doc="Width of the line in pixels.")
+
+ lineSmooth = event.notifyProperty(
+ '_lineSmooth',
+ converter=bool,
+ doc="Smooth line rendering enabled (bool, default: True)")
+
+ @property
+ def culling(self):
+ """Face culling (str)
+
+ One of 'back', 'front' or None.
+ """
+ return self._culling
+
+ @culling.setter
+ def culling(self, culling):
+ assert culling in ('back', 'front', None)
+ if culling != self._culling:
+ self._culling = culling
+ self.notify()
+
+ @property
+ def colormap(self):
+ """The colormap used to render the image"""
+ return self._colormap
+
+ def _cmapChanged(self, source, *args, **kwargs):
+ """Broadcast colormap changes"""
+ self.notify(*args, **kwargs)
+
+ def renderGL2(self, ctx):
+ if 'normal' in self._attributes:
+ self._renderGL2(ctx)
+ else: # Disable lighting
+ with self.viewport.light.turnOff():
+ self._renderGL2(ctx)
+
+ def _renderGL2(self, ctx):
+ fragment = self._shaders[1].substitute(
+ clippingDecl=ctx.clipper.fragDecl,
+ clippingCall=ctx.clipper.fragCall,
+ lightingFunction=ctx.viewport.light.fragmentDef,
+ lightingCall=ctx.viewport.light.fragmentCall,
+ colormapDecl=self.colormap.decl,
+ colormapCall=self.colormap.call)
+ program = ctx.glCtx.prog(self._shaders[0], fragment)
+ program.use()
+
+ ctx.viewport.light.setupProgram(ctx, program)
+ ctx.clipper.setupProgram(ctx, program)
+ self.colormap.setupProgram(ctx, program)
+
+ if self.culling is not None:
+ cullFace = gl.GL_FRONT if self.culling == 'front' else gl.GL_BACK
+ gl.glCullFace(cullFace)
+ gl.glEnable(gl.GL_CULL_FACE)
+
+ program.setUniformMatrix('matrix', ctx.objectToNDC.matrix)
+ program.setUniformMatrix('transformMat',
+ ctx.objectToCamera.matrix,
+ safe=True)
+
+ if self.drawMode in self._LINE_MODES:
+ gl.glLineWidth(self.lineWidth)
+ with gl.enabled(gl.GL_LINE_SMOOTH, self.lineSmooth):
+ self._draw(program)
+ else:
+ self._draw(program)
+
+ if self.culling is not None:
+ gl.glDisable(gl.GL_CULL_FACE)
+
+
+# ImageData ##################################################################
+
+class _Image(Geometry):
+ """Base class for ImageData and ImageRgba"""
+
+ _shaders = ("""
+ attribute vec2 position;
+
+ uniform mat4 matrix;
+ uniform mat4 transformMat;
+ uniform vec2 dataScale;
+
+ varying vec4 vCameraPosition;
+ varying vec3 vPosition;
+ varying vec3 vNormal;
+ varying vec2 vTexCoords;
+
+ void main(void)
+ {
+ vec4 positionVec4 = vec4(position, 0.0, 1.0);
+ vCameraPosition = transformMat * positionVec4;
+ vPosition = positionVec4.xyz;
+ vTexCoords = dataScale * position;
+ gl_Position = matrix * positionVec4;
+ }
+ """,
+ string.Template("""
+ varying vec4 vCameraPosition;
+ varying vec3 vPosition;
+ varying vec2 vTexCoords;
+ uniform sampler2D data;
+ uniform float alpha;
+
+ $imageDecl
+
+ $clippingDecl
+
+ $lightingFunction
+
+ void main(void)
+ {
+ vec4 color = imageColor(data, vTexCoords);
+ color.a = alpha;
+
+ $clippingCall(vCameraPosition);
+
+ vec3 normal = vec3(0.0, 0.0, 1.0);
+ gl_FragColor = $lightingCall(color, vPosition, normal);
+ }
+ """))
+
+ _UNIT_SQUARE = numpy.array(((0., 0.), (1., 0.), (0., 1.), (1., 1.)),
+ dtype=numpy.float32)
+
+ def __init__(self, data, copy=True):
+ super(_Image, self).__init__(mode='triangle_strip',
+ position=self._UNIT_SQUARE)
+
+ self._texture = None
+ self._update_texture = True
+ self._update_texture_filter = False
+ self._data = None
+ self.setData(data, copy)
+ self._alpha = 1.
+ self._interpolation = 'linear'
+
+ self.isBackfaceVisible = True
+
+ def setData(self, data, copy=True):
+ assert isinstance(data, numpy.ndarray)
+
+ if copy:
+ data = numpy.array(data, copy=True)
+
+ self._data = data
+ self._update_texture = True
+ # By updating the position rather than always using a unit square
+ # we benefit from Geometry bounds handling
+ self.setAttribute('position', self._UNIT_SQUARE * self._data.shape[:2])
+ self.notify()
+
+ def getData(self, copy=True):
+ return numpy.array(self._data, copy=copy)
+
+ @property
+ def interpolation(self):
+ """The texture interpolation mode: 'linear' or 'nearest'"""
+ return self._interpolation
+
+ @interpolation.setter
+ def interpolation(self, interpolation):
+ assert interpolation in ('linear', 'nearest')
+ self._interpolation = interpolation
+ self._update_texture_filter = True
+ self.notify()
+
+ @property
+ def alpha(self):
+ """Transparency of the image, float in [0, 1]"""
+ return self._alpha
+
+ @alpha.setter
+ def alpha(self, alpha):
+ self._alpha = float(alpha)
+ self.notify()
+
+ def _textureFormat(self):
+ """Implement this method to provide texture internal format and format
+
+ :return: 2-tuple of gl flags (internalFormat, format)
+ """
+ raise NotImplementedError(
+ "This method must be implemented in a subclass")
+
+ def prepareGL2(self, ctx):
+ if self._texture is None or self._update_texture:
+ if self._texture is not None:
+ self._texture.discard()
+
+ if self.interpolation == 'nearest':
+ filter_ = gl.GL_NEAREST
+ else:
+ filter_ = gl.GL_LINEAR
+ self._update_texture = False
+ self._update_texture_filter = False
+ if self._data.size == 0:
+ self._texture = None
+ else:
+ internalFormat, format_ = self._textureFormat()
+ self._texture = _glutils.Texture(
+ internalFormat,
+ self._data,
+ format_,
+ minFilter=filter_,
+ magFilter=filter_,
+ wrap=gl.GL_CLAMP_TO_EDGE)
+
+ if self._update_texture_filter and self._texture is not None:
+ self._update_texture_filter = False
+ if self.interpolation == 'nearest':
+ filter_ = gl.GL_NEAREST
+ else:
+ filter_ = gl.GL_LINEAR
+ self._texture.minFilter = filter_
+ self._texture.magFilter = filter_
+
+ super(_Image, self).prepareGL2(ctx)
+
+ def renderGL2(self, ctx):
+ if self._texture is None:
+ return # Nothing to render
+
+ with self.viewport.light.turnOff():
+ self._renderGL2(ctx)
+
+ def _renderGL2PreDrawHook(self, ctx, program):
+ """Override in subclass to run code before calling gl draw"""
+ pass
+
+ def _shaderImageColorDecl(self):
+ """Returns fragment shader imageColor function declaration"""
+ raise NotImplementedError(
+ "This method must be implemented in a subclass")
+
+ def _renderGL2(self, ctx):
+ fragment = self._shaders[1].substitute(
+ clippingDecl=ctx.clipper.fragDecl,
+ clippingCall=ctx.clipper.fragCall,
+ lightingFunction=ctx.viewport.light.fragmentDef,
+ lightingCall=ctx.viewport.light.fragmentCall,
+ imageDecl=self._shaderImageColorDecl()
+ )
+ program = ctx.glCtx.prog(self._shaders[0], fragment)
+ program.use()
+
+ ctx.viewport.light.setupProgram(ctx, program)
+
+ if not self.isBackfaceVisible:
+ gl.glCullFace(gl.GL_BACK)
+ gl.glEnable(gl.GL_CULL_FACE)
+
+ program.setUniformMatrix('matrix', ctx.objectToNDC.matrix)
+ program.setUniformMatrix('transformMat',
+ ctx.objectToCamera.matrix,
+ safe=True)
+ gl.glUniform1f(program.uniforms['alpha'], self._alpha)
+
+ shape = self._data.shape
+ gl.glUniform2f(program.uniforms['dataScale'], 1./shape[0], 1./shape[1])
+
+ gl.glUniform1i(program.uniforms['data'], self._texture.texUnit)
+
+ ctx.clipper.setupProgram(ctx, program)
+
+ self._texture.bind()
+
+ self._renderGL2PreDrawHook(ctx, program)
+
+ self._draw(program)
+
+ if not self.isBackfaceVisible:
+ gl.glDisable(gl.GL_CULL_FACE)
+
+
+class ImageData(_Image):
+ """Display a 2x2 data array with a texture."""
+
+ _imageDecl = string.Template("""
+ $colormapDecl
+
+ vec4 imageColor(sampler2D data, vec2 texCoords) {
+ float value = texture2D(data, texCoords).r;
+ vec4 color = $colormapCall(value);
+ return color;
+ }
+ """)
+
+ def __init__(self, data, copy=True, colormap=None):
+ super(ImageData, self).__init__(data, copy=copy)
+
+ self._colormap = colormap or Colormap() # Default colormap
+ self._colormap.addListener(self._cmapChanged)
+
+ def setData(self, data, copy=True):
+ data = numpy.array(data, copy=copy, order='C', dtype=numpy.float32)
+ # TODO support (u)int8|16
+ assert data.ndim == 2
+
+ super(ImageData, self).setData(data, copy=False)
+
+ @property
+ def colormap(self):
+ """The colormap used to render the image"""
+ return self._colormap
+
+ def _cmapChanged(self, source, *args, **kwargs):
+ """Broadcast colormap changes"""
+ self.notify(*args, **kwargs)
+
+ def _textureFormat(self):
+ return gl.GL_R32F, gl.GL_RED
+
+ def _renderGL2PreDrawHook(self, ctx, program):
+ self.colormap.setupProgram(ctx, program)
+
+ def _shaderImageColorDecl(self):
+ return self._imageDecl.substitute(
+ colormapDecl=self.colormap.decl,
+ colormapCall=self.colormap.call)
+
+
+# ImageRgba ##################################################################
+
+class ImageRgba(_Image):
+ """Display a 2x2 RGBA image with a texture.
+
+ Supports images of float in [0, 1] and uint8.
+ """
+
+ _imageDecl = """
+ vec4 imageColor(sampler2D data, vec2 texCoords) {
+ vec4 color = texture2D(data, texCoords);
+ return color;
+ }
+ """
+
+ def __init__(self, data, copy=True):
+ super(ImageRgba, self).__init__(data, copy=copy)
+
+ def setData(self, data, copy=True):
+ data = numpy.array(data, copy=copy, order='C')
+ assert data.ndim == 3
+ assert data.shape[2] in (3, 4)
+ if data.dtype.kind == 'f':
+ if data.dtype != numpy.dtype(numpy.float32):
+ _logger.warning("Converting image data to float32")
+ data = numpy.array(data, dtype=numpy.float32, copy=False)
+ else:
+ assert data.dtype == numpy.dtype(numpy.uint8)
+
+ super(ImageRgba, self).setData(data, copy=False)
+
+ def _textureFormat(self):
+ format_ = gl.GL_RGBA if self._data.shape[2] == 4 else gl.GL_RGB
+ return format_, format_
+
+ def _shaderImageColorDecl(self):
+ return self._imageDecl
+
+
# Group ######################################################################
# TODO lighting, clipping as groups?
@@ -1686,6 +2321,29 @@ class GroupDepthOffset(core.Group):
# TODO issue with picking in depth buffer!
+class GroupNoDepth(core.Group):
+ """A group rendering its children without writing to the depth buffer
+
+ :param bool mask: True (default) to disable writing in the depth buffer
+ :param bool notest: True (default) to disable depth test
+ """
+
+ def __init__(self, children=(), mask=True, notest=True):
+ super(GroupNoDepth, self).__init__(children)
+ self._mask = bool(mask)
+ self._notest = bool(notest)
+
+ def renderGL2(self, ctx):
+ if self._mask:
+ gl.glDepthMask(gl.GL_FALSE)
+
+ with gl.disabled(gl.GL_DEPTH_TEST, disable=self._notest):
+ super(GroupNoDepth, self).renderGL2(ctx)
+
+ if self._mask:
+ gl.glDepthMask(gl.GL_TRUE)
+
+
class GroupBBox(core.PrivateGroup):
"""A group displaying a bounding box around the children."""
@@ -1693,26 +2351,42 @@ class GroupBBox(core.PrivateGroup):
super(GroupBBox, self).__init__()
self._group = core.Group(children)
- self._boxTransforms = transform.TransformList(
- (transform.Translate(), transform.Scale()))
+ self._boxTransforms = transform.TransformList((transform.Translate(),))
+ # Using 1 of 3 primitives to render axes and/or bounding box
+ # To avoid z-fighting between axes and bounding box
self._boxWithAxes = BoxWithAxes(color)
self._boxWithAxes.smooth = False
self._boxWithAxes.transforms = self._boxTransforms
- self._children = [self._boxWithAxes, self._group]
+ self._box = Box(stroke=color, fill=(1., 1., 1., 0.))
+ self._box.strokeSmooth = False
+ self._box.transforms = self._boxTransforms
+ self._box.visible = False
+
+ self._axes = Axes()
+ self._axes.smooth = False
+ self._axes.transforms = self._boxTransforms
+ self._axes.visible = False
+
+ self.strokeWidth = 2.
+
+ self._children = [self._boxWithAxes, self._box, self._axes, self._group]
def _updateBoxAndAxes(self):
"""Update bbox and axes position and size according to children."""
bounds = self._group.bounds(dataBounds=True)
if bounds is not None:
origin = bounds[0]
- scale = [(d if d != 0. else 1.) for d in bounds[1] - bounds[0]]
+ size = bounds[1] - bounds[0]
else:
- origin, scale = (0., 0., 0.), (1., 1., 1.)
+ origin, size = (0., 0., 0.), (1., 1., 1.)
self._boxTransforms[0].translation = origin
- self._boxTransforms[1].scale = scale
+
+ self._boxWithAxes.size = size
+ self._box.size = size
+ self._axes.size = size
def _bounds(self, dataBounds=False):
self._updateBoxAndAxes()
@@ -1732,17 +2406,62 @@ class GroupBBox(core.PrivateGroup):
def children(self, iterable):
self._group.children = iterable
- # Give access to box color
+ # Give access to box color and stroke width
@property
def color(self):
"""The RGBA color to use for the box: 4 float in [0, 1]"""
- return self._boxWithAxes.color
+ return self._box.strokeColor
@color.setter
def color(self, color):
+ self._box.strokeColor = color
self._boxWithAxes.color = color
+ @property
+ def strokeWidth(self):
+ """The width of the stroke lines in pixels (float)"""
+ return self._box.strokeWidth
+
+ @strokeWidth.setter
+ def strokeWidth(self, width):
+ width = float(width)
+ self._box.strokeWidth = width
+ self._boxWithAxes.width = width
+ self._axes.width = width
+
+ # Toggle axes visibility
+
+ def _updateBoxAndAxesVisibility(self, axesVisible, boxVisible):
+ """Update visible flags of box and axes primitives accordingly.
+
+ :param bool axesVisible: True to display axes
+ :param bool boxVisible: True to display bounding box
+ """
+ self._boxWithAxes.visible = boxVisible and axesVisible
+ self._box.visible = boxVisible and not axesVisible
+ self._axes.visible = not boxVisible and axesVisible
+
+ @property
+ def axesVisible(self):
+ """Whether axes are displayed or not (bool)"""
+ return self._boxWithAxes.visible or self._axes.visible
+
+ @axesVisible.setter
+ def axesVisible(self, visible):
+ self._updateBoxAndAxesVisibility(axesVisible=bool(visible),
+ boxVisible=self.boxVisible)
+
+ @property
+ def boxVisible(self):
+ """Whether bounding box is displayed or not (bool)"""
+ return self._boxWithAxes.visible or self._box.visible
+
+ @boxVisible.setter
+ def boxVisible(self, visible):
+ self._updateBoxAndAxesVisibility(axesVisible=self.axesVisible,
+ boxVisible=bool(visible))
+
# Clipping Plane ##############################################################
diff --git a/silx/gui/plot3d/scene/test/test_utils.py b/silx/gui/plot3d/scene/test/test_utils.py
index 65c2407..4a2d515 100644
--- a/silx/gui/plot3d/scene/test/test_utils.py
+++ b/silx/gui/plot3d/scene/test/test_utils.py
@@ -27,11 +27,11 @@ from __future__ import absolute_import, division, unicode_literals
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "25/07/2016"
+__date__ = "17/01/2018"
import unittest
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
import numpy
diff --git a/silx/gui/plot3d/scene/transform.py b/silx/gui/plot3d/scene/transform.py
index 71a6b74..4061e81 100644
--- a/silx/gui/plot3d/scene/transform.py
+++ b/silx/gui/plot3d/scene/transform.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -317,7 +317,7 @@ class Transform(event.Notifier):
def transformPoint(self, point, direct=True, perspectiveDivide=False):
"""Apply the transform to a point.
- If len(point) == 3, apply persective divide if possible.
+ If len(point) == 3, apply perspective divide if possible.
:param point: Array-like vector of 3 or 4 coordinates.
:param bool direct: Whether to apply the direct (True, the default)
@@ -757,8 +757,9 @@ class _Projection(Transform):
:param float near: Distance to the near plane.
:param float far: Distance to the far plane.
:param bool checkDepthExtent: Toggle checks near > 0 and far > near.
- :param size: Viewport's size used to compute the aspect ratio.
- :type size: 2-tuple of float (width, height).
+ :param size:
+ Viewport's size used to compute the aspect ratio (width, height).
+ :type size: 2-tuple of float
"""
def __init__(self, near, far, checkDepthExtent=False, size=(1., 1.)):
@@ -833,8 +834,9 @@ class Orthographic(_Projection):
:param float top: Coord of the top clipping plane.
:param float near: Distance to the near plane.
:param float far: Distance to the far plane.
- :param size: Viewport's size used to compute the aspect ratio.
- :type size: 2-tuple of float (width, height).
+ :param size:
+ Viewport's size used to compute the aspect ratio (width, height).
+ :type size: 2-tuple of float
"""
def __init__(self, left=0., right=1., bottom=1., top=0., near=-1., far=1.,
@@ -923,8 +925,9 @@ class Ortho2DWidget(_Projection):
:param float near: Z coordinate of the near clipping plane.
:param float far: Z coordinante of the far clipping plane.
- :param size: Viewport's size used to compute the aspect ratio.
- :type size: 2-tuple of float (width, height).
+ :param size:
+ Viewport's size used to compute the aspect ratio (width, height).
+ :type size: 2-tuple of float
"""
def __init__(self, near=-1., far=1., size=(1., 1.)):
@@ -942,8 +945,9 @@ class Perspective(_Projection):
:param float fovy: Vertical field-of-view in degrees.
:param float near: The near clipping plane Z coord (stricly positive).
:param float far: The far clipping plane Z coord (> near).
- :param size: Viewport's size used to compute the aspect ratio.
- :type size: 2-tuple of float (width, height).
+ :param size:
+ Viewport's size used to compute the aspect ratio (width, height).
+ :type size: 2-tuple of float
"""
def __init__(self, fovy=90., near=0.1, far=1., size=(1., 1.)):
diff --git a/silx/gui/plot3d/scene/utils.py b/silx/gui/plot3d/scene/utils.py
index 930a087..04abd04 100644
--- a/silx/gui/plot3d/scene/utils.py
+++ b/silx/gui/plot3d/scene/utils.py
@@ -184,6 +184,32 @@ def unindexArrays(mode, indices, *arrays):
return tuple(numpy.ascontiguousarray(data[indices]) for data in arrays)
+def triangleStripToTriangles(strip):
+ """Convert a triangle strip to a set of triangles.
+
+ The order of the corners is inverted for odd triangles.
+
+ :param numpy.ndarray strip:
+ Array of triangle corners of shape (N, 3).
+ N must be at least 3.
+ :return: Equivalent triangles corner as an array of shape (N, 3, 3)
+ :rtype: numpy.ndarray
+ """
+ strip = numpy.array(strip).reshape(-1, 3)
+ assert len(strip) >= 3
+
+ triangles = numpy.empty((len(strip) - 2, 3, 3), dtype=strip.dtype)
+ triangles[0::2, 0] = strip[0:-2:2]
+ triangles[0::2, 1] = strip[1:-1:2]
+ triangles[0::2, 2] = strip[2::2]
+
+ triangles[1::2, 0] = strip[3::2]
+ triangles[1::2, 1] = strip[2:-1:2]
+ triangles[1::2, 2] = strip[1:-2:2]
+
+ return triangles
+
+
def trianglesNormal(positions):
"""Return normal for each triangle.
@@ -514,3 +540,19 @@ class Plane(event.Notifier):
def move(self, step):
"""Move the plane of step along the normal."""
self.point += step * self.normal
+
+ def segmentIntersection(self, s0, s1):
+ """Compute the plane intersection with segment [s0, s1].
+
+ :param s0: First end of the segment
+ :type s0: 1D numpy.ndarray-like of length 3
+ :param s1: Second end of the segment
+ :type s1: 1D numpy.ndarray-like of length 3
+ :return: The intersection points. The number of points goes
+ from 0 (no intersection) to 2 (segment in the plane)
+ :rtype: list of 1D numpy.ndarray
+ """
+ if not self.isPlane:
+ return []
+ else:
+ return segmentPlaneIntersect(s0, s1, self.normal, self.point)
diff --git a/silx/gui/plot3d/scene/viewport.py b/silx/gui/plot3d/scene/viewport.py
index 72e1ea3..0cacbf0 100644
--- a/silx/gui/plot3d/scene/viewport.py
+++ b/silx/gui/plot3d/scene/viewport.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -198,12 +198,17 @@ class Viewport(event.Notifier):
@property
def background(self):
- """Background color of the viewport (4-tuple of float in [0, 1]"""
+ """Viewport's background color (4-tuple of float in [0, 1] or None)
+
+ The background color is used to clear to viewport.
+ If None, the viewport is not cleared
+ """
return self._background
@background.setter
def background(self, color):
- color = rgba(color)
+ if color is not None:
+ color = rgba(color)
if self._background != color:
self._background = color
self._changed()
@@ -295,12 +300,16 @@ class Viewport(event.Notifier):
gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST)
gl.glEnable(gl.GL_LINE_SMOOTH)
- gl.glClearColor(*self.background)
+ if self.background is None:
+ gl.glClear(gl.GL_STENCIL_BUFFER_BIT |
+ gl.GL_DEPTH_BUFFER_BIT)
+ else:
+ gl.glClearColor(*self.background)
- # Prepare OpenGL
- gl.glClear(gl.GL_COLOR_BUFFER_BIT |
- gl.GL_STENCIL_BUFFER_BIT |
- gl.GL_DEPTH_BUFFER_BIT)
+ # Prepare OpenGL
+ gl.glClear(gl.GL_COLOR_BUFFER_BIT |
+ gl.GL_STENCIL_BUFFER_BIT |
+ gl.GL_DEPTH_BUFFER_BIT)
ctx = RenderContext(self, glContext)
self.scene.render(ctx)
@@ -454,11 +463,13 @@ class Viewport(event.Notifier):
winy = oy + height * 0.5 * (1. - ndcY)
return winx, winy
- def _pickNdcZGL(self, x, y):
+ def _pickNdcZGL(self, x, y, offset=0):
"""Retrieve depth from depth buffer and return corresponding NDC Z.
:param int x: In pixels in window coordinates, origin left.
:param int y: In pixels in window coordinates, origin top.
+ :param int offset: Number of pixels to look at around the given pixel
+
:return: Normalize device Z coordinate of depth in [-1, 1]
or None if outside viewport.
:rtype: float or None
@@ -476,10 +487,34 @@ class Viewport(event.Notifier):
# Get depth from depth buffer in [0., 1.]
# Bind used framebuffer to get depth
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.framebuffer)
- depth = gl.glReadPixels(
- x, y, 1, 1, gl.GL_DEPTH_COMPONENT, gl.GL_FLOAT)[0]
+
+ if offset == 0: # Fast path
+ # glReadPixels is not GL|ES friendly
+ depth = gl.glReadPixels(
+ x, y, 1, 1, gl.GL_DEPTH_COMPONENT, gl.GL_FLOAT)[0]
+ else:
+ offset = abs(int(offset))
+ size = 2*offset + 1
+ depthPatch = gl.glReadPixels(
+ x - offset, y - offset,
+ size, size,
+ gl.GL_DEPTH_COMPONENT, gl.GL_FLOAT)
+ depthPatch = depthPatch.ravel() # Work in 1D
+
+ # TODO cache sortedIndices to avoid computing it each time
+ # Compute distance of each pixels to the center of the patch
+ offsetToCenter = numpy.arange(- offset, offset + 1, dtype=numpy.float32) ** 2
+ sqDistToCenter = numpy.add.outer(offsetToCenter, offsetToCenter)
+
+ # Use distance to center to sort values from the patch
+ sortedIndices = numpy.argsort(sqDistToCenter.ravel())
+ sortedValues = depthPatch[sortedIndices]
+
+ # Take first depth that is not 1 in the sorted values
+ hits = sortedValues[sortedValues != 1.]
+ depth = 1. if len(hits) == 0 else hits[0]
+
gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
- # This is not GL|ES friendly
# Z in NDC in [-1., 1.]
return float(depth) * 2. - 1.
diff --git a/silx/gui/plot3d/scene/window.py b/silx/gui/plot3d/scene/window.py
index 3c63c7a..baa76a2 100644
--- a/silx/gui/plot3d/scene/window.py
+++ b/silx/gui/plot3d/scene/window.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -124,18 +124,26 @@ class ContextGL2(Context):
# programs
- def prog(self, vertexShaderSrc, fragmentShaderSrc):
+ def prog(self, vertexShaderSrc, fragmentShaderSrc, attrib0='position'):
"""Cache program within context.
WARNING: No clean-up.
+
+ :param str vertexShaderSrc: Vertex shader source code
+ :param str fragmentShaderSrc: Fragment shader source code
+ :param str attrib0:
+ Attribute's name to bind to position 0 (default: 'position').
+ On some platform, this attribute MUST be active and with an
+ array attached to it in order for the rendering to occur....
"""
assert self.isCurrent
- key = vertexShaderSrc, fragmentShaderSrc
- prog = self._programs.get(key, None)
- if prog is None:
- prog = _glutils.Program(vertexShaderSrc, fragmentShaderSrc)
- self._programs[key] = prog
- return prog
+ key = vertexShaderSrc, fragmentShaderSrc, attrib0
+ program = self._programs.get(key, None)
+ if program is None:
+ program = _glutils.Program(
+ vertexShaderSrc, fragmentShaderSrc, attrib0=attrib0)
+ self._programs[key] = program
+ return program
# VBOs
@@ -318,7 +326,8 @@ class Window(event.Notifier):
"""Returns the raster of the scene as an RGB numpy array
:returns: OpenGL scene RGB bitmap
- :rtype: numpy.ndarray of uint8 of dimension (height, width, 3)
+ as an array of dimension (height, width, 3)
+ :rtype: numpy.ndarray of uint8
"""
height, width = self.shape
image = numpy.empty((height, width, 3), dtype=numpy.uint8)
diff --git a/silx/gui/plot3d/setup.py b/silx/gui/plot3d/setup.py
index bb6eaa5..c477919 100644
--- a/silx/gui/plot3d/setup.py
+++ b/silx/gui/plot3d/setup.py
@@ -32,7 +32,9 @@ from numpy.distutils.misc_util import Configuration
def configuration(parent_package='', top_path=None):
config = Configuration('plot3d', parent_package, top_path)
+ config.add_subpackage('_model')
config.add_subpackage('actions')
+ config.add_subpackage('items')
config.add_subpackage('scene')
config.add_subpackage('tools')
config.add_subpackage('test')
diff --git a/silx/gui/plot3d/test/__init__.py b/silx/gui/plot3d/test/__init__.py
index 2e8c9f4..bd2f7c3 100644
--- a/silx/gui/plot3d/test/__init__.py
+++ b/silx/gui/plot3d/test/__init__.py
@@ -26,12 +26,13 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "05/01/2017"
+__date__ = "09/11/2017"
import logging
import os
import unittest
+from silx.test.utils import test_options
_logger = logging.getLogger(__name__)
@@ -40,15 +41,14 @@ _logger = logging.getLogger(__name__)
def suite():
test_suite = unittest.TestSuite()
- if os.environ.get('WITH_GL_TEST', 'True') == 'False':
+ if not test_options.WITH_GL_TEST:
# Explicitly disabled tests
- _logger.warning(
- "silx.gui.plot3d tests disabled (WITH_GL_TEST=False)")
+ msg = "silx.gui.plot3d tests disabled: %s" % test_options.WITH_GL_TEST_REASON
+ _logger.warning(msg)
class SkipPlot3DTest(unittest.TestCase):
def runTest(self):
- self.skipTest(
- "silx.gui.plot3d tests disabled (WITH_GL_TEST=False)")
+ self.skipTest(test_options.WITH_GL_TEST_REASON)
test_suite.addTest(SkipPlot3DTest())
return test_suite
diff --git a/silx/gui/plot3d/test/testScalarFieldView.py b/silx/gui/plot3d/test/testScalarFieldView.py
index 5ad4051..43d401f 100644
--- a/silx/gui/plot3d/test/testScalarFieldView.py
+++ b/silx/gui/plot3d/test/testScalarFieldView.py
@@ -25,7 +25,7 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "11/07/2017"
+__date__ = "17/01/2018"
import logging
@@ -33,7 +33,7 @@ import unittest
import numpy
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
from silx.gui.test.utils import TestCaseQt
from silx.gui import qt
diff --git a/silx/gui/plot3d/tools/GroupPropertiesWidget.py b/silx/gui/plot3d/tools/GroupPropertiesWidget.py
new file mode 100644
index 0000000..30e11de
--- /dev/null
+++ b/silx/gui/plot3d/tools/GroupPropertiesWidget.py
@@ -0,0 +1,200 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+""":class:`GroupPropertiesWidget` allows to reset properties in a GroupItem."""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "11/01/2018"
+
+from ....gui import qt
+from ....gui.plot.Colormap import Colormap
+from ....gui.plot.ColormapDialog import ColormapDialog
+
+from ..items import SymbolMixIn, ColormapMixIn
+
+
+class GroupPropertiesWidget(qt.QWidget):
+ """Set properties of all items in a :class:`GroupItem`
+
+ :param QWidget parent:
+ """
+
+ MAX_MARKER_SIZE = 20
+ """Maximum value for marker size"""
+
+ MAX_LINE_WIDTH = 10
+ """Maximum value for line width"""
+
+ def __init__(self, parent=None):
+ super(GroupPropertiesWidget, self).__init__(parent)
+ self._group = None
+ self.setEnabled(False)
+
+ # Set widgets
+ layout = qt.QFormLayout(self)
+ self.setLayout(layout)
+
+ # Colormap
+ colormapButton = qt.QPushButton('Set...')
+ colormapButton.setToolTip("Set colormap for all items")
+ colormapButton.clicked.connect(self._colormapButtonClicked)
+ layout.addRow('Colormap', colormapButton)
+
+ self._markerComboBox = qt.QComboBox(self)
+ self._markerComboBox.addItems(SymbolMixIn.getSupportedSymbolNames())
+
+ # Marker
+ markerButton = qt.QPushButton('Set')
+ markerButton.setToolTip("Set marker for all items")
+ markerButton.clicked.connect(self._markerButtonClicked)
+
+ markerLayout = qt.QHBoxLayout()
+ markerLayout.setContentsMargins(0, 0, 0, 0)
+ markerLayout.addWidget(self._markerComboBox, 1)
+ markerLayout.addWidget(markerButton, 0)
+
+ layout.addRow('Marker', markerLayout)
+
+ # Marker size
+ self._markerSizeSlider = qt.QSlider()
+ self._markerSizeSlider.setOrientation(qt.Qt.Horizontal)
+ self._markerSizeSlider.setSingleStep(1)
+ self._markerSizeSlider.setRange(1, self.MAX_MARKER_SIZE)
+ self._markerSizeSlider.setValue(1)
+
+ markerSizeButton = qt.QPushButton('Set')
+ markerSizeButton.setToolTip("Set marker size for all items")
+ markerSizeButton.clicked.connect(self._markerSizeButtonClicked)
+
+ markerSizeLayout = qt.QHBoxLayout()
+ markerSizeLayout.setContentsMargins(0, 0, 0, 0)
+ markerSizeLayout.addWidget(qt.QLabel('1'))
+ markerSizeLayout.addWidget(self._markerSizeSlider, 1)
+ markerSizeLayout.addWidget(qt.QLabel(str(self.MAX_MARKER_SIZE)))
+ markerSizeLayout.addWidget(markerSizeButton, 0)
+
+ layout.addRow('Marker Size', markerSizeLayout)
+
+ # Line width
+ self._lineWidthSlider = qt.QSlider()
+ self._lineWidthSlider.setOrientation(qt.Qt.Horizontal)
+ self._lineWidthSlider.setSingleStep(1)
+ self._lineWidthSlider.setRange(1, self.MAX_LINE_WIDTH)
+ self._lineWidthSlider.setValue(1)
+
+ lineWidthButton = qt.QPushButton('Set')
+ lineWidthButton.setToolTip("Set line width for all items")
+ lineWidthButton.clicked.connect(self._lineWidthButtonClicked)
+
+ lineWidthLayout = qt.QHBoxLayout()
+ lineWidthLayout.setContentsMargins(0, 0, 0, 0)
+ lineWidthLayout.addWidget(qt.QLabel('1'))
+ lineWidthLayout.addWidget(self._lineWidthSlider, 1)
+ lineWidthLayout.addWidget(qt.QLabel(str(self.MAX_LINE_WIDTH)))
+ lineWidthLayout.addWidget(lineWidthButton, 0)
+
+ layout.addRow('Line Width', lineWidthLayout)
+
+ self._colormapDialog = None # To store dialog
+ self._colormap = Colormap()
+
+ def getGroup(self):
+ """Returns the :class:`GroupItem` this widget is attached to.
+
+ :rtype: Union[GroupItem, None]
+ """
+ return self._group
+
+ def setGroup(self, group):
+ """Set the :class:`GroupItem` this widget is attached to.
+
+ :param GroupItem group: GroupItem to control (or None)
+ """
+ self._group = group
+ if group is not None:
+ self.setEnabled(True)
+
+ def _colormapButtonClicked(self, checked=False):
+ """Handle colormap button clicked"""
+ group = self.getGroup()
+ if group is None:
+ return
+
+ if self._colormapDialog is None:
+ self._colormapDialog = ColormapDialog(self)
+ self._colormapDialog.setColormap(self._colormap)
+
+ previousColormap = self._colormapDialog.getColormap()
+ if self._colormapDialog.exec_():
+ colormap = self._colormapDialog.getColormap()
+
+ for item in group.visit():
+ if isinstance(item, ColormapMixIn):
+ itemCmap = item.getColormap()
+ cmapName = colormap.getName()
+ if cmapName is not None:
+ itemCmap.setName(colormap.getName())
+ else:
+ itemCmap.setColormapLUT(colormap.getColormapLUT())
+ itemCmap.setNormalization(colormap.getNormalization())
+ itemCmap.setVRange(colormap.getVMin(), colormap.getVMax())
+ else:
+ # Reset colormap
+ self._colormapDialog.setColormap(previousColormap)
+
+ def _markerButtonClicked(self, checked=False):
+ """Handle marker set button clicked"""
+ group = self.getGroup()
+ if group is None:
+ return
+
+ marker = self._markerComboBox.currentText()
+ for item in group.visit():
+ if isinstance(item, SymbolMixIn):
+ item.setSymbol(marker)
+
+ def _markerSizeButtonClicked(self, checked=False):
+ """Handle marker size set button clicked"""
+ group = self.getGroup()
+ if group is None:
+ return
+
+ markerSize = self._markerSizeSlider.value()
+ for item in group.visit():
+ if isinstance(item, SymbolMixIn):
+ item.setSymbolSize(markerSize)
+
+ def _lineWidthButtonClicked(self, checked=False):
+ """Handle line width set button clicked"""
+ group = self.getGroup()
+ if group is None:
+ return
+
+ lineWidth = self._lineWidthSlider.value()
+ for item in group.visit():
+ if hasattr(item, 'setLineWidth'):
+ item.setLineWidth(lineWidth)
diff --git a/silx/gui/plot3d/tools/ViewpointTools.py b/silx/gui/plot3d/tools/ViewpointTools.py
index 1346c1c..0607382 100644
--- a/silx/gui/plot3d/tools/ViewpointTools.py
+++ b/silx/gui/plot3d/tools/ViewpointTools.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -31,105 +31,54 @@ __license__ = "MIT"
__date__ = "08/09/2017"
+import weakref
+
from silx.gui import qt
from silx.gui.icons import getQIcon
-
-
-class _ViewpointActionGroup(qt.QActionGroup):
- """ActionGroup of actions to reset the viewpoint.
-
- As for QActionGroup, add group's actions to the widget with:
- `widget.addActions(actionGroup.actions())`
-
- :param Plot3DWidget plot3D: The widget for which to control the viewpoint
- :param parent: See :class:`QActionGroup`
- """
-
- # Action information: icon name, text, tooltip
- _RESET_CAMERA_ACTIONS = (
- ('cube-front', 'Front', 'View along the -Z axis'),
- ('cube-back', 'Back', 'View along the +Z axis'),
- ('cube-top', 'Top', 'View along the -Y'),
- ('cube-bottom', 'Bottom', 'View along the +Y'),
- ('cube-right', 'Right', 'View along the -X'),
- ('cube-left', 'Left', 'View along the +X'),
- ('cube', 'Side', 'Side view')
- )
-
- def __init__(self, plot3D, parent=None):
- super(_ViewpointActionGroup, self).__init__(parent)
- self.setExclusive(False)
-
- self._plot3D = plot3D
-
- for actionInfo in self._RESET_CAMERA_ACTIONS:
- iconname, text, tooltip = actionInfo
-
- action = qt.QAction(getQIcon(iconname), text, None)
- action.setIconVisibleInMenu(True)
- action.setCheckable(False)
- action.setToolTip(tooltip)
- self.addAction(action)
-
- self.triggered[qt.QAction].connect(self._actionGroupTriggered)
-
- def _actionGroupTriggered(self, action):
- actionname = action.text().lower()
-
- self._plot3D.viewport.camera.extrinsic.reset(face=actionname)
- self._plot3D.centerScene()
-
-
-class ViewpointToolBar(qt.QToolBar):
- """A toolbar providing icons to reset the viewpoint.
-
- :param parent: See :class:`QToolBar`
- :param Plot3DWidget plot3D: The widget to control
- :param str title: Title of the toolbar
- """
-
- def __init__(self, parent=None, plot3D=None, title='Viewpoint control'):
- super(ViewpointToolBar, self).__init__(title, parent)
-
- self._actionGroup = _ViewpointActionGroup(plot3D)
- assert plot3D is not None
- self._plot3D = plot3D
- self.addActions(self._actionGroup.actions())
-
- # Choosing projection disabled for now
- # Add projection combo box
- # comboBoxProjection = qt.QComboBox()
- # comboBoxProjection.addItem('Perspective')
- # comboBoxProjection.addItem('Parallel')
- # comboBoxProjection.setToolTip(
- # 'Choose the projection:'
- # ' perspective or parallel (i.e., orthographic)')
- # comboBoxProjection.currentIndexChanged[(str)].connect(
- # self._comboBoxProjectionCurrentIndexChanged)
- # self.addWidget(qt.QLabel('Projection:'))
- # self.addWidget(comboBoxProjection)
-
- # def _comboBoxProjectionCurrentIndexChanged(self, text):
- # """Projection combo box listener"""
- # self._plot3D.setProjection(
- # 'perspective' if text == 'Perspective' else 'orthographic')
+from .. import actions
class ViewpointToolButton(qt.QToolButton):
"""A toolbutton with a drop-down list of ways to reset the viewpoint.
:param parent: See :class:`QToolButton`
- :param Plot3DWiddget plot3D: The widget to control
"""
- def __init__(self, parent=None, plot3D=None):
+ def __init__(self, parent=None):
super(ViewpointToolButton, self).__init__(parent)
- self._actionGroup = _ViewpointActionGroup(plot3D)
+ self._plot3DRef = None
menu = qt.QMenu(self)
- menu.addActions(self._actionGroup.actions())
+ menu.addAction(actions.viewpoint.FrontViewpointAction(parent=self))
+ menu.addAction(actions.viewpoint.BackViewpointAction(parent=self))
+ menu.addAction(actions.viewpoint.TopViewpointAction(parent=self))
+ menu.addAction(actions.viewpoint.BottomViewpointAction(parent=self))
+ menu.addAction(actions.viewpoint.RightViewpointAction(parent=self))
+ menu.addAction(actions.viewpoint.LeftViewpointAction(parent=self))
+ menu.addAction(actions.viewpoint.SideViewpointAction(parent=self))
+
self.setMenu(menu)
self.setPopupMode(qt.QToolButton.InstantPopup)
self.setIcon(getQIcon('cube'))
self.setToolTip('Reset the viewpoint to a defined position')
+
+ def setPlot3DWidget(self, widget):
+ """Set the Plot3DWidget this toolbar is associated with
+
+ :param ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget widget:
+ The widget to control
+ """
+ self._plot3DRef = None if widget is None else weakref.ref(widget)
+
+ for action in self.menu().actions():
+ action.setPlot3DWidget(widget)
+
+ def getPlot3DWidget(self):
+ """Return the Plot3DWidget associated to this toolbar.
+
+ If no widget is associated, it returns None.
+
+ :rtype: ~silx.gui.plot3d.Plot3DWidget.Plot3DWidget or None
+ """
+ return None if self._plot3DRef is None else self._plot3DRef()
diff --git a/silx/gui/plot3d/tools/__init__.py b/silx/gui/plot3d/tools/__init__.py
index e14f604..c8b8d21 100644
--- a/silx/gui/plot3d/tools/__init__.py
+++ b/silx/gui/plot3d/tools/__init__.py
@@ -28,5 +28,7 @@ __authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "08/09/2017"
-from .toolbars import InteractiveModeToolBar, OutputToolBar
-from .ViewpointTools import ViewpointToolBar, ViewpointToolButton
+from .toolbars import InteractiveModeToolBar # noqa
+from .toolbars import OutputToolBar # noqa
+from .toolbars import ViewpointToolBar # noqa
+from .ViewpointTools import ViewpointToolButton # noqa
diff --git a/silx/gui/plot3d/tools/toolbars.py b/silx/gui/plot3d/tools/toolbars.py
index c8be226..d4f32db 100644
--- a/silx/gui/plot3d/tools/toolbars.py
+++ b/silx/gui/plot3d/tools/toolbars.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -44,40 +44,44 @@ __license__ = "MIT"
__date__ = "06/09/2017"
import logging
+import weakref
from silx.gui import qt
+from .ViewpointTools import ViewpointToolButton
from .. import actions
_logger = logging.getLogger(__name__)
-class InteractiveModeToolBar(qt.QToolBar):
- """Toolbar providing icons to change the interaction mode
+class Plot3DWidgetToolBar(qt.QToolBar):
+ """Base class for toolbar associated to a Plot3DWidget
:param parent: See :class:`QWidget`
:param str title: Title of the toolbar.
"""
- def __init__(self, parent=None, title='Plot3D Interaction'):
- super(InteractiveModeToolBar, self).__init__(title, parent)
+ def __init__(self, parent=None, title=''):
+ super(Plot3DWidgetToolBar, self).__init__(title, parent)
- self._plot3d = None
+ self._plot3DRef = None
- self._rotateAction = actions.mode.RotateArcballAction(parent=self)
- self.addAction(self._rotateAction)
+ def _plot3DWidgetChanged(self, widget):
+ """Handle change of Plot3DWidget and sync actions
- self._panAction = actions.mode.PanAction(parent=self)
- self.addAction(self._panAction)
+ :param Plot3DWidget widget:
+ """
+ for action in self.actions():
+ if isinstance(action, actions.Plot3DAction):
+ action.setPlot3DWidget(widget)
def setPlot3DWidget(self, widget):
"""Set the Plot3DWidget this toolbar is associated with
- :param Plot3DWidget widget: The widget to copy/save/print
+ :param Plot3DWidget widget: The widget to control
"""
- self._plot3d = widget
- self.getRotateAction().setPlot3DWidget(widget)
- self.getPanAction().setPlot3DWidget(widget)
+ self._plot3DRef = None if widget is None else weakref.ref(widget)
+ self._plot3DWidgetChanged(widget)
def getPlot3DWidget(self):
"""Return the Plot3DWidget associated to this toolbar.
@@ -86,7 +90,24 @@ class InteractiveModeToolBar(qt.QToolBar):
:rtype: qt.QWidget
"""
- return self._plot3d
+ return None if self._plot3DRef is None else self._plot3DRef()
+
+
+class InteractiveModeToolBar(Plot3DWidgetToolBar):
+ """Toolbar providing icons to change the interaction mode
+
+ :param parent: See :class:`QWidget`
+ :param str title: Title of the toolbar.
+ """
+
+ def __init__(self, parent=None, title='Plot3D Interaction'):
+ super(InteractiveModeToolBar, self).__init__(parent, title)
+
+ self._rotateAction = actions.mode.RotateArcballAction(parent=self)
+ self.addAction(self._rotateAction)
+
+ self._panAction = actions.mode.PanAction(parent=self)
+ self.addAction(self._panAction)
def getRotateAction(self):
"""Returns the QAction setting rotate interaction of the Plot3DWidget
@@ -103,7 +124,7 @@ class InteractiveModeToolBar(qt.QToolBar):
return self._panAction
-class OutputToolBar(qt.QToolBar):
+class OutputToolBar(Plot3DWidgetToolBar):
"""Toolbar providing icons to copy, save and print the OpenGL scene
:param parent: See :class:`QWidget`
@@ -111,9 +132,7 @@ class OutputToolBar(qt.QToolBar):
"""
def __init__(self, parent=None, title='Plot3D Output'):
- super(OutputToolBar, self).__init__(title, parent)
-
- self._plot3d = None
+ super(OutputToolBar, self).__init__(parent, title)
self._copyAction = actions.io.CopyAction(parent=self)
self.addAction(self._copyAction)
@@ -127,26 +146,6 @@ class OutputToolBar(qt.QToolBar):
self._printAction = actions.io.PrintAction(parent=self)
self.addAction(self._printAction)
- def setPlot3DWidget(self, widget):
- """Set the Plot3DWidget this toolbar is associated with
-
- :param Plot3DWidget widget: The widget to copy/save/print
- """
- self._plot3d = widget
- self.getCopyAction().setPlot3DWidget(widget)
- self.getSaveAction().setPlot3DWidget(widget)
- self.getVideoRecordAction().setPlot3DWidget(widget)
- self.getPrintAction().setPlot3DWidget(widget)
-
- def getPlot3DWidget(self):
- """Return the Plot3DWidget associated to this toolbar.
-
- If no widget is associated, it returns None.
-
- :rtype: qt.QWidget
- """
- return self._plot3d
-
def getCopyAction(self):
"""Returns the QAction performing copy to clipboard of the Plot3DWidget
@@ -174,3 +173,37 @@ class OutputToolBar(qt.QToolBar):
:rtype: qt.QAction
"""
return self._printAction
+
+
+class ViewpointToolBar(Plot3DWidgetToolBar):
+ """A toolbar providing icons to reset the viewpoint.
+
+ :param parent: See :class:`QToolBar`
+ :param str title: Title of the toolbar
+ """
+
+ def __init__(self, parent=None, title='Viewpoint control'):
+ super(ViewpointToolBar, self).__init__(parent, title)
+
+ self._viewpointToolButton = ViewpointToolButton(parent=self)
+ self.addWidget(self._viewpointToolButton)
+ self._rotateViewpointAction = actions.viewpoint.RotateViewpoint(parent=self)
+ self.addAction(self._rotateViewpointAction)
+
+ def _plot3DWidgetChanged(self, widget):
+ self.getViewpointToolButton().setPlot3DWidget(widget)
+ super(ViewpointToolBar, self)._plot3DWidgetChanged(widget)
+
+ def getViewpointToolButton(self):
+ """Returns the ViewpointToolButton to set viewpoint of the Plot3DWidget
+
+ :rtype: ViewpointToolButton
+ """
+ return self._viewpointToolButton
+
+ def getRotateViewpointAction(self):
+ """Returns the QAction to start/stop rotation of the Plot3DWidget
+
+ :rtype: qt.QAction
+ """
+ return self._rotateViewpointAction
diff --git a/silx/gui/qt/_qt.py b/silx/gui/qt/_qt.py
index 0962c21..a54ea67 100644
--- a/silx/gui/qt/_qt.py
+++ b/silx/gui/qt/_qt.py
@@ -29,18 +29,18 @@
- `PySide <http://www.pyside.org>`_.
If a Qt binding is already loaded, it will use it, otherwise the different
-Qt bindings are tried in this order: PyQt4, PySide, PyQt5.
+Qt bindings are tried in this order: PySide2, PyQt4, PySide, PyQt5.
The name of the loaded Qt binding is stored in the BINDING variable.
For an alternative solution providing a structured namespace,
see `qtpy <https://pypi.python.org/pypi/QtPy/>`_ which
-provides the namespace of PyQt5 over PyQt4 and PySide.
+provides the namespace of PyQt5 over PyQt4, PySide and PySide2.
"""
-__authors__ = ["V.A. Sole - ESRF Data Analysis"]
+__authors__ = ["V.A. Sole"]
__license__ = "MIT"
-__date__ = "17/01/2017"
+__date__ = "11/10/2017"
import logging
@@ -52,10 +52,10 @@ _logger = logging.getLogger(__name__)
BINDING = None
-"""The name of the Qt binding in use: 'PyQt5', 'PyQt4' or 'PySide'."""
+"""The name of the Qt binding in use: PyQt5, 'PyQt4, PySide2 or PySide."""
QtBinding = None # noqa
-"""The Qt binding module in use: PyQt5, PyQt4 or PySide."""
+"""The Qt binding module in use: PyQt5, PyQt4, PySide2 or PySide."""
HAS_SVG = False
"""True if Qt provides support for Scalable Vector Graphics (QtSVG)."""
@@ -64,7 +64,10 @@ HAS_OPENGL = False
"""True if Qt provides support for OpenGL (QtOpenGL)."""
# First check for an already loaded wrapper
-if 'PySide.QtCore' in sys.modules:
+if 'PySide2.QtCore' in sys.modules:
+ BINDING = 'PySide2'
+
+elif 'PySide.QtCore' in sys.modules:
BINDING = 'PySide'
elif 'PyQt5.QtCore' in sys.modules:
@@ -83,8 +86,13 @@ else: # Then try Qt bindings
try:
import PyQt5 # noqa
except ImportError:
- raise ImportError(
- 'No Qt wrapper found. Install PyQt4, PyQt5 or PySide.')
+ try:
+ import PySide2 # noqa
+ except ImportError:
+ raise ImportError(
+ 'No Qt wrapper found. Install PyQt4, PyQt5 or PySide2.')
+ else:
+ BINDING = 'PySide2'
else:
BINDING = 'PyQt5'
else:
@@ -96,7 +104,7 @@ else: # Then try Qt bindings
if BINDING == 'PyQt4':
_logger.debug('Using PyQt4 bindings')
- if sys.version < "3.0.0":
+ if sys.version_info < (3, ):
try:
import sip
@@ -201,8 +209,42 @@ elif BINDING == 'PyQt5':
Slot = pyqtSlot
+elif BINDING == 'PySide2':
+ _logger.debug('Using PySide2 bindings')
+ _logger.warning(
+ 'Using PySide2 Qt binding: PySide2 support in silx is experimental!')
+
+ import PySide2 as QtBinding # noqa
+
+ from PySide2.QtCore import * # noqa
+ from PySide2.QtGui import * # noqa
+ from PySide2.QtWidgets import * # noqa
+ from PySide2.QtPrintSupport import * # noqa
+
+ try:
+ from PySide2.QtOpenGL import * # noqa
+ except ImportError:
+ _logger.info("PySide2.QtOpenGL not available")
+ HAS_OPENGL = False
+ else:
+ HAS_OPENGL = True
+
+ try:
+ from PySide2.QtSvg import * # noqa
+ except ImportError:
+ _logger.info("PySide2.QtSvg not available")
+ HAS_SVG = False
+ else:
+ HAS_SVG = True
+
+ # Import loadUi wrapper for PySide2
+ # TODO from ._pyside_dynamic import loadUi # noqa
+
+ pyqtSignal = Signal
+
else:
- raise ImportError('No Qt wrapper found. Install PyQt4, PyQt5 or PySide')
+ raise ImportError('No Qt wrapper found. Install PyQt4, PyQt5, PySide2')
+
# provide a exception handler but not implement it by default
def exceptionHandler(type_, value, trace):
diff --git a/silx/gui/qt/_utils.py b/silx/gui/qt/_utils.py
index 0aa3ef1..be55465 100644
--- a/silx/gui/qt/_utils.py
+++ b/silx/gui/qt/_utils.py
@@ -30,15 +30,34 @@ __license__ = "MIT"
__date__ = "30/11/2016"
import sys
-from ._qt import BINDING, QImageReader
+from . import _qt as qt
def supportedImageFormats():
"""Return a set of string of file format extensions supported by the
Qt runtime."""
- if sys.version_info[0] < 3 or BINDING == 'PySide':
+ if sys.version_info[0] < 3 or qt.BINDING in ('PySide', 'PySide2'):
convert = str
else:
convert = lambda data: str(data, 'ascii')
- formats = QImageReader.supportedImageFormats()
+ formats = qt.QImageReader.supportedImageFormats()
return set([convert(data) for data in formats])
+
+
+__globalThreadPoolInstance = None
+"""Store the own silx global thread pool"""
+
+
+def silxGlobalThreadPool():
+ """"Manage an own QThreadPool to avoid issue on Qt5 Windows with the
+ default Qt global thread pool.
+
+ :rtype: qt.QThreadPool
+ """
+ global __globalThreadPoolInstance
+ if __globalThreadPoolInstance is None:
+ tp = qt.QThreadPool()
+ # This pointless command fixes a segfault with PyQt 5.9.1 on Windows
+ tp.setMaxThreadCount(tp.maxThreadCount())
+ __globalThreadPoolInstance = tp
+ return __globalThreadPoolInstance
diff --git a/silx/gui/setup.py b/silx/gui/setup.py
index 163cabf..8e8c796 100644
--- a/silx/gui/setup.py
+++ b/silx/gui/setup.py
@@ -24,7 +24,7 @@
# ###########################################################################*/
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "04/05/2017"
+__date__ = "28/11/2017"
from numpy.distutils.misc_util import Configuration
@@ -41,6 +41,7 @@ def configuration(parent_package='', top_path=None):
config.add_subpackage('test')
config.add_subpackage('plot3d')
config.add_subpackage('data')
+ config.add_subpackage('dialog')
return config
diff --git a/silx/gui/test/__init__.py b/silx/gui/test/__init__.py
index 7449860..0d0805f 100644
--- a/silx/gui/test/__init__.py
+++ b/silx/gui/test/__init__.py
@@ -24,13 +24,14 @@
# ###########################################################################*/
__authors__ = ["T. Vincent", "P. Knobel"]
__license__ = "MIT"
-__date__ = "05/01/2017"
+__date__ = "28/11/2017"
import logging
import os
import sys
import unittest
+from silx.test.utils import test_options
_logger = logging.getLogger(__name__)
@@ -52,15 +53,14 @@ def suite():
test_suite.addTest(SkipGUITest())
return test_suite
- elif os.environ.get('WITH_QT_TEST', 'True') == 'False':
+ elif not test_options.WITH_QT_TEST:
# Explicitly disabled tests
- _logger.warning(
- "silx.gui tests disabled (env. variable WITH_QT_TEST=False)")
+ msg = "silx.gui tests disabled: %s" % test_options.WITH_QT_TEST_REASON
+ _logger.warning(msg)
class SkipGUITest(unittest.TestCase):
def runTest(self):
- self.skipTest(
- "silx.gui tests disabled (env. variable WITH_QT_TEST=False)")
+ self.skipTest(test_options.WITH_QT_TEST_REASON)
test_suite.addTest(SkipGUITest())
return test_suite
@@ -72,6 +72,7 @@ def suite():
from ..hdf5 import test as test_hdf5
from ..widgets import test as test_widgets
from ..data import test as test_data
+ from ..dialog import test as test_dialog
from . import test_qt
# Console tests disabled due to corruption of python environment
# (see issue #538 on github)
@@ -94,7 +95,6 @@ def suite():
test_plot3d_suite = SkipPlot3DTest
-
test_suite.addTest(test_qt.suite())
test_suite.addTest(test_plot.suite())
test_suite.addTest(test_fit.suite())
@@ -105,4 +105,5 @@ def suite():
test_suite.addTest(test_data.suite())
test_suite.addTest(test_utils.suite())
test_suite.addTest(test_plot3d_suite())
+ test_suite.addTest(test_dialog.suite())
return test_suite
diff --git a/silx/gui/test/test_utils.py b/silx/gui/test/test_utils.py
index 4625969..b1cdf0f 100644
--- a/silx/gui/test/test_utils.py
+++ b/silx/gui/test/test_utils.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -29,10 +29,12 @@ __license__ = "MIT"
__date__ = "16/01/2017"
+import threading
import unittest
import numpy
+from silx.third_party.concurrent_futures import wait
from silx.gui import qt
from silx.gui.test.utils import TestCaseQt
@@ -66,10 +68,97 @@ class TestQImageConversion(TestCaseQt):
self.assertTrue(numpy.all(numpy.equal(image, 1)))
+class TestSubmitToQtThread(TestCaseQt):
+ """Test submission of tasks to Qt main thread"""
+
+ def setUp(self):
+ # Reset executor to test lazy-loading in different conditions
+ _utils._executor = None
+ super(TestSubmitToQtThread, self).setUp()
+
+ def _task(self, value1, value2):
+ return value1, value2
+
+ def _taskWithException(self, *args, **kwargs):
+ raise RuntimeError('task exception')
+
+ def testFromMainThread(self):
+ """Call submitToQtMainThread from the main thread"""
+ value1, value2 = 0, 1
+ future = _utils.submitToQtMainThread(self._task, value1, value2=value2)
+ self.assertTrue(future.done())
+ self.assertEqual(future.result(1), (value1, value2))
+ self.assertIsNone(future.exception(1))
+
+ future = _utils.submitToQtMainThread(self._taskWithException)
+ self.assertTrue(future.done())
+ with self.assertRaises(RuntimeError):
+ future.result(1)
+ self.assertIsInstance(future.exception(1), RuntimeError)
+
+ def _threadedTest(self):
+ """Function run in a thread for the tests"""
+ value1, value2 = 0, 1
+ future = _utils.submitToQtMainThread(self._task, value1, value2=value2)
+
+ wait([future], 3)
+
+ self.assertTrue(future.done())
+ self.assertEqual(future.result(1), (value1, value2))
+ self.assertIsNone(future.exception(1))
+
+ future = _utils.submitToQtMainThread(self._taskWithException)
+
+ wait([future], 3)
+
+ self.assertTrue(future.done())
+ with self.assertRaises(RuntimeError):
+ future.result(1)
+ self.assertIsInstance(future.exception(1), RuntimeError)
+
+ def testFromPythonThread(self):
+ """Call submitToQtMainThread from a Python thread"""
+ thread = threading.Thread(target=self._threadedTest)
+ thread.start()
+ for i in range(100): # Loop over for 10 seconds
+ self.qapp.processEvents()
+ thread.join(0.1)
+ if not thread.is_alive():
+ break
+ else:
+ self.fail(('Thread task still running'))
+
+ def testFromQtThread(self):
+ """Call submitToQtMainThread from a Qt thread pool"""
+ class Runner(qt.QRunnable):
+ def __init__(self, fn):
+ super(Runner, self).__init__()
+ self._fn = fn
+
+ def run(self):
+ self._fn()
+
+ def autoDelete(self):
+ return True
+
+ threadPool = qt.silxGlobalThreadPool()
+ runner = Runner(self._threadedTest)
+ threadPool.start(runner)
+ for i in range(100): # Loop over for 10 seconds
+ self.qapp.processEvents()
+ done = threadPool.waitForDone(100)
+ if done:
+ break
+ else:
+ self.fail('Thread pool task still running')
+
+
def suite():
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(
TestQImageConversion))
+ test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(
+ TestSubmitToQtThread))
return test_suite
diff --git a/silx/gui/test/utils.py b/silx/gui/test/utils.py
index 19c448a..3eee474 100644
--- a/silx/gui/test/utils.py
+++ b/silx/gui/test/utils.py
@@ -26,7 +26,7 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "01/09/2017"
+__date__ = "27/02/2018"
import gc
@@ -43,6 +43,8 @@ from silx.gui import qt
if qt.BINDING == 'PySide':
from PySide.QtTest import QTest
+elif qt.BINDING == 'PySide2':
+ from PySide2.QtTest import QTest
elif qt.BINDING == 'PyQt5':
from PyQt5.QtTest import QTest
elif qt.BINDING == 'PyQt4':
@@ -137,11 +139,9 @@ class TestCaseQt(unittest.TestCase):
# Makes sure a QApplication exists and do it once for all
_qapp = qt.QApplication.instance() or qt.QApplication([])
- # Create/delate a QWidget to make sure init of QDesktopWidget
- _dummyWidget = qt.QWidget()
- _dummyWidget.setAttribute(qt.Qt.WA_DeleteOnClose)
- _dummyWidget.show()
- _dummyWidget.close()
+ # Makes sure QDesktopWidget is init
+ # Otherwise it happens randomly during the tests
+ cls._desktopWidget = _qapp.desktop()
_qapp.processEvents()
@classmethod
@@ -163,9 +163,10 @@ class TestCaseQt(unittest.TestCase):
# For Python < 3.4
result = getattr(self, '_outcomeForDoCleanups', self._resultForDoCleanups)
+ skipped = self.id() in [case.id() for case, _ in result.skipped]
error = self.id() in [case.id() for case, _ in result.errors]
failure = self.id() in [case.id() for case, _ in result.failures]
- return not error and not failure
+ return not error and not failure and not skipped
def _checkForUnreleasedWidgets(self):
"""Test fixture checking that no more widgets exists."""
@@ -175,7 +176,7 @@ class TestCaseQt(unittest.TestCase):
if widget not in self.__previousWidgets]
del self.__previousWidgets
- if qt.BINDING == 'PySide':
+ if qt.BINDING in ('PySide', 'PySide2'):
return # Do not test for leaking widgets with PySide
allowedLeakingWidgets = self.allowedLeakingWidgets
@@ -318,24 +319,25 @@ class TestCaseQt(unittest.TestCase):
"""
QTest.qSleep(ms + self.TIMEOUT_WAIT)
- def qWait(self, ms=None):
+ @classmethod
+ def qWait(cls, ms=None):
"""Waits for ms milliseconds, events will be processed.
See QTest.qWait for details.
"""
if ms is None:
- ms = self.DEFAULT_TIMEOUT_WAIT
+ ms = cls.DEFAULT_TIMEOUT_WAIT
if qt.BINDING == 'PySide':
# PySide has no qWait, provide a replacement
timeout = int(ms)
endTimeMS = int(time.time() * 1000) + timeout
while timeout > 0:
- self.qapp.processEvents(qt.QEventLoop.AllEvents,
+ _qapp.processEvents(qt.QEventLoop.AllEvents,
maxtime=timeout)
timeout = endTimeMS - int(time.time() * 1000)
else:
- QTest.qWait(ms + self.TIMEOUT_WAIT)
+ QTest.qWait(ms + cls.TIMEOUT_WAIT)
def qWaitForWindowExposed(self, window, timeout=None):
"""Waits until the window is shown in the screen.
@@ -349,6 +351,57 @@ class TestCaseQt(unittest.TestCase):
return result
+ _qobject_destroyed = False
+
+ @classmethod
+ def _aboutToDestroy(cls):
+ cls._qobject_destroyed = True
+
+ @classmethod
+ def qWaitForDestroy(cls, ref):
+ """
+ Wait for Qt object destruction.
+
+ Use a weakref as parameter to avoid any strong references to the
+ object.
+
+ It have to be used as following. Removing the reference to the object
+ before calling the function looks to be expected, else
+ :meth:`deleteLater` will not work.
+
+ .. code-block:: python
+
+ ref = weakref.ref(self.obj)
+ self.obj = None
+ self.qWaitForDestroy(ref)
+
+ :param weakref ref: A weakref to an object to avoid any reference
+ :return: True if the object was destroyed
+ :rtype: bool
+ """
+ cls._qobject_destroyed = False
+ if qt.BINDING == 'PyQt4':
+ # Without this, QWidget will be still alive on PyQt4
+ # (at least on Windows Python 2.7)
+ # If it is not skipped on PySide, silx.gui.dialog tests will
+ # segfault (at least on Windows Python 2.7)
+ import gc
+ gc.collect()
+ qobject = ref()
+ if qobject is None:
+ return True
+ qobject.destroyed.connect(cls._aboutToDestroy)
+ qobject.deleteLater()
+ qobject = None
+ for _ in range(10):
+ if cls._qobject_destroyed:
+ break
+ cls.qWait(10)
+ else:
+ _logger.debug("Object was not destroyed")
+
+ return ref() is None
+
def logScreenShot(self, level=logging.ERROR):
"""Take a screenshot and log it into the logging system if the
logger is enabled for the expected level.
@@ -454,3 +507,14 @@ def getQToolButtonFromAction(action):
if isinstance(widget, qt.QToolButton):
return widget
return None
+
+
+def findChildren(parent, kind, name=None):
+ if qt.BINDING == "PySide" and name is not None:
+ result = []
+ for obj in parent.findChildren(kind):
+ if obj.objectName() == name:
+ result.append(obj)
+ return result
+ else:
+ return parent.findChildren(kind, name=name)
diff --git a/silx/gui/widgets/FrameBrowser.py b/silx/gui/widgets/FrameBrowser.py
index 6737e9c..a8c0349 100644
--- a/silx/gui/widgets/FrameBrowser.py
+++ b/silx/gui/widgets/FrameBrowser.py
@@ -229,8 +229,6 @@ class HorizontalSliderWithBrowser(qt.QAbstractSlider):
:param QWidget parent: Optional parent widget
"""
- sigIndexChanged = qt.pyqtSignal(object)
-
def __init__(self, parent=None):
qt.QAbstractSlider.__init__(self, parent)
self.setOrientation(qt.Qt.Horizontal)
diff --git a/silx/gui/widgets/MedianFilterDialog.py b/silx/gui/widgets/MedianFilterDialog.py
index 3eddff3..dd4a00d 100644
--- a/silx/gui/widgets/MedianFilterDialog.py
+++ b/silx/gui/widgets/MedianFilterDialog.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -35,8 +35,14 @@ __authors__ = ["H. Payno"]
__license__ = "MIT"
__date__ = "14/02/2017"
+
+import logging
+
from silx.gui import qt
+
+_logger = logging.getLogger(__name__)
+
class MedianFilterDialog(qt.QDialog):
"""QDialog window featuring a :class:`BackgroundWidget`"""
sigFilterOptChanged = qt.Signal(int, bool)
@@ -69,6 +75,6 @@ class MedianFilterDialog(qt.QDialog):
def _filterOptionChanged(self):
"""Call back used when the filter values are changed"""
if self._filterWidth.value()%2 == 0:
- logging.warning('median filter only accept odd values')
+ _logger.warning('median filter only accept odd values')
else:
self.sigFilterOptChanged.emit(self._filterWidth.value(), self._filterOption.isChecked()) \ No newline at end of file
diff --git a/silx/gui/widgets/PeriodicTable.py b/silx/gui/widgets/PeriodicTable.py
index db71483..0233e8c 100644
--- a/silx/gui/widgets/PeriodicTable.py
+++ b/silx/gui/widgets/PeriodicTable.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -634,7 +634,7 @@ class PeriodicTable(qt.QWidget):
objects.
:return: Selected items
- :rtype: list(PeriodicTableItem)
+ :rtype: List[PeriodicTableItem]
"""
return [b.item for b in self._eltButtons.values() if b.isSelected()]
@@ -644,7 +644,7 @@ class PeriodicTable(qt.QWidget):
This causes the sigSelectionChanged signal
to be emitted, even if the selection didn't actually change.
- :param list(str) symbols: List of symbols of elements to be selected
+ :param List[str] symbols: List of symbols of elements to be selected
(e.g. *["Fe", "Hg", "Li"]*)
"""
# accept list of PeriodicTableItems as input, because getSelection
@@ -813,7 +813,7 @@ class PeriodicList(qt.QTreeWidget):
objects.
:return: Selected elements
- :rtype: list(PeriodicTableItem)"""
+ :rtype: List[PeriodicTableItem]"""
return [_defaultTableItems[idx] for idx in range(len(self.tree_items))
if self.tree_items[idx].isSelected()]
diff --git a/silx/gui/widgets/PrintPreview.py b/silx/gui/widgets/PrintPreview.py
index 158d6b7..2b4c433 100644
--- a/silx/gui/widgets/PrintPreview.py
+++ b/silx/gui/widgets/PrintPreview.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -666,8 +666,6 @@ class _GraphicsResizeRectItem(qt.QGraphicsRectItem):
def main():
"""
"""
- import sys
-
if len(sys.argv) < 2:
print("give an image file as parameter please.")
sys.exit(1)
diff --git a/silx/gui/widgets/ThreadPoolPushButton.py b/silx/gui/widgets/ThreadPoolPushButton.py
index 4dba488..949b6ef 100644
--- a/silx/gui/widgets/ThreadPoolPushButton.py
+++ b/silx/gui/widgets/ThreadPoolPushButton.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -201,17 +201,20 @@ class ThreadPoolPushButton(WaitingPushButton):
return
self.__runnerStarted()
runner = self._createRunner(self.__callable, self.__args, self.__kwargs)
- qt.QThreadPool.globalInstance().start(runner)
+ qt.silxGlobalThreadPool().start(runner)
self.__runnerSet.add(runner)
def __releaseRunner(self, runner):
self.__runnerSet.remove(runner)
+ def hasPendingOperations(self):
+ return len(self.__runnerSet) > 0
+
def _createRunner(self, function, args, kwargs):
"""Create a QRunnable from a callable object.
:param callable function: A callable Python object.
- :param list args: List of arguments to call the function.
+ :param List args: List of arguments to call the function.
:param dict kwargs: Dictionary of arguments used to call the function.
:rtpye: qt.QRunnable
"""
@@ -227,7 +230,7 @@ class ThreadPoolPushButton(WaitingPushButton):
WARNING: The callable will be called in a separate thread.
:param callable function: A callable Python object
- :param list args: List of arguments to call the function.
+ :param List args: List of arguments to call the function.
:param dict kwargs: Dictionary of arguments used to call the function.
"""
self.__callable = function
diff --git a/silx/gui/widgets/test/test_threadpoolpushbutton.py b/silx/gui/widgets/test/test_threadpoolpushbutton.py
index 126f8f3..a8618a4 100644
--- a/silx/gui/widgets/test/test_threadpoolpushbutton.py
+++ b/silx/gui/widgets/test/test_threadpoolpushbutton.py
@@ -26,7 +26,7 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "15/12/2016"
+__date__ = "17/01/2018"
import unittest
@@ -35,7 +35,7 @@ from silx.gui import qt
from silx.gui.test.utils import TestCaseQt
from silx.gui.test.utils import SignalListener
from silx.gui.widgets.ThreadPoolPushButton import ThreadPoolPushButton
-from silx.test.utils import TestLogging
+from silx.utils.testutils import TestLogging
class TestThreadPoolPushButton(TestCaseQt):
@@ -44,6 +44,14 @@ class TestThreadPoolPushButton(TestCaseQt):
super(TestThreadPoolPushButton, self).setUp()
self._result = []
+ def waitForPendingOperations(self, object):
+ for i in range(50):
+ if not object.hasPendingOperations():
+ break
+ self.qWait(10)
+ else:
+ raise RuntimeError("Still waiting for a pending operation")
+
def _trace(self, name, delay=0):
self._result.append(name)
if delay != 0:
@@ -61,27 +69,25 @@ class TestThreadPoolPushButton(TestCaseQt):
button.executeCallable()
time.sleep(0.1)
self.assertListEqual(self._result, ["a"])
- self.qapp.processEvents()
+ self.waitForPendingOperations(button)
def testMultiExecution(self):
button = ThreadPoolPushButton()
button.setCallable(self._trace, "a", 0)
- number = qt.QThreadPool.globalInstance().maxThreadCount() * 2
+ number = qt.silxGlobalThreadPool().maxThreadCount()
for _ in range(number):
button.executeCallable()
- time.sleep(number * 0.01 + 0.1)
+ self.waitForPendingOperations(button)
self.assertListEqual(self._result, ["a"] * number)
- self.qapp.processEvents()
def testSaturateThreadPool(self):
button = ThreadPoolPushButton()
button.setCallable(self._trace, "a", 100)
- number = qt.QThreadPool.globalInstance().maxThreadCount() * 2
+ number = qt.silxGlobalThreadPool().maxThreadCount() * 2
for _ in range(number):
button.executeCallable()
- time.sleep(number * 0.1 + 0.1)
+ self.waitForPendingOperations(button)
self.assertListEqual(self._result, ["a"] * number)
- self.qapp.processEvents()
def testSuccess(self):
listener = SignalListener()
diff --git a/silx/image/test/test_shapes.py b/silx/image/test/test_shapes.py
index 0c5ab5e..1e6a9ca 100644
--- a/silx/image/test/test_shapes.py
+++ b/silx/image/test/test_shapes.py
@@ -27,14 +27,14 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "15/05/2017"
+__date__ = "17/01/2018"
import logging
import unittest
import numpy
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
from silx.image import shapes
_logger = logging.getLogger(__name__)
diff --git a/silx/io/__init__.py b/silx/io/__init__.py
index 96f6708..5e736b5 100644
--- a/silx/io/__init__.py
+++ b/silx/io/__init__.py
@@ -26,7 +26,7 @@
__authors__ = ["P. Knobel"]
__license__ = "MIT"
-__date__ = "15/05/2017"
+__date__ = "11/12/2017"
from .utils import open # pylint:disable=redefined-builtin
@@ -36,6 +36,11 @@ from .utils import is_dataset
from .utils import is_file
from .utils import is_group
from .utils import is_softlink
+from .utils import supported_extensions
+from .utils import get_data
# avoid to import open with "import *"
-__all__ = ["save1D", "is_dataset", "is_file", "is_group", "is_softlink"]
+__all = locals().keys()
+__all = filter(lambda x: not x.startswith("_"), __all)
+__all = filter(lambda x: x != "open", __all)
+__all__ = list(__all)
diff --git a/silx/io/commonh5.py b/silx/io/commonh5.py
index 02c4181..4fbcd08 100644
--- a/silx/io/commonh5.py
+++ b/silx/io/commonh5.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -32,12 +32,13 @@ import collections
import h5py
import numpy
from silx.third_party import six
+import weakref
from .utils import is_dataset
__authors__ = ["V. Valls", "P. Knobel"]
__license__ = "MIT"
-__date__ = "02/10/2017"
+__date__ = "11/10/2017"
class _MappingProxyType(collections.MutableMapping):
@@ -90,7 +91,7 @@ class Node(object):
"""
def __init__(self, name, parent=None, attrs=None):
- self.__parent = parent
+ self._set_parent(parent)
self.__basename = name
self.__attrs = {}
if attrs is not None:
@@ -114,7 +115,25 @@ class Node(object):
:rtype: Node
"""
- return self.__parent
+ if self.__parent is None:
+ parent = None
+ else:
+ parent = self.__parent()
+ if parent is None:
+ self.__parent = None
+ return parent
+
+ def _set_parent(self, parent):
+ """Set the parent of this node.
+
+ It do not update the parent object.
+
+ :param Node parent: New parent for this node
+ """
+ if parent is not None:
+ self.__parent = weakref.ref(parent)
+ else:
+ self.__parent = None
@property
def file(self):
@@ -123,22 +142,13 @@ class Node(object):
:rtype: Node
"""
node = self
- while node.__parent is not None:
- node = node.__parent
+ while node.parent is not None:
+ node = node.parent
if isinstance(node, File):
return node
else:
return None
- def _set_parent(self, parent):
- """Set the parent of this node.
-
- It do not update the parent object.
-
- :param Node parent: New parent for this node
- """
- self.__parent = parent
-
@property
def attrs(self):
"""Returns HDF5 attributes of this node.
@@ -154,11 +164,12 @@ class Node(object):
def name(self):
"""Returns the HDF5 name of this node.
"""
- if self.__parent is None:
+ parent = self.parent
+ if parent is None:
return "/"
- if self.__parent.name == "/":
+ if parent.name == "/":
return "/" + self.basename
- return self.__parent.name + "/" + self.basename
+ return parent.name + "/" + self.basename
@property
def basename(self):
@@ -709,7 +720,7 @@ class Group(Node):
def __getitem__(self, name):
"""Return a child from his name.
- :param name str: name of a member or a path throug members using '/'
+ :param str name: name of a member or a path throug members using '/'
separator. A '/' as a prefix access to the root item of the tree.
:rtype: Node
"""
@@ -806,7 +817,7 @@ class Group(Node):
See the documentation for `h5py.Group.visit` for more help.
:param func: Callable (function, method or callable object)
- :type func: function
+ :type func: callable
"""
origin_name = self.name
return self._visit(func, origin_name, visit_links)
@@ -816,7 +827,7 @@ class Group(Node):
See the documentation for `h5py.Group.visititems` for more help.
:param func: Callable (function, method or callable object)
- :type func: function
+ :type func: callable
:param bool visit_links: If *False*, ignore links. If *True*,
call `func(name)` for links and recurse into target groups.
"""
diff --git a/silx/io/configdict.py b/silx/io/configdict.py
index 21e24b7..2ba9755 100644
--- a/silx/io/configdict.py
+++ b/silx/io/configdict.py
@@ -1,5 +1,5 @@
# /*##########################################################################
-# Copyright (C) 2004-2016 European Synchrotron Radiation Facility
+# Copyright (C) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -92,7 +92,7 @@ from collections import OrderedDict
import numpy
import re
import sys
-if sys.version < '3.0':
+if sys.version_info < (3, ):
import ConfigParser as configparser
else:
import configparser
@@ -382,7 +382,7 @@ class ConfigDict(OrderedDict):
dictionary
:param sections: If not ``None``, add only the content of the
specified sections
- :type sections: list
+ :type sections: List
"""
filelist = self.__tolist(filelist)
sections = self.__tolist(sections)
@@ -475,7 +475,7 @@ class ConfigDict(OrderedDict):
# Escape commas
sstr = sstr.replace(",", "\,")
- if sys.version > '3.0':
+ if sys.version_info >= (3, ):
# Escape % characters except in "%%" and "%("
sstr = re.sub(r'%([^%\(])', r'%%\1', sstr)
diff --git a/silx/io/convert.py b/silx/io/convert.py
index 41f1e36..a2639e6 100644
--- a/silx/io/convert.py
+++ b/silx/io/convert.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -28,39 +28,39 @@ supported formats.
Read the documentation of :mod:`silx.io.spech5` and :mod:`silx.io.fabioh5` for
information on the structure of the output HDF5 files.
-Strings are written to the HDF5 datasets as fixed-length ASCII (NumPy *S* type).
-This is done in order to produce files that have maximum compatibility with
-other HDF5 libraries, as recommended in the
-`h5py documentation <http://docs.h5py.org/en/latest/strings.html#how-to-store-text-strings>`_.
+Text strings are written to the HDF5 datasets as variable-length utf-8.
-If you read the files back with *h5py* in Python 3, you will recover strings
-as bytes, which you should decode to transform them into python strings::
+.. warning::
- >>> import h5py
- >>> f = h5py.File("myfile.h5")
- >>> f["/1.1/instrument/specfile/scan_header"][0]
- b'#S 94 ascan del -0.5 0.5 20 1'
- >>> f["/1.1/instrument/specfile/scan_header"][0].decode()
- '#S 94 ascan del -0.5 0.5 20 1'
+ The output format for text strings changed in silx version 0.7.0.
+ Prior to that, text was output as fixed-length ASCII.
+
+ To be on the safe side, when reading back a HDF5 file written with an
+ older version of silx, you can test for the presence of a *decode*
+ attribute. To ensure that you always work with unicode text::
+
+ >>> import h5py
+ >>> h5f = h5py.File("my_scans.h5", "r")
+ >>> title = h5f["/68.1/title"]
+ >>> if hasattr(title, "decode"):
+ ... title = title.decode()
-Arrays of strings, such as file and scan headers, are stored as fixed-length
-strings. The length of all strings in an array is equal to the length of the
-longest string. Shorter strings are right-padded with blank spaces.
.. note:: This module has a dependency on the `h5py <http://www.h5py.org/>`_
library, which is not a mandatory dependency for `silx`. You might need
to install it if you don't already have it.
"""
-import numpy
import logging
+import numpy
import silx.io
from silx.io import is_dataset, is_group, is_softlink
+from silx.third_party import six
__authors__ = ["P. Knobel"]
__license__ = "MIT"
-__date__ = "14/09/2017"
+__date__ = "12/02/2018"
_logger = logging.getLogger(__name__)
@@ -92,7 +92,7 @@ def _create_link(h5f, link_name, target_name,
target_name)
del h5f[link_name]
else:
- _logger.warn(link_name + " already exist. Can't create link to " +
+ _logger.warn(link_name + " already exist. Cannot create link to " +
target_name)
return None
@@ -104,6 +104,23 @@ def _create_link(h5f, link_name, target_name,
raise ValueError("link_type must be 'hard' or 'soft'")
+def _attr_utf8(attr_value):
+ """If attr_value is bytes, make sure we output utf-8
+
+ :param attr_value: String (possibly bytes if PY2)
+ :return: Attr ready to be written by h5py as utf8
+ """
+ if isinstance(attr_value, six.binary_type) or \
+ isinstance(attr_value, six.text_type):
+ out_attr_value = numpy.array(
+ attr_value,
+ dtype=h5py.special_dtype(vlen=six.text_type))
+ else:
+ out_attr_value = attr_value
+
+ return out_attr_value
+
+
class Hdf5Writer(object):
"""Converter class to write the content of a data file to a HDF5 file.
"""
@@ -168,7 +185,7 @@ class Hdf5Writer(object):
for key in infile.attrs:
if self.overwrite_data or key not in root_grp.attrs:
root_grp.attrs.create(key,
- numpy.string_(infile.attrs[key]))
+ _attr_utf8(infile.attrs[key]))
# Handle links at the end, when their targets are created
for link_name, target_name in self._links:
@@ -208,10 +225,11 @@ class Hdf5Writer(object):
# add HDF5 attributes
for key in obj.attrs:
if self.overwrite_data or key not in ds.attrs:
- ds.attrs.create(key, numpy.string_(obj.attrs[key]))
+ ds.attrs.create(key,
+ _attr_utf8(obj.attrs[key]))
if not self.overwrite_data and member_initially_exists:
- _logger.warn("Ignoring existing dataset: " + h5_name)
+ _logger.warn("Not overwriting existing dataset: " + h5_name)
elif is_group(obj):
if h5_name not in self._h5f:
@@ -223,7 +241,14 @@ class Hdf5Writer(object):
# add HDF5 attributes
for key in obj.attrs:
if self.overwrite_data or key not in grp.attrs:
- grp.attrs.create(key, numpy.string_(obj.attrs[key]))
+ grp.attrs.create(key,
+ _attr_utf8(obj.attrs[key]))
+
+
+def _is_commonh5_group(grp):
+ """Return True if grp is a commonh5 group.
+ (h5py.Group objects are not commonh5 groups)"""
+ return is_group(grp) and not isinstance(grp, h5py.Group)
def write_to_h5(infile, h5file, h5path='/', mode="a",
@@ -232,7 +257,7 @@ def write_to_h5(infile, h5file, h5path='/', mode="a",
"""Write content of a h5py-like object into a HDF5 file.
:param infile: Path of input file, or :class:`commonh5.File` object
- or :class:`commonh5.Group` object
+ or :class:`commonh5.Group` object.
:param h5file: Path of output HDF5 file or HDF5 file handle
(`h5py.File` object)
:param str h5path: Target path in HDF5 file in which scan groups are created.
@@ -264,15 +289,23 @@ def write_to_h5(infile, h5file, h5path='/', mode="a",
# both infile and h5file can be either file handle or a file name: 4 cases
if not isinstance(h5file, h5py.File) and not is_group(infile):
with silx.io.open(infile) as h5pylike:
+ if not _is_commonh5_group(h5pylike):
+ raise IOError("Cannot convert HDF5 file %s to HDF5" % infile)
with h5py.File(h5file, mode) as h5f:
writer.write(h5pylike, h5f)
elif isinstance(h5file, h5py.File) and not is_group(infile):
with silx.io.open(infile) as h5pylike:
+ if not _is_commonh5_group(h5pylike):
+ raise IOError("Cannot convert HDF5 file %s to HDF5" % infile)
writer.write(h5pylike, h5file)
elif is_group(infile) and not isinstance(h5file, h5py.File):
+ if not _is_commonh5_group(infile):
+ raise IOError("Cannot convert HDF5 file %s to HDF5" % infile.file.name)
with h5py.File(h5file, mode) as h5f:
writer.write(infile, h5f)
else:
+ if not _is_commonh5_group(infile):
+ raise IOError("Cannot convert HDF5 file %s to HDF5" % infile.file.name)
writer.write(infile, h5file)
diff --git a/silx/io/dictdump.py b/silx/io/dictdump.py
index 1860b7f..1857cdb 100644
--- a/silx/io/dictdump.py
+++ b/silx/io/dictdump.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -225,6 +225,13 @@ def dicttoh5(treedict, h5file, h5path='/',
elif treedict[key] is None or (isinstance(treedict[key], dict) and
not len(treedict[key])):
+ if (h5path + key) in h5f:
+ if overwrite_data is True:
+ del h5f[h5path + key]
+ else:
+ logger.warning('key (%s) already exists. '
+ 'Not overwriting.' % (h5path + key))
+ continue
# Create empty group
h5f.create_group(h5path + key)
@@ -232,9 +239,25 @@ def dicttoh5(treedict, h5file, h5path='/',
ds = _prepare_hdf5_dataset(treedict[key])
# can't apply filters on scalars (datasets with shape == () )
if ds.shape == () or create_dataset_args is None:
+ if h5path + key in h5f:
+ if overwrite_data is True:
+ del h5f[h5path + key]
+ else:
+ logger.warning('key (%s) already exists. '
+ 'Not overwriting.' % (h5path + key))
+ continue
+
h5f.create_dataset(h5path + key,
data=ds)
else:
+ if h5path + key in h5f:
+ if overwrite_data is True:
+ del h5f[h5path + key]
+ else:
+ logger.warning('key (%s) already exists. '
+ 'Not overwriting.' % (h5path + key))
+ continue
+
h5f.create_dataset(h5path + key,
data=ds,
**create_dataset_args)
@@ -283,7 +306,7 @@ def h5todict(h5file, path="/", exclude_names=None):
fabioh5 file.
:param str path: Name of HDF5 group to use as dictionary root level,
to read only a sub-group in the file
- :param list[str] exclude_names: Groups and datasets whose name contains
+ :param List[str] exclude_names: Groups and datasets whose name contains
a string in this list will be ignored. Default is None (ignore nothing)
:return: Nested dictionary
"""
diff --git a/silx/io/fabioh5.py b/silx/io/fabioh5.py
index 2cee032..95eef23 100644
--- a/silx/io/fabioh5.py
+++ b/silx/io/fabioh5.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -36,8 +36,9 @@ import collections
import datetime
import logging
import numbers
+import os
-import fabio
+import fabio.file_series
import numpy
from . import commonh5
@@ -53,15 +54,60 @@ except ImportError as e:
_logger = logging.getLogger(__name__)
+_fabio_extensions = set([])
+
+
+def supported_extensions():
+ """Returns all extensions supported by fabio.
+
+ :returns: A set containing extensions like "*.edf".
+ :rtype: Set[str]
+ """
+ global _fabio_extensions
+ if len(_fabio_extensions) > 0:
+ return _fabio_extensions
+
+ formats = fabio.fabioformats.get_classes(reader=True)
+ all_extensions = set([])
+
+ for reader in formats:
+ if not hasattr(reader, "DEFAULT_EXTENSIONS"):
+ continue
+
+ ext = reader.DEFAULT_EXTENSIONS
+ ext = ["*.%s" % e for e in ext]
+ all_extensions.update(ext)
+
+ _fabio_extensions = set(all_extensions)
+ return _fabio_extensions
+
+
+class _FileSeries(fabio.file_series.file_series):
+ """
+ .. note:: Overwrite a function to fix an issue in fabio.
+ """
+ def jump(self, num):
+ """
+ Goto a position in sequence
+ """
+ assert num < len(self) and num >= 0, "num out of range"
+ self._current = num
+ return self[self._current]
+
+
class FrameData(commonh5.LazyLoadableDataset):
"""Expose a cube of image from a Fabio file using `FabioReader` as
cache."""
def __init__(self, name, fabio_reader, parent=None):
- attrs = {"interpretation": "image"}
+ if fabio_reader.is_spectrum():
+ attrs = {"interpretation": "spectrum"}
+ else:
+ attrs = {"interpretation": "image"}
commonh5.LazyLoadableDataset.__init__(self, name, parent, attrs=attrs)
self.__fabio_reader = fabio_reader
+
def _create_data(self):
return self.__fabio_reader.get_data()
@@ -69,20 +115,17 @@ class FrameData(commonh5.LazyLoadableDataset):
class RawHeaderData(commonh5.LazyLoadableDataset):
"""Lazy loadable raw header"""
- def __init__(self, name, fabio_file, parent=None):
+ def __init__(self, name, fabio_reader, parent=None):
commonh5.LazyLoadableDataset.__init__(self, name, parent)
- self.__fabio_file = fabio_file
+ self.__fabio_reader = fabio_reader
def _create_data(self):
"""Initialize hold data by merging all headers of each frames.
"""
headers = []
types = set([])
- for frame in range(self.__fabio_file.nframes):
- if self.__fabio_file.nframes == 1:
- header = self.__fabio_file.header
- else:
- header = self.__fabio_file.getframe(frame).header
+ for fabio_frame in self.__fabio_reader.iter_frames():
+ header = fabio_frame.header
data = []
for key, value in header.items():
@@ -239,19 +282,100 @@ class FabioReader(object):
COUNTER = 1
POSITIONER = 2
- def __init__(self, fabio_file):
- self.__fabio_file = fabio_file
+ def __init__(self, file_name=None, fabio_image=None, file_series=None):
+ """
+ Constructor
+
+ :param str file_name: File name of the image file to read
+ :param fabio.fabioimage.FabioImage fabio_image: An already openned
+ :class:`fabio.fabioimage.FabioImage` instance.
+ :param Union[list[str],fabio.file_series.file_series] file_series: An
+ list of file name or a :class:`fabio.file_series.file_series`
+ instance
+ """
+ self.__at_least_32bits = False
+ self.__signed_type = False
+
+ self.__load(file_name, fabio_image, file_series)
self.__counters = {}
self.__positioners = {}
self.__measurements = {}
self.__key_filters = set([])
self.__data = None
- self.__frame_count = self.__fabio_file.nframes
- self._read(self.__fabio_file)
+ self.__frame_count = self.frame_count()
+ self._read()
+
+ def __load(self, file_name=None, fabio_image=None, file_series=None):
+ if file_name is not None and fabio_image:
+ raise TypeError("Parameters file_name and fabio_image are mutually exclusive.")
+ if file_name is not None and fabio_image:
+ raise TypeError("Parameters fabio_image and file_series are mutually exclusive.")
+
+ self.__must_be_closed = False
+
+ if file_name is not None:
+ self.__fabio_file = fabio.open(file_name)
+ self.__must_be_closed = True
+ elif fabio_image is not None:
+ if isinstance(fabio_image, fabio.fabioimage.FabioImage):
+ self.__fabio_file = fabio_image
+ else:
+ raise TypeError("FabioImage expected but %s found.", fabio_image.__class__)
+ elif file_series is not None:
+ if isinstance(file_series, list):
+ self.__fabio_file = _FileSeries(file_series)
+ elif isinstance(file_series, fabio.file_series.file_series):
+ self.__fabio_file = file_series
+ else:
+ raise TypeError("file_series or list expected but %s found.", file_series.__class__)
+
+ def close(self):
+ """Close the object, and free up associated resources.
+
+ The associated FabioImage is closed only if the object was created from
+ a filename by this class itself.
+
+ After calling this method, attempts to use the object (and children)
+ may fail.
+ """
+ if self.__must_be_closed:
+ # It looks like there is no close on FabioImage
+ # self.__fabio_image.close()
+ pass
+ self.__fabio_image = None
def fabio_file(self):
return self.__fabio_file
+ def frame_count(self):
+ """Returns the number of frames available."""
+ if isinstance(self.__fabio_file, fabio.file_series.file_series):
+ return len(self.__fabio_file)
+ elif isinstance(self.__fabio_file, fabio.fabioimage.FabioImage):
+ return self.__fabio_file.nframes
+ else:
+ raise TypeError("Unsupported type %s", self.__fabio_file.__class__)
+
+ def iter_frames(self):
+ """Iter all the available frames.
+
+ A frame provides at least `data` and `header` attributes.
+ """
+ if isinstance(self.__fabio_file, fabio.file_series.file_series):
+ for file_number in range(len(self.__fabio_file)):
+ with self.__fabio_file.jump_image(file_number) as fabio_image:
+ # return the first frame only
+ assert(fabio_image.nframes == 1)
+ yield fabio_image
+ elif isinstance(self.__fabio_file, fabio.fabioimage.FabioImage):
+ for frame_count in range(self.__fabio_file.nframes):
+ if self.__fabio_file.nframes == 1:
+ yield self.__fabio_file
+ else:
+ yield self.__fabio_file.getframe(frame_count)
+ else:
+ raise TypeError("Unsupported type %s", self.__fabio_file.__class__)
+
def _create_data(self):
"""Initialize hold data by merging all frames into a single cube.
@@ -261,12 +385,8 @@ class FabioReader(object):
The computation is cached into the class, and only done ones.
"""
images = []
- for frame in range(self.__fabio_file.nframes):
- if self.__fabio_file.nframes == 1:
- image = self.__fabio_file.data
- else:
- image = self.__fabio_file.getframe(frame).data
- images.append(image)
+ for fabio_frame in self.iter_frames():
+ images.append(fabio_frame.data)
# returns the data without extra dim in case of single frame
if len(images) == 1:
@@ -329,8 +449,15 @@ class FabioReader(object):
"""
value = self.__get_dict(kind)[name]
if not isinstance(value, numpy.ndarray):
+ if kind in [self.COUNTER, self.POSITIONER]:
+ # Force normalization for counters and positioners
+ old = self._set_vector_normalization(at_least_32bits=True, signed_type=True)
+ else:
+ old = None
value = self._convert_metadata_vector(value)
self.__get_dict(kind)[name] = value
+ if old is not None:
+ self._set_vector_normalization(*old)
return value
def _set_counter_value(self, frame_id, name, value):
@@ -351,22 +478,25 @@ class FabioReader(object):
self.__measurements[name] = [None] * self.__frame_count
self.__measurements[name][frame_id] = value
- def _read(self, fabio_file):
- """Read all metadata from the fabio file and store it into this
- object."""
-
+ def _enable_key_filters(self, fabio_file):
self.__key_filters.clear()
if hasattr(fabio_file, "RESERVED_HEADER_KEYS"):
# Provided in fabio 0.5
for key in fabio_file.RESERVED_HEADER_KEYS:
self.__key_filters.add(key.lower())
- for frame in range(fabio_file.nframes):
- if fabio_file.nframes == 1:
- header = fabio_file.header
- else:
- header = fabio_file.getframe(frame).header
- self._read_frame(frame, header)
+ def _read(self):
+ """Read all metadata from the fabio file and store it into this
+ object."""
+
+ file_series = isinstance(self.__fabio_file, fabio.file_series.file_series)
+ if not file_series:
+ self._enable_key_filters(self.__fabio_file)
+
+ for frame_id, fabio_frame in enumerate(self.iter_frames()):
+ if file_series:
+ self._enable_key_filters(fabio_frame)
+ self._read_frame(frame_id, fabio_frame.header)
def _is_filtered_key(self, key):
"""
@@ -390,6 +520,29 @@ class FabioReader(object):
"""Read a key from the metadata and cache it into this object."""
self._set_measurement_value(frame_id, name, value)
+ def _set_vector_normalization(self, at_least_32bits, signed_type):
+ previous = self.__at_least_32bits, self.__signed_type
+ self.__at_least_32bits = at_least_32bits
+ self.__signed_type = signed_type
+ return previous
+
+ def _normalize_vector_type(self, dtype):
+ """Normalize the """
+ if self.__at_least_32bits:
+ if numpy.issubdtype(dtype, numpy.signedinteger):
+ dtype = numpy.result_type(dtype, numpy.uint32)
+ if numpy.issubdtype(dtype, numpy.unsignedinteger):
+ dtype = numpy.result_type(dtype, numpy.uint32)
+ elif numpy.issubdtype(dtype, numpy.floating):
+ dtype = numpy.result_type(dtype, numpy.float32)
+ elif numpy.issubdtype(dtype, numpy.complexfloating):
+ dtype = numpy.result_type(dtype, numpy.complex64)
+ if self.__signed_type:
+ if numpy.issubdtype(dtype, numpy.unsignedinteger):
+ signed = numpy.dtype("%s%i" % ('i', dtype.itemsize))
+ dtype = numpy.result_type(dtype, signed)
+ return dtype
+
def _convert_metadata_vector(self, values):
"""Convert a list of numpy data into a numpy array with the better
fitting type."""
@@ -420,6 +573,8 @@ class FabioReader(object):
else:
result = converted
+ result_type = self._normalize_vector_type(result_type)
+
if has_none:
# Fix missing data according to the array type
if result_type.kind == "S":
@@ -550,6 +705,14 @@ class FabioReader(object):
"""
return False
+ def is_spectrum(self):
+ """Returns true if the data should be interpreted as
+ MCA data.
+
+ :rtype: bool
+ """
+ return False
+
class EdfFabioReader(FabioReader):
"""Class which read and cache data and metadata from a fabio image.
@@ -558,8 +721,8 @@ class EdfFabioReader(FabioReader):
motor_mne are parsed using a special way.
"""
- def __init__(self, fabio_file):
- FabioReader.__init__(self, fabio_file)
+ def __init__(self, file_name=None, fabio_image=None, file_series=None):
+ FabioReader.__init__(self, file_name, fabio_image, file_series)
self.__unit_cell_abc = None
self.__unit_cell_alphabetagamma = None
self.__ub_matrix = None
@@ -622,17 +785,26 @@ class EdfFabioReader(FabioReader):
else:
raise Exception("State unexpected (base_key: %s)" % base_key)
+ def _get_first_header(self):
+ """
+ ..note:: This function can be cached
+ """
+ fabio_file = self.fabio_file()
+ if isinstance(fabio_file, fabio.file_series.file_series):
+ return fabio_file.jump_image(0).header
+ return fabio_file.header
+
def has_ub_matrix(self):
"""Returns true if a UB matrix is available.
:rtype: bool
"""
- header = self.fabio_file().header
+ header = self._get_first_header()
expected_keys = set(["UB_mne", "UB_pos", "sample_mne", "sample_pos"])
return expected_keys.issubset(header)
def parse_ub_matrix(self):
- header = self.fabio_file().header
+ header = self._get_first_header()
ub_data = self._get_mnemonic_key("UB", header)
s_data = self._get_mnemonic_key("sample", header)
if len(ub_data) > 9:
@@ -685,31 +857,52 @@ class EdfFabioReader(FabioReader):
self.parse_ub_matrix()
return self.__ub_matrix
+ def is_spectrum(self):
+ """Returns true if the data should be interpreted as
+ MCA data.
+ EDF files or file series, with two or more header names starting with
+ "MCA", should be interpreted as MCA data.
+
+ :rtype: bool
+ """
+ count = 0
+ for key in self._get_first_header():
+ if key.lower().startswith("mca"):
+ count += 1
+ if count >= 2:
+ return True
+ return False
+
class File(commonh5.File):
"""Class which handle a fabio image as a mimick of a h5py.File.
"""
- def __init__(self, file_name=None, fabio_image=None):
- self.__must_be_closed = False
- if file_name is not None and fabio_image is not None:
- raise TypeError("Parameters file_name and fabio_image are mutually exclusive.")
- if file_name is not None:
- self.__fabio_image = fabio.open(file_name)
- self.__must_be_closed = True
- elif fabio_image is not None:
- self.__fabio_image = fabio_image
- file_name = self.__fabio_image.filename
+ def __init__(self, file_name=None, fabio_image=None, file_series=None):
+ """
+ Constructor
+
+ :param str file_name: File name of the image file to read
+ :param fabio.fabioimage.FabioImage fabio_image: An already openned
+ :class:`fabio.fabioimage.FabioImage` instance.
+ :param Union[list[str],fabio.file_series.file_series] file_series: An
+ list of file name or a :class:`fabio.file_series.file_series`
+ instance
+ """
+ self.__fabio_reader = self.create_fabio_reader(file_name, fabio_image, file_series)
+ if fabio_image is not None:
+ file_name = fabio_image.filename
+
attrs = {"NX_class": "NXroot",
"file_time": datetime.datetime.now().isoformat(),
- "file_name": file_name,
"creator": "silx %s" % silx_version}
+ if file_name is not None:
+ attrs["file_name"] = file_name
commonh5.File.__init__(self, name=file_name, attrs=attrs)
- self.__fabio_reader = self.create_fabio_reader(self.__fabio_image)
- scan = self.create_scan_group(self.__fabio_image, self.__fabio_reader)
+ scan = self.create_scan_group(self.__fabio_reader)
self.add_node(scan)
- def create_scan_group(self, fabio_image, fabio_reader):
+ def create_scan_group(self, fabio_reader):
"""Factory to create the scan group.
:param FabioImage fabio_image: A Fabio image
@@ -722,7 +915,7 @@ class File(commonh5.File):
measurement = MeasurementGroup("measurement", fabio_reader, attrs={"NX_class": "NXcollection"})
file_ = commonh5.Group("file", attrs={"NX_class": "NXcollection"})
positioners = MetadataGroup("positioners", fabio_reader, FabioReader.POSITIONER, attrs={"NX_class": "NXpositioner"})
- raw_header = RawHeaderData("scan_header", fabio_image, self)
+ raw_header = RawHeaderData("scan_header", fabio_reader, self)
detector = DetectorGroup("detector_0", fabio_reader)
scan.add_node(instrument)
@@ -738,26 +931,43 @@ class File(commonh5.File):
return scan
- def create_fabio_reader(self, fabio_file):
+ def create_fabio_reader(self, file_name, fabio_image, file_series):
"""Factory to create fabio reader.
:rtype: FabioReader"""
- if isinstance(fabio_file, fabio.edfimage.EdfImage):
- metadata = EdfFabioReader(fabio_file)
+ use_edf_reader = False
+ first_file_name = None
+ first_image = None
+
+ if isinstance(file_series, list):
+ first_file_name = file_series[0]
+ elif isinstance(file_series, fabio.file_series.file_series):
+ first_image = file_series.first_image()
+ elif fabio_image is not None:
+ first_image = fabio_image
+ else:
+ first_file_name = file_name
+
+ if first_file_name is not None:
+ _, ext = os.path.splitext(first_file_name)
+ ext = ext[1:]
+ use_edf_reader = ext in fabio.edfimage.EdfImage.DEFAULT_EXTENSIONS
+ elif first_image is not None:
+ use_edf_reader = isinstance(first_image, fabio.edfimage.EdfImage)
+ else:
+ assert(False)
+
+ if use_edf_reader:
+ reader = EdfFabioReader(file_name, fabio_image, file_series)
else:
- metadata = FabioReader(fabio_file)
- return metadata
+ reader = FabioReader(file_name, fabio_image, file_series)
+ return reader
def close(self):
"""Close the object, and free up associated resources.
- The associated FabioImage is closed anyway the object was created from
- a filename or from a FabioImage.
-
- After calling this method, attempts to use the object may fail.
+ After calling this method, attempts to use the object (and children)
+ may fail.
"""
- if self.__must_be_closed:
- # It looks like there is no close on FabioImage
- # self.__fabio_image.close()
- pass
- self.__fabio_image = None
+ self.__fabio_reader.close()
+ self.__fabio_reader = None
diff --git a/silx/io/nxdata.py b/silx/io/nxdata.py
index 977721f..cc153b0 100644
--- a/silx/io/nxdata.py
+++ b/silx/io/nxdata.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -29,30 +29,47 @@ See http://download.nexusformat.org/sphinx/classes/base_classes/NXdata.html
"""
import logging
+import os
+import os.path
import numpy
-from .utils import is_dataset, is_group
+from .utils import is_dataset, is_group, is_file
from silx.third_party import six
+try:
+ import h5py
+except ImportError:
+ h5py = None
+
+__authors__ = ["P. Knobel"]
+__license__ = "MIT"
+__date__ = "12/02/2018"
+
_logger = logging.getLogger(__name__)
_INTERPDIM = {"scalar": 0,
"spectrum": 1,
"image": 2,
- # "rgba-image": 3, "hsla-image": 3, "cmyk-image": 3, # TODO
+ "rgba-image": 3, # "hsla-image": 3, "cmyk-image": 3, # TODO
"vertex": 1} # 3D scatter: 1D signal + 3 axes (x, y, z) of same legth
"""Number of signal dimensions associated to each possible @interpretation
attribute.
"""
-def _nxdata_warning(msg):
+def _nxdata_warning(msg, group_name=""):
"""Log a warning message prefixed with
*"NXdata warning: "*
:param str msg: Warning message
+ :param str group_name: Name of NXdata group this warning relates to
"""
- _logger.warning("NXdata warning: " + msg)
+ warning_prefix = "NXdata warning"
+ if group_name:
+ warning_prefix += " (group %s): " % group_name
+ else:
+ warning_prefix += ": "
+ _logger.warning(warning_prefix + msg)
def get_attr_as_string(item, attr_name, default=None):
@@ -64,16 +81,26 @@ def get_attr_as_string(item, attr_name, default=None):
:param item: Group or dataset
:param attr_name: Attribute name
+ :param default: Value to be returned if attribute is not found.
:return: item.attrs[attr_name]
"""
attr = item.attrs.get(attr_name, default)
if six.PY2:
- return attr
+ if isinstance(attr, six.text_type):
+ # unicode
+ return attr.encode("utf-8")
+ else:
+ return attr
if six.PY3:
if hasattr(attr, "decode"):
# byte-string
return attr.decode("utf-8")
- elif isinstance(attr, numpy.ndarray) and hasattr(attr[0], "decode"):
+ elif isinstance(attr, numpy.ndarray) and not attr.shape and\
+ hasattr(attr[()], "decode"):
+ # byte string as ndarray scalar
+ return attr[()].decode("utf-8")
+ elif isinstance(attr, numpy.ndarray) and len(attr.shape) and\
+ hasattr(attr[0], "decode"):
# array of byte-strings
return [element.decode("utf-8") for element in attr]
else:
@@ -92,7 +119,7 @@ def is_valid_nxdata(group): # noqa
:param group: h5py-like group
:return: True if this NXdata group is valid.
- :raise: TypeError if group is not a h5py group, a spech5 group,
+ :raise TypeError: if group is not a h5py group, a spech5 group,
or a fabioh5 group
"""
if not is_group(group):
@@ -100,28 +127,60 @@ def is_valid_nxdata(group): # noqa
if get_attr_as_string(group, "NX_class") != "NXdata":
return False
if "signal" not in group.attrs:
- _logger.warning("NXdata group does not define a signal attr.")
- return False
+ _logger.info("NXdata group %s does not define a signal attr. "
+ "Testing legacy specification.", group.name)
+ signal_name = None
+ for key in group:
+ if "signal" in group[key].attrs:
+ signal_name = key
+ signal_attr = group[key].attrs["signal"]
+ if signal_attr in [1, b"1", u"1"]:
+ # This is the main (default) signal
+ break
+ if signal_name is None:
+ _nxdata_warning("No @signal attribute on the NXdata group, "
+ "and no dataset with a @signal=1 attr found",
+ group.name)
+ return False
+ else:
+ signal_name = get_attr_as_string(group, "signal")
- signal_name = get_attr_as_string(group, "signal")
if signal_name not in group or not is_dataset(group[signal_name]):
- _logger.warning(
- "Cannot find signal dataset '%s' in NXdata group" % signal_name)
+ _nxdata_warning(
+ "Cannot find signal dataset '%s'" % signal_name,
+ group.name)
return False
+ auxiliary_signals_names = get_attr_as_string(group, "auxiliary_signals",
+ default=[])
+ if isinstance(auxiliary_signals_names, (six.text_type, six.binary_type)):
+ auxiliary_signals_names = [auxiliary_signals_names]
+ for asn in auxiliary_signals_names:
+ if asn not in group or not is_dataset(group[asn]):
+ _nxdata_warning(
+ "Cannot find auxiliary signal dataset '%s'" % asn,
+ group.name)
+ return False
+ if group[signal_name].shape != group[asn].shape:
+ _nxdata_warning("Auxiliary signal dataset '%s' does not" % asn +
+ " have the same shape as the main signal.",
+ group.name)
+ return False
+
ndim = len(group[signal_name].shape)
if "axes" in group.attrs:
axes_names = get_attr_as_string(group, "axes")
- if isinstance(axes_names, str):
+ if isinstance(axes_names, (six.text_type, six.binary_type)):
axes_names = [axes_names]
if 1 < ndim < len(axes_names):
- # ndim = 1 and several axes could be a scatter
+ # ndim = 1 with several axes could be a scatter
_nxdata_warning(
"More @axes defined than there are " +
"signal dimensions: " +
- "%d axes, %d dimensions." % (len(axes_names), ndim))
+ "%d axes, %d dimensions." % (len(axes_names), ndim),
+ group.name)
return False
# case of less axes than dimensions: number of axes must match
@@ -132,18 +191,33 @@ def is_valid_nxdata(group): # noqa
interpretation = get_attr_as_string(group, "interpretation")
if interpretation is None:
_nxdata_warning("No @interpretation and not enough" +
- " @axes defined.")
+ " @axes defined.", group.name)
return False
if interpretation not in _INTERPDIM:
_nxdata_warning("Unrecognized @interpretation=" + interpretation +
- " for data with wrong number of defined @axes.")
+ " for data with wrong number of defined @axes.",
+ group.name)
return False
+ if interpretation == "rgba-image":
+ if ndim != 3 or group[signal_name].shape[-1] not in [3, 4]:
+ _nxdata_warning(
+ "Inconsistent RGBA Image. Expected 3 dimensions with " +
+ "last one of length 3 or 4. Got ndim=%d " % ndim +
+ "with last dimension of length %d." % group[signal_name].shape[-1],
+ group.name)
+ return False
+ if len(axes_names) != 2:
+ _nxdata_warning(
+ "Inconsistent number of axes for RGBA Image. Expected "
+ "3, but got %d." % ndim, group.name)
+ return False
- if len(axes_names) != _INTERPDIM[interpretation]:
+ elif len(axes_names) != _INTERPDIM[interpretation]:
_nxdata_warning(
"%d-D signal with @interpretation=%s " % (ndim, interpretation) +
- "must define %d or %d axes." % (ndim, _INTERPDIM[interpretation]))
+ "must define %d or %d axes." % (ndim, _INTERPDIM[interpretation]),
+ group.name)
return False
# Test consistency of @uncertainties
@@ -155,7 +229,7 @@ def is_valid_nxdata(group): # noqa
if uncertainties_names is not None:
if len(uncertainties_names) != len(axes_names):
_nxdata_warning("@uncertainties does not define the same " +
- "number of fields than @axes")
+ "number of fields than @axes", group.name)
return False
# Test individual axes
@@ -165,10 +239,12 @@ def is_valid_nxdata(group): # noqa
signal_size *= dim
polynomial_axes_names = []
for i, axis_name in enumerate(axes_names):
+
if axis_name == ".":
continue
if axis_name not in group or not is_dataset(group[axis_name]):
- _nxdata_warning("Could not find axis dataset '%s'" % axis_name)
+ _nxdata_warning("Could not find axis dataset '%s'" % axis_name,
+ group.name)
return False
axis_size = 1
@@ -180,7 +256,8 @@ def is_valid_nxdata(group): # noqa
# size is exactly the signal's size (weird n-d scatter)
if axis_size != signal_size:
_nxdata_warning("Axis %s is not a 1D dataset" % axis_name +
- " and its shape does not match the signal's shape")
+ " and its shape does not match the signal's shape",
+ group.name)
return False
axis_len = axis_size
else:
@@ -195,7 +272,7 @@ def is_valid_nxdata(group): # noqa
"Axis %s number of elements does not " % axis_name +
"correspond to the length of any signal dimension,"
" it does not appear to be a constant or a linear calibration," +
- " and this does not seem to be a scatter plot.")
+ " and this does not seem to be a scatter plot.", group.name)
return False
elif axis_len in (1, 2):
polynomial_axes_names.append(axis_name)
@@ -205,7 +282,8 @@ def is_valid_nxdata(group): # noqa
_nxdata_warning(
"Axis %s number of elements is equal " % axis_name +
"to the length of the signal, but this does not seem" +
- " to be a scatter (other axes have different sizes)")
+ " to be a scatter (other axes have different sizes)",
+ group.name)
return False
# Test individual uncertainties
@@ -216,14 +294,15 @@ def is_valid_nxdata(group): # noqa
if group[errors_name].shape != group[axis_name].shape:
_nxdata_warning(
"Errors '%s' does not have the same " % errors_name +
- "dimensions as axis '%s'." % axis_name)
+ "dimensions as axis '%s'." % axis_name, group.name)
return False
# test dimensions of errors associated with signal
if "errors" in group and is_dataset(group["errors"]):
if group["errors"].shape != group[signal_name].shape:
_nxdata_warning("Dataset containing standard deviations must " +
- "have the same dimensions as the signal.")
+ "have the same dimensions as the signal.",
+ group.name)
return False
return True
@@ -245,10 +324,19 @@ class NXdata(object):
"""h5py-like group object compliant with NeXus NXdata specification.
"""
- self.signal = self.group[get_attr_as_string(self.group, "signal")]
- """Signal dataset in this NXdata group.
+ self.signal = self.group[self.signal_dataset_name]
+ """Main signal dataset in this NXdata group.
+
+ In case more than one signal is present in this group,
+ the other ones can be found in :attr:`auxiliary_signals`.
"""
+ self.signal_name = get_attr_as_string(self.signal, "long_name")
+ """Signal long name, as specified in the @long_name attribute of the
+ signal dataset. If not specified, the dataset name is used."""
+ if self.signal_name is None:
+ self.signal_name = self.signal_dataset_name
+
# ndim will be available in very recent h5py versions only
self.signal_ndim = getattr(self.signal, "ndim",
len(self.signal.shape))
@@ -276,6 +364,86 @@ class NXdata(object):
self.signal_is_1d = self.signal_is_1d and len(self.axes) <= 1 # excludes n-D scatters
@property
+ def signal_dataset_name(self):
+ """Name of the main signal dataset."""
+ signal_dataset_name = get_attr_as_string(self.group, "signal")
+ if signal_dataset_name is None:
+ # find a dataset with @signal == 1
+ for dsname in self.group:
+ signal_attr = self.group[dsname].attrs.get("signal")
+ if signal_attr in [1, b"1", u"1"]:
+ # This is the main (default) signal
+ signal_dataset_name = dsname
+ break
+ assert signal_dataset_name is not None
+ return signal_dataset_name
+
+ @property
+ def auxiliary_signals_dataset_names(self):
+ """Sorted list of names of the auxiliary signals datasets.
+
+ These are the names provided by the *@auxiliary_signals* attribute
+ on the NXdata group.
+
+ In case the NXdata group does not specify a *@signal* attribute
+ but has a dataset with an attribute *@signal=1*,
+ we look for datasets with attributes *@signal=2, @signal=3...*
+ (deprecated NXdata specification)."""
+ signal_dataset_name = get_attr_as_string(self.group, "signal")
+ if signal_dataset_name is not None:
+ auxiliary_signals_names = get_attr_as_string(self.group, "auxiliary_signals")
+ if auxiliary_signals_names is not None:
+ if not isinstance(auxiliary_signals_names,
+ (tuple, list, numpy.ndarray)):
+ # tolerate a single string, but coerce into a list
+ return [auxiliary_signals_names]
+ return list(auxiliary_signals_names)
+ return []
+
+ # try old spec, @signal=1 (2, 3...) on dataset
+ numbered_names = []
+ for dsname in self.group:
+ if dsname == self.signal_dataset_name:
+ # main signal, not auxiliary
+ continue
+ ds = self.group[dsname]
+ signal_attr = ds.attrs.get("signal")
+ if signal_attr is not None and not is_dataset(ds):
+ _logger.warning("Item %s with @signal=%s is not a dataset (%s)",
+ dsname, signal_attr, type(ds))
+ continue
+ if signal_attr is not None:
+ try:
+ signal_number = int(signal_attr)
+ except (ValueError, TypeError):
+ _logger.warning("Could not parse attr @signal=%s on "
+ "dataset %s as an int",
+ signal_attr, dsname)
+ continue
+ numbered_names.append((signal_number, dsname))
+ return [a[1] for a in sorted(numbered_names)]
+
+ @property
+ def auxiliary_signals_names(self):
+ """List of names of the auxiliary signals.
+
+ Similar to :attr:`auxiliary_signals_dataset_names`, but the @long_name
+ is used when this attribute is present, instead of the dataset name.
+ """
+ signal_names = []
+ for asdn in self.auxiliary_signals_dataset_names:
+ if "long_name" in self.group[asdn].attrs:
+ signal_names.append(self.group[asdn].attrs["long_name"])
+ else:
+ signal_names.append(asdn)
+ return signal_names
+
+ @property
+ def auxiliary_signals(self):
+ """List of all auxiliary signal datasets."""
+ return [self.group[dsname] for dsname in self.auxiliary_signals_dataset_names]
+
+ @property
def interpretation(self):
"""*@interpretation* attribute associated with the *signal*
dataset of the NXdata group. ``None`` if no interpretation
@@ -300,7 +468,7 @@ class NXdata(object):
interpretation is returned anyway.
"""
allowed_interpretations = [None, "scalar", "spectrum", "image",
- # "rgba-image", "hsla-image", "cmyk-image" # TODO
+ "rgba-image", # "hsla-image", "cmyk-image"
"vertex"]
interpretation = get_attr_as_string(self.signal, "interpretation")
@@ -317,20 +485,19 @@ class NXdata(object):
"""List of the axes datasets.
The list typically has as many elements as there are dimensions in the
- signal dataset, the exception being scatter plots which typically
- use a 1D signal and several 1D axes of the same size.
+ signal dataset, the exception being scatter plots which use a 1D
+ signal and multiple 1D axes of the same size.
If an axis dataset applies to several dimensions of the signal, it
will be repeated in the list.
- If a dimension of the signal has no dimension scale (i.e. there is a
- "." in that position in the *@axes* array), `None` is inserted in the
- output list in its position.
+ If a dimension of the signal has no dimension scale, `None` is
+ inserted in its position in the list.
.. note::
- In theory, the *@axes* attribute defines as many entries as there
- are dimensions in the signal. In such a case, there is no ambiguity.
+ The *@axes* attribute should define as many entries as there
+ are dimensions in the signal, to avoid any ambiguity.
If this is not the case, this implementation relies on the existence
of an *@interpretation* (*spectrum* or *image*) attribute in the
*signal* dataset.
@@ -339,47 +506,20 @@ class NXdata(object):
If an axis dataset defines attributes @first_good or @last_good,
the output will be a numpy array resulting from slicing that
- axis to keep only the good index range: axis[first_good:last_good + 1]
+ axis (*axis[first_good:last_good + 1]*).
- :rtype: list[Dataset or 1D array or None]
+ :rtype: List[Dataset or 1D array or None]
"""
if self._axes is not None:
# use cache
return self._axes
- ndims = len(self.signal.shape)
- axes_names = get_attr_as_string(self.group, "axes")
- interpretation = self.interpretation
-
- if axes_names is None:
- self._axes = [None for _i in range(ndims)]
- return self._axes
-
- if isinstance(axes_names, str):
- axes_names = [axes_names]
+ axes = []
+ for axis_name in self.axes_dataset_names:
+ if axis_name is None:
+ axes.append(None)
+ else:
+ axes.append(self.group[axis_name])
- if len(axes_names) == ndims:
- # axes is a list of strings, one axis per dim is explicitly defined
- axes = [None] * ndims
- for i, axis_n in enumerate(axes_names):
- if axis_n != ".":
- axes[i] = self.group[axis_n]
- elif interpretation is not None:
- # case of @interpretation attribute defined: we expect 1, 2 or 3 axes
- # corresponding to the 1, 2, or 3 last dimensions of the signal
- assert len(axes_names) == _INTERPDIM[interpretation]
- axes = [None] * (ndims - _INTERPDIM[interpretation])
- for axis_n in axes_names:
- if axis_n != ".":
- axes.append(self.group[axis_n])
- else:
- axes.append(None)
- else: # scatter
- axes = []
- for axis_n in axes_names:
- if axis_n != ".":
- axes.append(self.group[axis_n])
- else:
- axes.append(None)
# keep only good range of axis data
for i, axis in enumerate(axes):
if axis is None:
@@ -395,7 +535,8 @@ class NXdata(object):
@property
def axes_dataset_names(self):
- """
+ """List of axes dataset names.
+
If an axis dataset applies to several dimensions of the signal, its
name will be repeated in the list.
@@ -403,15 +544,46 @@ class NXdata(object):
"." in that position in the *@axes* array), `None` is inserted in the
output list in its position.
"""
+ numbered_names = [] # used in case of @axis=0 (old spec)
axes_dataset_names = get_attr_as_string(self.group, "axes")
if axes_dataset_names is None:
- axes_dataset_names = get_attr_as_string(self.group, "axes")
+ # try @axes on signal dataset (older NXdata specification)
+ axes_dataset_names = get_attr_as_string(self.signal, "axes")
+ if axes_dataset_names is not None:
+ # we expect a comma separated string
+ if hasattr(axes_dataset_names, "split"):
+ axes_dataset_names = axes_dataset_names.split(":")
+ else:
+ # try @axis on the individual datasets (oldest NXdata specification)
+ for dsname in self.group:
+ if not is_dataset(self.group[dsname]):
+ continue
+ axis_attr = self.group[dsname].attrs.get("axis")
+ if axis_attr is not None:
+ try:
+ axis_num = int(axis_attr)
+ except (ValueError, TypeError):
+ _logger.warning("Could not interpret attr @axis as"
+ "int on dataset %s", dsname)
+ continue
+ numbered_names.append((axis_num, dsname))
ndims = len(self.signal.shape)
if axes_dataset_names is None:
- return [None] * ndims
+ if numbered_names:
+ axes_dataset_names = []
+ numbers = [a[0] for a in numbered_names]
+ names = [a[1] for a in numbered_names]
+ for i in range(ndims):
+ if i in numbers:
+ axes_dataset_names.append(names[numbers.index(i)])
+ else:
+ axes_dataset_names.append(None)
+ return axes_dataset_names
+ else:
+ return [None] * ndims
- if isinstance(axes_dataset_names, str):
+ if isinstance(axes_dataset_names, (six.text_type, six.binary_type)):
axes_dataset_names = [axes_dataset_names]
for i, axis_name in enumerate(axes_dataset_names):
@@ -422,17 +594,48 @@ class NXdata(object):
if len(axes_dataset_names) != ndims:
if self.is_scatter and ndims == 1:
+ # case of a 1D signal with arbitrary number of axes
return list(axes_dataset_names)
- # @axes may only define 1 or 2 axes if @interpretation=spectrum/image.
- # Use the existing names for the last few dims, and prepend with Nones.
- assert len(axes_dataset_names) == _INTERPDIM[self.interpretation]
- all_dimensions_names = [None] * (ndims - _INTERPDIM[self.interpretation])
- for axis_name in axes_dataset_names:
- all_dimensions_names.append(axis_name)
+ if self.interpretation != "rgba-image":
+ # @axes may only define 1 or 2 axes if @interpretation=spectrum/image.
+ # Use the existing names for the last few dims, and prepend with Nones.
+ assert len(axes_dataset_names) == _INTERPDIM[self.interpretation]
+ all_dimensions_names = [None] * (ndims - _INTERPDIM[self.interpretation])
+ for axis_name in axes_dataset_names:
+ all_dimensions_names.append(axis_name)
+ else:
+ # 2 axes applying to the first two dimensions.
+ # The 3rd signal dimension is expected to contain 3(4) RGB(A) values.
+ assert len(axes_dataset_names) == 2
+ all_dimensions_names = [axn for axn in axes_dataset_names]
+ all_dimensions_names.append(None)
return all_dimensions_names
return list(axes_dataset_names)
+ @property
+ def title(self):
+ """Plot title. If not found, returns an empty string.
+
+ This attribute does not appear in the NXdata specification, but it is
+ implemented in *nexpy* as a dataset named "title" inside the NXdata
+ group. This dataset is expected to contain text.
+
+ Because the *nexpy* approach could cause a conflict if the signal
+ dataset or an axis dataset happened to be called "title", we also
+ support providing the title as an attribute of the NXdata group.
+ """
+ title = self.group.get("title")
+ data_dataset_names = [self.signal_name] + self.axes_dataset_names
+ if (title is not None and is_dataset(title) and
+ "title" not in data_dataset_names):
+ return str(title[()])
+
+ title = self.group.attrs.get("title")
+ if title is None:
+ return ""
+ return str(title)
+
def get_axis_errors(self, axis_name):
"""Return errors (uncertainties) associated with an axis.
@@ -442,7 +645,7 @@ class NXdata(object):
:param str axis_name: Name of axis dataset. This dataset **must exist**.
:return: Dataset with axis errors, or None
- :raise: KeyError if this group does not contain a dataset named axis_name
+ :raise KeyError: if this group does not contain a dataset named axis_name
"""
# ensure axis_name is decoded, before comparing it with decoded attributes
if hasattr(axis_name, "decode"):
@@ -541,3 +744,303 @@ class NXdata(object):
def is_unsupported_scatter(self):
"""True if this is a scatter with a signal and more than 2 axes."""
return self.is_scatter and len(self.axes) > 2
+
+ @property
+ def is_curve(self):
+ """This property is True if the signal is 1D or :attr:`interpretation` is
+ *"spectrum"*, and there is at most one axis with a consistent length.
+ """
+ if self.signal_is_0d or self.interpretation not in [None, "spectrum"]:
+ return False
+ # the axis, if any, must be of the same length as the last dimension
+ # of the signal, or of length 2 (a + b *x scale)
+ if self.axes[-1] is not None and len(self.axes[-1]) not in [
+ self.signal.shape[-1], 2]:
+ return False
+ if self.interpretation is None:
+ # We no longer test whether x values are monotonic
+ # (in the past, in that case, we used to consider it a scatter)
+ return self.signal_is_1d
+ # everything looks good
+ return True
+
+ @property
+ def is_image(self):
+ """True if the signal is 2D, or 3D with last dimension of length 3 or 4
+ and interpretation *rgba-image*, or >2D with interpretation *image*.
+ The axes (if any) length must also be consistent with the signal shape.
+ """
+ if self.interpretation in ["scalar", "spectrum", "scaler"]:
+ return False
+ if self.signal_is_0d or self.signal_is_1d:
+ return False
+ if not self.signal_is_2d and \
+ self.interpretation not in ["image", "rgba-image"]:
+ return False
+ if self.signal_is_3d and self.interpretation == "rgba-image":
+ if self.signal.shape[-1] not in [3, 4]:
+ return False
+ img_axes = self.axes[0:2]
+ img_shape = self.signal.shape[0:2]
+ else:
+ img_axes = self.axes[-2:]
+ img_shape = self.signal.shape[-2:]
+ for i, axis in enumerate(img_axes):
+ if axis is not None and len(axis) not in [img_shape[i], 2]:
+ return False
+
+ return True
+
+ @property
+ def is_stack(self):
+ """True in the signal is at least 3D and interpretation is not
+ "scalar", "spectrum", "image" or "rgba-image".
+ The axes length must also be consistent with the last 3 dimensions
+ of the signal.
+ """
+ if self.signal_ndim < 3 or self.interpretation in [
+ "scalar", "scaler", "spectrum", "image", "rgba-image"]:
+ return False
+ stack_shape = self.signal.shape[-3:]
+ for i, axis in enumerate(self.axes[-3:]):
+ if axis is not None and len(axis) not in [stack_shape[i], 2]:
+ return False
+ return True
+
+
+def is_NXentry_with_default_NXdata(group):
+ """Return True if group is a valid NXentry defining a valid default
+ NXdata."""
+ if not is_group(group):
+ return False
+
+ if get_attr_as_string(group, "NX_class") != "NXentry":
+ return False
+
+ default_nxdata_name = group.attrs.get("default")
+ if default_nxdata_name is None or default_nxdata_name not in group:
+ return False
+
+ default_nxdata_group = group.get(default_nxdata_name)
+
+ if not is_group(default_nxdata_group):
+ return False
+
+ return is_valid_nxdata(default_nxdata_group)
+
+
+def is_NXroot_with_default_NXdata(group):
+ """Return True if group is a valid NXroot defining a default NXentry
+ defining a valid default NXdata."""
+ if not is_group(group):
+ return False
+
+ # A NXroot is supposed to be at the root of a data file, and @NX_class
+ # is therefore optional. We accept groups that are not located at the root
+ # if they have @NX_class=NXroot (use case: several nexus files archived
+ # in a single HDF5 file)
+ if get_attr_as_string(group, "NX_class") != "NXroot" and not is_file(group):
+ return False
+
+ default_nxentry_name = group.attrs.get("default")
+ if default_nxentry_name is None or default_nxentry_name not in group:
+ return False
+
+ default_nxentry_group = group.get(default_nxentry_name)
+ return is_NXentry_with_default_NXdata(default_nxentry_group)
+
+
+def get_default(group):
+ """Return a :class:`NXdata` object corresponding to the default NXdata group
+ in the group specified as parameter.
+
+ This function can find the NXdata if the group is already a NXdata, or
+ if it is a NXentry defining a default NXdata, or if it is a NXroot
+ defining such a default valid NXentry.
+
+ Return None if no valid NXdata could be found.
+
+ :param group: h5py-like group following the Nexus specification
+ (NXdata, NXentry or NXroot).
+ :return: :class:`NXdata` object or None
+ :raise TypeError: if group is not a h5py-like group
+ """
+ if not is_group(group):
+ raise TypeError("Provided parameter is not a h5py-like group")
+
+ if is_NXroot_with_default_NXdata(group):
+ default_entry = group[group.attrs["default"]]
+ default_data = default_entry[default_entry.attrs["default"]]
+ elif is_NXentry_with_default_NXdata(group):
+ default_data = group[group.attrs["default"]]
+ elif is_valid_nxdata(group):
+ default_data = group
+ else:
+ return None
+
+ return NXdata(default_data)
+
+
+def _str_to_utf8(text):
+ return numpy.array(text, dtype=h5py.special_dtype(vlen=six.text_type))
+
+
+def save_NXdata(filename, signal, axes=None,
+ signal_name="data", axes_names=None,
+ signal_long_name=None, axes_long_names=None,
+ signal_errors=None, axes_errors=None,
+ title=None, interpretation=None,
+ nxentry_name="entry", nxdata_name=None):
+ """Write data to an NXdata group.
+
+ .. note::
+
+ No consistency checks are made regarding the dimensionality of the
+ signal and number of axes. The user is responsible for providing
+ meaningful data, that can be interpreted by visualization software.
+
+ :param str filename: Path to output file. If the file does not
+ exists, it is created.
+ :param numpy.ndarray signal: Signal array.
+ :param List[numpy.ndarray] axes: List of axes arrays.
+ :param str signal_name: Name of signal dataset, in output file
+ :param List[str] axes_names: List of dataset names for axes, in
+ output file
+ :param str signal_long_name: *@long_name* attribute for signal, or None.
+ :param axes_long_names: None, or list of long names
+ for axes
+ :type axes_long_names: List[str, None]
+ :param numpy.ndarray signal_errors: Array of errors associated with the
+ signal
+ :param axes_errors: List of arrays of errors
+ associated with each axis
+ :type axes_errors: List[numpy.ndarray, None]
+ :param str title: Graph title (saved as a "title" dataset) or None.
+ :param str interpretation: *@interpretation* attribute ("spectrum",
+ "image", "rgba-image" or None). This is only needed in cases of
+ ambiguous dimensionality, e.g. a 3D array which represents a RGBA
+ image rather than a stack.
+ :param str nxentry_name: Name of group in which the NXdata group
+ is created. By default, "/entry" is used.
+
+ .. note::
+
+ The Nexus format specification requires for NXdata groups
+ be part of a NXentry group.
+ The specified group should have attribute *@NX_class=NXentry*, in
+ order for the created file to be nexus compliant.
+ :param str nxdata_name: Name of NXdata group. If omitted (None), the
+ function creates a new group using the first available name ("data0",
+ or "data1"...).
+ Overwriting an existing group (or dataset) is not supported, you must
+ delete it yourself prior to calling this function if this is what you
+ want.
+ :return: True if save was successful, else False.
+ """
+ if h5py is None:
+ raise ImportError("h5py could not be imported, but is required by "
+ "save_NXdata function")
+
+ if axes_names is not None:
+ assert axes is not None, "Axes names defined, but missing axes arrays"
+ assert len(axes) == len(axes_names), \
+ "Mismatch between number of axes and axes_names"
+
+ if axes is not None and axes_names is None:
+ axes_names = []
+ for i, axis in enumerate(axes):
+ axes_names.append("dim%d" % i if axis is not None else ".")
+ if axes is None:
+ axes = []
+
+ # Open file in
+ if os.path.exists(filename):
+ errmsg = "Cannot write/append to existing path %s"
+ if not os.path.isfile(filename):
+ errmsg += " (not a file)"
+ _logger.error(errmsg, filename)
+ return False
+ if not os.access(filename, os.W_OK):
+ errmsg += " (no permission to write)"
+ _logger.error(errmsg, filename)
+ return False
+ mode = "r+"
+ else:
+ mode = "w-"
+
+ with h5py.File(filename, mode=mode) as h5f:
+ # get or create entry
+ if nxentry_name is not None:
+ entry = h5f.require_group(nxentry_name)
+ if "default" not in h5f.attrs:
+ # set this entry as default
+ h5f.attrs["default"] = _str_to_utf8(nxentry_name)
+ if "NX_class" not in entry.attrs:
+ entry.attrs["NX_class"] = u"NXentry"
+ else:
+ # write NXdata into the root of the file (invalid nexus!)
+ entry = h5f
+
+ # Create NXdata group
+ if nxdata_name is not None:
+ if nxdata_name in entry:
+ _logger.error("Cannot assign an NXdata group to an existing"
+ " group or dataset")
+ return False
+ else:
+ # no name specified, take one that is available
+ nxdata_name = "data0"
+ i = 1
+ while nxdata_name in entry:
+ _logger.info("%s item already exists in NXentry group," +
+ " trying %s", nxdata_name, "data%d" % i)
+ nxdata_name = "data%d" % i
+ i += 1
+
+ data_group = entry.create_group(nxdata_name)
+ data_group.attrs["NX_class"] = u"NXdata"
+ data_group.attrs["signal"] = _str_to_utf8(signal_name)
+ if axes:
+ data_group.attrs["axes"] = _str_to_utf8(axes_names)
+ if title:
+ # not in NXdata spec, but implemented by nexpy
+ data_group["title"] = title
+ # better way imho
+ data_group.attrs["title"] = _str_to_utf8(title)
+
+ signal_dataset = data_group.create_dataset(signal_name,
+ data=signal)
+ if signal_long_name:
+ signal_dataset.attrs["long_name"] = _str_to_utf8(signal_long_name)
+ if interpretation:
+ signal_dataset.attrs["interpretation"] = _str_to_utf8(interpretation)
+
+ for i, axis_array in enumerate(axes):
+ if axis_array is None:
+ assert axes_names[i] in [".", None], \
+ "Axis name defined for dim %d but no axis array" % i
+ continue
+ axis_dataset = data_group.create_dataset(axes_names[i],
+ data=axis_array)
+ if axes_long_names is not None:
+ axis_dataset.attrs["long_name"] = _str_to_utf8(axes_long_names[i])
+
+ if signal_errors is not None:
+ data_group.create_dataset("errors",
+ data=signal_errors)
+
+ if axes_errors is not None:
+ assert isinstance(axes_errors, (list, tuple)), \
+ "axes_errors must be a list or a tuple of ndarray or None"
+ assert len(axes_errors) == len(axes_names), \
+ "Mismatch between number of axes_errors and axes_names"
+ for i, axis_errors in enumerate(axes_errors):
+ if axis_errors is not None:
+ dsname = axes_names[i] + "_errors"
+ data_group.create_dataset(dsname,
+ data=axis_errors)
+ if "default" not in entry.attrs:
+ # set this NXdata as default
+ entry.attrs["default"] = nxdata_name
+
+ return True
diff --git a/silx/io/specfile.c b/silx/io/specfile.c
index e244f3d..a95282a 100644
--- a/silx/io/specfile.c
+++ b/silx/io/specfile.c
@@ -1,40 +1,28 @@
-/* Generated by Cython 0.25.2 */
-
-/* BEGIN: Cython Metadata
-{
- "distutils": {
- "define_macros": [
- [
- "SPECFILE_POSIX",
- null
- ]
- ],
- "depends": [
- "/usr/lib/python2.7/dist-packages/numpy/core/include/numpy/arrayobject.h",
- "/usr/lib/python2.7/dist-packages/numpy/core/include/numpy/ufuncobject.h",
- "silx/io/specfile/include/SpecFileCython.h"
- ],
- "include_dirs": [
- "silx/io/specfile/include",
- "/usr/lib/python2.7/dist-packages/numpy/core/include"
- ],
- "language": "c"
- },
- "module_name": "silx.io.specfile"
-}
-END: Cython Metadata */
+/* Generated by Cython 0.21.1 */
#define PY_SSIZE_T_CLEAN
+#ifndef CYTHON_USE_PYLONG_INTERNALS
+#ifdef PYLONG_BITS_IN_DIGIT
+#define CYTHON_USE_PYLONG_INTERNALS 0
+#else
+#include "pyconfig.h"
+#ifdef PYLONG_BITS_IN_DIGIT
+#define CYTHON_USE_PYLONG_INTERNALS 1
+#else
+#define CYTHON_USE_PYLONG_INTERNALS 0
+#endif
+#endif
+#endif
#include "Python.h"
#ifndef Py_PYTHON_H
#error Python headers needed to compile C extensions, please install development version of Python.
#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03020000)
#error Cython requires Python 2.6+ or Python 3.2+.
#else
-#define CYTHON_ABI "0_25_2"
+#define CYTHON_ABI "0_21_1"
#include <stddef.h>
#ifndef offsetof
- #define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
+#define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
#endif
#if !defined(WIN32) && !defined(MS_WINDOWS)
#ifndef __stdcall
@@ -53,11 +41,6 @@ END: Cython Metadata */
#ifndef DL_EXPORT
#define DL_EXPORT(t) t
#endif
-#ifndef HAVE_LONG_LONG
- #if PY_VERSION_HEX >= 0x03030000 || (PY_MAJOR_VERSION == 2 && PY_VERSION_HEX >= 0x02070000)
- #define HAVE_LONG_LONG
- #endif
-#endif
#ifndef PY_LONG_LONG
#define PY_LONG_LONG LONG_LONG
#endif
@@ -65,214 +48,63 @@ END: Cython Metadata */
#define Py_HUGE_VAL HUGE_VAL
#endif
#ifdef PYPY_VERSION
- #define CYTHON_COMPILING_IN_PYPY 1
- #define CYTHON_COMPILING_IN_PYSTON 0
- #define CYTHON_COMPILING_IN_CPYTHON 0
- #undef CYTHON_USE_TYPE_SLOTS
- #define CYTHON_USE_TYPE_SLOTS 0
- #undef CYTHON_USE_ASYNC_SLOTS
- #define CYTHON_USE_ASYNC_SLOTS 0
- #undef CYTHON_USE_PYLIST_INTERNALS
- #define CYTHON_USE_PYLIST_INTERNALS 0
- #undef CYTHON_USE_UNICODE_INTERNALS
- #define CYTHON_USE_UNICODE_INTERNALS 0
- #undef CYTHON_USE_UNICODE_WRITER
- #define CYTHON_USE_UNICODE_WRITER 0
- #undef CYTHON_USE_PYLONG_INTERNALS
- #define CYTHON_USE_PYLONG_INTERNALS 0
- #undef CYTHON_AVOID_BORROWED_REFS
- #define CYTHON_AVOID_BORROWED_REFS 1
- #undef CYTHON_ASSUME_SAFE_MACROS
- #define CYTHON_ASSUME_SAFE_MACROS 0
- #undef CYTHON_UNPACK_METHODS
- #define CYTHON_UNPACK_METHODS 0
- #undef CYTHON_FAST_THREAD_STATE
- #define CYTHON_FAST_THREAD_STATE 0
- #undef CYTHON_FAST_PYCALL
- #define CYTHON_FAST_PYCALL 0
-#elif defined(PYSTON_VERSION)
- #define CYTHON_COMPILING_IN_PYPY 0
- #define CYTHON_COMPILING_IN_PYSTON 1
- #define CYTHON_COMPILING_IN_CPYTHON 0
- #ifndef CYTHON_USE_TYPE_SLOTS
- #define CYTHON_USE_TYPE_SLOTS 1
- #endif
- #undef CYTHON_USE_ASYNC_SLOTS
- #define CYTHON_USE_ASYNC_SLOTS 0
- #undef CYTHON_USE_PYLIST_INTERNALS
- #define CYTHON_USE_PYLIST_INTERNALS 0
- #ifndef CYTHON_USE_UNICODE_INTERNALS
- #define CYTHON_USE_UNICODE_INTERNALS 1
- #endif
- #undef CYTHON_USE_UNICODE_WRITER
- #define CYTHON_USE_UNICODE_WRITER 0
- #undef CYTHON_USE_PYLONG_INTERNALS
- #define CYTHON_USE_PYLONG_INTERNALS 0
- #ifndef CYTHON_AVOID_BORROWED_REFS
- #define CYTHON_AVOID_BORROWED_REFS 0
- #endif
- #ifndef CYTHON_ASSUME_SAFE_MACROS
- #define CYTHON_ASSUME_SAFE_MACROS 1
- #endif
- #ifndef CYTHON_UNPACK_METHODS
- #define CYTHON_UNPACK_METHODS 1
- #endif
- #undef CYTHON_FAST_THREAD_STATE
- #define CYTHON_FAST_THREAD_STATE 0
- #undef CYTHON_FAST_PYCALL
- #define CYTHON_FAST_PYCALL 0
+#define CYTHON_COMPILING_IN_PYPY 1
+#define CYTHON_COMPILING_IN_CPYTHON 0
#else
- #define CYTHON_COMPILING_IN_PYPY 0
- #define CYTHON_COMPILING_IN_PYSTON 0
- #define CYTHON_COMPILING_IN_CPYTHON 1
- #ifndef CYTHON_USE_TYPE_SLOTS
- #define CYTHON_USE_TYPE_SLOTS 1
- #endif
- #if PY_MAJOR_VERSION < 3
- #undef CYTHON_USE_ASYNC_SLOTS
- #define CYTHON_USE_ASYNC_SLOTS 0
- #elif !defined(CYTHON_USE_ASYNC_SLOTS)
- #define CYTHON_USE_ASYNC_SLOTS 1
- #endif
- #if PY_VERSION_HEX < 0x02070000
- #undef CYTHON_USE_PYLONG_INTERNALS
- #define CYTHON_USE_PYLONG_INTERNALS 0
- #elif !defined(CYTHON_USE_PYLONG_INTERNALS)
- #define CYTHON_USE_PYLONG_INTERNALS 1
- #endif
- #ifndef CYTHON_USE_PYLIST_INTERNALS
- #define CYTHON_USE_PYLIST_INTERNALS 1
- #endif
- #ifndef CYTHON_USE_UNICODE_INTERNALS
- #define CYTHON_USE_UNICODE_INTERNALS 1
- #endif
- #if PY_VERSION_HEX < 0x030300F0
- #undef CYTHON_USE_UNICODE_WRITER
- #define CYTHON_USE_UNICODE_WRITER 0
- #elif !defined(CYTHON_USE_UNICODE_WRITER)
- #define CYTHON_USE_UNICODE_WRITER 1
- #endif
- #ifndef CYTHON_AVOID_BORROWED_REFS
- #define CYTHON_AVOID_BORROWED_REFS 0
- #endif
- #ifndef CYTHON_ASSUME_SAFE_MACROS
- #define CYTHON_ASSUME_SAFE_MACROS 1
- #endif
- #ifndef CYTHON_UNPACK_METHODS
- #define CYTHON_UNPACK_METHODS 1
- #endif
- #ifndef CYTHON_FAST_THREAD_STATE
- #define CYTHON_FAST_THREAD_STATE 1
- #endif
- #ifndef CYTHON_FAST_PYCALL
- #define CYTHON_FAST_PYCALL 1
- #endif
+#define CYTHON_COMPILING_IN_PYPY 0
+#define CYTHON_COMPILING_IN_CPYTHON 1
#endif
-#if !defined(CYTHON_FAST_PYCCALL)
-#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1)
-#endif
-#if CYTHON_USE_PYLONG_INTERNALS
- #include "longintrepr.h"
- #undef SHIFT
- #undef BASE
- #undef MASK
-#endif
-#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag)
- #define Py_OptimizeFlag 0
+#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600
+#define Py_OptimizeFlag 0
#endif
#define __PYX_BUILD_PY_SSIZE_T "n"
#define CYTHON_FORMAT_SSIZE_T "z"
#if PY_MAJOR_VERSION < 3
#define __Pyx_BUILTIN_MODULE_NAME "__builtin__"
- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\
+ #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \
PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
#define __Pyx_DefaultClassType PyClass_Type
#else
#define __Pyx_BUILTIN_MODULE_NAME "builtins"
- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\
+ #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \
PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
#define __Pyx_DefaultClassType PyType_Type
#endif
-#ifndef Py_TPFLAGS_CHECKTYPES
+#if PY_MAJOR_VERSION >= 3
#define Py_TPFLAGS_CHECKTYPES 0
-#endif
-#ifndef Py_TPFLAGS_HAVE_INDEX
#define Py_TPFLAGS_HAVE_INDEX 0
-#endif
-#ifndef Py_TPFLAGS_HAVE_NEWBUFFER
#define Py_TPFLAGS_HAVE_NEWBUFFER 0
#endif
-#ifndef Py_TPFLAGS_HAVE_FINALIZE
+#if PY_VERSION_HEX < 0x030400a1 && !defined(Py_TPFLAGS_HAVE_FINALIZE)
#define Py_TPFLAGS_HAVE_FINALIZE 0
#endif
-#ifndef METH_FASTCALL
- #define METH_FASTCALL 0x80
- typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject **args,
- Py_ssize_t nargs, PyObject *kwnames);
-#else
- #define __Pyx_PyCFunctionFast _PyCFunctionFast
-#endif
-#if CYTHON_FAST_PYCCALL
-#define __Pyx_PyFastCFunction_Check(func)\
- ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)))))
-#else
-#define __Pyx_PyFastCFunction_Check(func) 0
-#endif
#if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND)
#define CYTHON_PEP393_ENABLED 1
- #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\
+ #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ? \
0 : _PyUnicode_Ready((PyObject *)(op)))
#define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u)
#define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i)
- #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u)
#define __Pyx_PyUnicode_KIND(u) PyUnicode_KIND(u)
#define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u)
#define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i)
- #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch)
- #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u)))
#else
#define CYTHON_PEP393_ENABLED 0
- #define PyUnicode_1BYTE_KIND 1
- #define PyUnicode_2BYTE_KIND 2
- #define PyUnicode_4BYTE_KIND 4
#define __Pyx_PyUnicode_READY(op) (0)
#define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u)
#define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i]))
- #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535 : 1114111)
#define __Pyx_PyUnicode_KIND(u) (sizeof(Py_UNICODE))
#define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u))
#define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i]))
- #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = ch)
- #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u))
#endif
#if CYTHON_COMPILING_IN_PYPY
#define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b)
#define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b)
+ #define __Pyx_PyFrozenSet_Size(s) PyObject_Size(s)
#else
#define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b)
- #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\
+ #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ? \
PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b))
-#endif
-#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains)
- #define PyUnicode_Contains(u, s) PySequence_Contains(u, s)
-#endif
-#if CYTHON_COMPILING_IN_PYPY && !defined(PyByteArray_Check)
- #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type)
-#endif
-#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format)
- #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt)
-#endif
-#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc)
- #define PyObject_Malloc(s) PyMem_Malloc(s)
- #define PyObject_Free(p) PyMem_Free(p)
- #define PyObject_Realloc(p) PyMem_Realloc(p)
-#endif
-#if CYTHON_COMPILING_IN_PYSTON
- #define __Pyx_PyCode_HasFreeVars(co) PyCode_HasFreeVars(co)
- #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno)
-#else
- #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0)
- #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno)
+ #define __Pyx_PyFrozenSet_Size(s) PySet_Size(s)
#endif
#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b))
#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b))
@@ -281,9 +113,6 @@ END: Cython Metadata */
#else
#define __Pyx_PyString_Format(a, b) PyString_Format(a, b)
#endif
-#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII)
- #define PyObject_ASCII(o) PyObject_Repr(o)
-#endif
#if PY_MAJOR_VERSION >= 3
#define PyBaseString_Type PyUnicode_Type
#define PyStringObject PyUnicodeObject
@@ -302,7 +131,6 @@ END: Cython Metadata */
#define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type)
#endif
#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type)
-#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception)
#if PY_MAJOR_VERSION >= 3
#define PyIntObject PyLongObject
#define PyInt_Type PyLong_Type
@@ -341,20 +169,16 @@ END: Cython Metadata */
#else
#define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass)
#endif
-#if CYTHON_USE_ASYNC_SLOTS
- #if PY_VERSION_HEX >= 0x030500B1
- #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
- #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async)
+#ifndef CYTHON_INLINE
+ #if defined(__GNUC__)
+ #define CYTHON_INLINE __inline__
+ #elif defined(_MSC_VER)
+ #define CYTHON_INLINE __inline
+ #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+ #define CYTHON_INLINE inline
#else
- typedef struct {
- unaryfunc am_await;
- unaryfunc am_aiter;
- unaryfunc am_anext;
- } __Pyx_PyAsyncMethodsStruct;
- #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved))
+ #define CYTHON_INLINE
#endif
-#else
- #define __Pyx_PyType_AsAsync(obj) NULL
#endif
#ifndef CYTHON_RESTRICT
#if defined(__GNUC__)
@@ -367,74 +191,26 @@ END: Cython Metadata */
#define CYTHON_RESTRICT
#endif
#endif
-#ifndef CYTHON_UNUSED
-# if defined(__GNUC__)
-# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
-# define CYTHON_UNUSED __attribute__ ((__unused__))
-# else
-# define CYTHON_UNUSED
-# endif
-# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
-# define CYTHON_UNUSED __attribute__ ((__unused__))
-# else
-# define CYTHON_UNUSED
-# endif
-#endif
-#ifndef CYTHON_MAYBE_UNUSED_VAR
-# if defined(__cplusplus)
- template<class T> void CYTHON_MAYBE_UNUSED_VAR( const T& ) { }
-# else
-# define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x)
-# endif
-#endif
-#ifndef CYTHON_NCP_UNUSED
-# if CYTHON_COMPILING_IN_CPYTHON
-# define CYTHON_NCP_UNUSED
-# else
-# define CYTHON_NCP_UNUSED CYTHON_UNUSED
-# endif
-#endif
-#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None)
-
-#ifndef CYTHON_INLINE
- #if defined(__clang__)
- #define CYTHON_INLINE __inline__ __attribute__ ((__unused__))
- #elif defined(__GNUC__)
- #define CYTHON_INLINE __inline__
- #elif defined(_MSC_VER)
- #define CYTHON_INLINE __inline
- #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
- #define CYTHON_INLINE inline
- #else
- #define CYTHON_INLINE
- #endif
-#endif
-
-#if defined(WIN32) || defined(MS_WINDOWS)
- #define _USE_MATH_DEFINES
-#endif
-#include <math.h>
#ifdef NAN
#define __PYX_NAN() ((float) NAN)
#else
static CYTHON_INLINE float __PYX_NAN() {
+ /* Initialize NaN. The sign is irrelevant, an exponent with all bits 1 and
+ a nonzero mantissa means NaN. If the first bit in the mantissa is 1, it is
+ a quiet NaN. */
float value;
memset(&value, 0xFF, sizeof(value));
return value;
}
#endif
-#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL)
-#define __Pyx_truncl trunc
-#else
-#define __Pyx_truncl truncl
+#ifdef __cplusplus
+template<typename T>
+void __Pyx_call_destructor(T* x) {
+ x->~T();
+}
#endif
-#define __PYX_ERR(f_index, lineno, Ln_error) \
-{ \
- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \
-}
-
#if PY_MAJOR_VERSION >= 3
#define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y)
#define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y)
@@ -451,11 +227,15 @@ static CYTHON_INLINE float __PYX_NAN() {
#endif
#endif
+#if defined(WIN32) || defined(MS_WINDOWS)
+#define _USE_MATH_DEFINES
+#endif
+#include <math.h>
#define __PYX_HAVE__silx__io__specfile
#define __PYX_HAVE_API__silx__io__specfile
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include "string.h"
+#include "stdio.h"
+#include "stdlib.h"
#include "numpy/arrayobject.h"
#include "numpy/ufuncobject.h"
#include "SpecFileCython.h"
@@ -467,7 +247,20 @@ static CYTHON_INLINE float __PYX_NAN() {
#define CYTHON_WITHOUT_ASSERTIONS
#endif
-typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding;
+#ifndef CYTHON_UNUSED
+# if defined(__GNUC__)
+# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+# define CYTHON_UNUSED __attribute__ ((__unused__))
+# else
+# define CYTHON_UNUSED
+# endif
+# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
+# define CYTHON_UNUSED __attribute__ ((__unused__))
+# else
+# define CYTHON_UNUSED
+# endif
+#endif
+typedef struct {PyObject **p; char *s; const Py_ssize_t n; const char* encoding;
const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry;
#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0
@@ -475,34 +268,16 @@ typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* enc
#define __PYX_DEFAULT_STRING_ENCODING ""
#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString
#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize
-#define __Pyx_uchar_cast(c) ((unsigned char)c)
-#define __Pyx_long_cast(x) ((long)x)
-#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\
- (sizeof(type) < sizeof(Py_ssize_t)) ||\
- (sizeof(type) > sizeof(Py_ssize_t) &&\
- likely(v < (type)PY_SSIZE_T_MAX ||\
- v == (type)PY_SSIZE_T_MAX) &&\
- (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\
- v == (type)PY_SSIZE_T_MIN))) ||\
- (sizeof(type) == sizeof(Py_ssize_t) &&\
- (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\
+#define __Pyx_fits_Py_ssize_t(v, type, is_signed) ( \
+ (sizeof(type) < sizeof(Py_ssize_t)) || \
+ (sizeof(type) > sizeof(Py_ssize_t) && \
+ likely(v < (type)PY_SSIZE_T_MAX || \
+ v == (type)PY_SSIZE_T_MAX) && \
+ (!is_signed || likely(v > (type)PY_SSIZE_T_MIN || \
+ v == (type)PY_SSIZE_T_MIN))) || \
+ (sizeof(type) == sizeof(Py_ssize_t) && \
+ (is_signed || likely(v < (type)PY_SSIZE_T_MAX || \
v == (type)PY_SSIZE_T_MAX))) )
-#if defined (__cplusplus) && __cplusplus >= 201103L
- #include <cstdlib>
- #define __Pyx_sst_abs(value) std::abs(value)
-#elif SIZEOF_INT >= SIZEOF_SIZE_T
- #define __Pyx_sst_abs(value) abs(value)
-#elif SIZEOF_LONG >= SIZEOF_SIZE_T
- #define __Pyx_sst_abs(value) labs(value)
-#elif defined (_MSC_VER) && defined (_M_X64)
- #define __Pyx_sst_abs(value) _abs64(value)
-#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
- #define __Pyx_sst_abs(value) llabs(value)
-#elif defined (__GNUC__)
- #define __Pyx_sst_abs(value) __builtin_llabs(value)
-#else
- #define __Pyx_sst_abs(value) ((value<0) ? -value : value)
-#endif
static CYTHON_INLINE char* __Pyx_PyObject_AsString(PyObject*);
static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length);
#define __Pyx_PyByteArray_FromString(s) PyByteArray_FromStringAndSize((const char*)s, strlen((const char*)s))
@@ -519,11 +294,11 @@ static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*);
#endif
#define __Pyx_PyObject_AsSString(s) ((signed char*) __Pyx_PyObject_AsString(s))
#define __Pyx_PyObject_AsUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s))
-#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s)
-#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s)
-#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s)
-#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s)
-#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s)
+#define __Pyx_PyObject_FromUString(s) __Pyx_PyObject_FromString((const char*)s)
+#define __Pyx_PyBytes_FromUString(s) __Pyx_PyBytes_FromString((const char*)s)
+#define __Pyx_PyByteArray_FromUString(s) __Pyx_PyByteArray_FromString((const char*)s)
+#define __Pyx_PyStr_FromUString(s) __Pyx_PyStr_FromString((const char*)s)
+#define __Pyx_PyUnicode_FromUString(s) __Pyx_PyUnicode_FromString((const char*)s)
#if PY_MAJOR_VERSION < 3
static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)
{
@@ -537,25 +312,18 @@ static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)
#define __Pyx_PyUnicode_FromUnicode(u) PyUnicode_FromUnicode(u, __Pyx_Py_UNICODE_strlen(u))
#define __Pyx_PyUnicode_FromUnicodeAndLength PyUnicode_FromUnicode
#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode
-#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj)
-#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None)
-#define __Pyx_PyBool_FromLong(b) ((b) ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False))
+#define __Pyx_Owned_Py_None(b) (Py_INCREF(Py_None), Py_None)
+#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
-static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
+static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x);
static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
-#if CYTHON_ASSUME_SAFE_MACROS
+#if CYTHON_COMPILING_IN_CPYTHON
#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))
#else
#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x)
#endif
#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x))
-#if PY_MAJOR_VERSION >= 3
-#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x))
-#else
-#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x))
-#endif
-#define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Float(x))
#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII
static int __Pyx_sys_getdefaultencoding_not_ascii;
static int __Pyx_init_sys_getdefaultencoding_params(void) {
@@ -566,7 +334,7 @@ static int __Pyx_init_sys_getdefaultencoding_params(void) {
const char* default_encoding_c;
sys = PyImport_ImportModule("sys");
if (!sys) goto bad;
- default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL);
+ default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL);
Py_DECREF(sys);
if (!default_encoding) goto bad;
default_encoding_c = PyBytes_AsString(default_encoding);
@@ -646,13 +414,11 @@ static PyObject *__pyx_d;
static PyObject *__pyx_b;
static PyObject *__pyx_empty_tuple;
static PyObject *__pyx_empty_bytes;
-static PyObject *__pyx_empty_unicode;
static int __pyx_lineno;
static int __pyx_clineno = 0;
static const char * __pyx_cfilenm= __FILE__;
static const char *__pyx_filename;
-/* Header.proto */
#if !defined(CYTHON_CCOMPLEX)
#if defined(__cplusplus)
#define CYTHON_CCOMPLEX 1
@@ -681,7 +447,7 @@ static const char *__pyx_f[] = {
"type.pxd",
};
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":725
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":723
* # in Cython to enable them only on the right systems.
*
* ctypedef npy_int8 int8_t # <<<<<<<<<<<<<<
@@ -690,7 +456,7 @@ static const char *__pyx_f[] = {
*/
typedef npy_int8 __pyx_t_5numpy_int8_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":726
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":724
*
* ctypedef npy_int8 int8_t
* ctypedef npy_int16 int16_t # <<<<<<<<<<<<<<
@@ -699,7 +465,7 @@ typedef npy_int8 __pyx_t_5numpy_int8_t;
*/
typedef npy_int16 __pyx_t_5numpy_int16_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":727
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":725
* ctypedef npy_int8 int8_t
* ctypedef npy_int16 int16_t
* ctypedef npy_int32 int32_t # <<<<<<<<<<<<<<
@@ -708,7 +474,7 @@ typedef npy_int16 __pyx_t_5numpy_int16_t;
*/
typedef npy_int32 __pyx_t_5numpy_int32_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":728
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":726
* ctypedef npy_int16 int16_t
* ctypedef npy_int32 int32_t
* ctypedef npy_int64 int64_t # <<<<<<<<<<<<<<
@@ -717,7 +483,7 @@ typedef npy_int32 __pyx_t_5numpy_int32_t;
*/
typedef npy_int64 __pyx_t_5numpy_int64_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":732
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":730
* #ctypedef npy_int128 int128_t
*
* ctypedef npy_uint8 uint8_t # <<<<<<<<<<<<<<
@@ -726,7 +492,7 @@ typedef npy_int64 __pyx_t_5numpy_int64_t;
*/
typedef npy_uint8 __pyx_t_5numpy_uint8_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":733
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":731
*
* ctypedef npy_uint8 uint8_t
* ctypedef npy_uint16 uint16_t # <<<<<<<<<<<<<<
@@ -735,7 +501,7 @@ typedef npy_uint8 __pyx_t_5numpy_uint8_t;
*/
typedef npy_uint16 __pyx_t_5numpy_uint16_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":734
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":732
* ctypedef npy_uint8 uint8_t
* ctypedef npy_uint16 uint16_t
* ctypedef npy_uint32 uint32_t # <<<<<<<<<<<<<<
@@ -744,7 +510,7 @@ typedef npy_uint16 __pyx_t_5numpy_uint16_t;
*/
typedef npy_uint32 __pyx_t_5numpy_uint32_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":735
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":733
* ctypedef npy_uint16 uint16_t
* ctypedef npy_uint32 uint32_t
* ctypedef npy_uint64 uint64_t # <<<<<<<<<<<<<<
@@ -753,7 +519,7 @@ typedef npy_uint32 __pyx_t_5numpy_uint32_t;
*/
typedef npy_uint64 __pyx_t_5numpy_uint64_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":739
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":737
* #ctypedef npy_uint128 uint128_t
*
* ctypedef npy_float32 float32_t # <<<<<<<<<<<<<<
@@ -762,7 +528,7 @@ typedef npy_uint64 __pyx_t_5numpy_uint64_t;
*/
typedef npy_float32 __pyx_t_5numpy_float32_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":740
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":738
*
* ctypedef npy_float32 float32_t
* ctypedef npy_float64 float64_t # <<<<<<<<<<<<<<
@@ -771,7 +537,7 @@ typedef npy_float32 __pyx_t_5numpy_float32_t;
*/
typedef npy_float64 __pyx_t_5numpy_float64_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":749
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":747
* # The int types are mapped a bit surprising --
* # numpy.int corresponds to 'l' and numpy.long to 'q'
* ctypedef npy_long int_t # <<<<<<<<<<<<<<
@@ -780,7 +546,7 @@ typedef npy_float64 __pyx_t_5numpy_float64_t;
*/
typedef npy_long __pyx_t_5numpy_int_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":750
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":748
* # numpy.int corresponds to 'l' and numpy.long to 'q'
* ctypedef npy_long int_t
* ctypedef npy_longlong long_t # <<<<<<<<<<<<<<
@@ -789,7 +555,7 @@ typedef npy_long __pyx_t_5numpy_int_t;
*/
typedef npy_longlong __pyx_t_5numpy_long_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":751
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":749
* ctypedef npy_long int_t
* ctypedef npy_longlong long_t
* ctypedef npy_longlong longlong_t # <<<<<<<<<<<<<<
@@ -798,7 +564,7 @@ typedef npy_longlong __pyx_t_5numpy_long_t;
*/
typedef npy_longlong __pyx_t_5numpy_longlong_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":753
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":751
* ctypedef npy_longlong longlong_t
*
* ctypedef npy_ulong uint_t # <<<<<<<<<<<<<<
@@ -807,7 +573,7 @@ typedef npy_longlong __pyx_t_5numpy_longlong_t;
*/
typedef npy_ulong __pyx_t_5numpy_uint_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":754
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":752
*
* ctypedef npy_ulong uint_t
* ctypedef npy_ulonglong ulong_t # <<<<<<<<<<<<<<
@@ -816,7 +582,7 @@ typedef npy_ulong __pyx_t_5numpy_uint_t;
*/
typedef npy_ulonglong __pyx_t_5numpy_ulong_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":755
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":753
* ctypedef npy_ulong uint_t
* ctypedef npy_ulonglong ulong_t
* ctypedef npy_ulonglong ulonglong_t # <<<<<<<<<<<<<<
@@ -825,7 +591,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulong_t;
*/
typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":757
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":755
* ctypedef npy_ulonglong ulonglong_t
*
* ctypedef npy_intp intp_t # <<<<<<<<<<<<<<
@@ -834,7 +600,7 @@ typedef npy_ulonglong __pyx_t_5numpy_ulonglong_t;
*/
typedef npy_intp __pyx_t_5numpy_intp_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":758
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":756
*
* ctypedef npy_intp intp_t
* ctypedef npy_uintp uintp_t # <<<<<<<<<<<<<<
@@ -843,7 +609,7 @@ typedef npy_intp __pyx_t_5numpy_intp_t;
*/
typedef npy_uintp __pyx_t_5numpy_uintp_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":760
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":758
* ctypedef npy_uintp uintp_t
*
* ctypedef npy_double float_t # <<<<<<<<<<<<<<
@@ -852,7 +618,7 @@ typedef npy_uintp __pyx_t_5numpy_uintp_t;
*/
typedef npy_double __pyx_t_5numpy_float_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":761
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":759
*
* ctypedef npy_double float_t
* ctypedef npy_double double_t # <<<<<<<<<<<<<<
@@ -861,7 +627,7 @@ typedef npy_double __pyx_t_5numpy_float_t;
*/
typedef npy_double __pyx_t_5numpy_double_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":762
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":760
* ctypedef npy_double float_t
* ctypedef npy_double double_t
* ctypedef npy_longdouble longdouble_t # <<<<<<<<<<<<<<
@@ -869,7 +635,6 @@ typedef npy_double __pyx_t_5numpy_double_t;
* ctypedef npy_cfloat cfloat_t
*/
typedef npy_longdouble __pyx_t_5numpy_longdouble_t;
-/* Declarations.proto */
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
typedef ::std::complex< float > __pyx_t_float_complex;
@@ -879,9 +644,7 @@ typedef npy_longdouble __pyx_t_5numpy_longdouble_t;
#else
typedef struct { float real, imag; } __pyx_t_float_complex;
#endif
-static CYTHON_INLINE __pyx_t_float_complex __pyx_t_float_complex_from_parts(float, float);
-/* Declarations.proto */
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
typedef ::std::complex< double > __pyx_t_double_complex;
@@ -891,7 +654,6 @@ static CYTHON_INLINE __pyx_t_float_complex __pyx_t_float_complex_from_parts(floa
#else
typedef struct { double real, imag; } __pyx_t_double_complex;
#endif
-static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double, double);
/*--- Type declarations ---*/
@@ -899,7 +661,7 @@ struct __pyx_obj_4silx_2io_8specfile_SpecFile;
struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct____iter__;
struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct_1___iter__;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":764
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":762
* ctypedef npy_longdouble longdouble_t
*
* ctypedef npy_cfloat cfloat_t # <<<<<<<<<<<<<<
@@ -908,7 +670,7 @@ struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct_1___iter__;
*/
typedef npy_cfloat __pyx_t_5numpy_cfloat_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":765
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":763
*
* ctypedef npy_cfloat cfloat_t
* ctypedef npy_cdouble cdouble_t # <<<<<<<<<<<<<<
@@ -917,7 +679,7 @@ typedef npy_cfloat __pyx_t_5numpy_cfloat_t;
*/
typedef npy_cdouble __pyx_t_5numpy_cdouble_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":766
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":764
* ctypedef npy_cfloat cfloat_t
* ctypedef npy_cdouble cdouble_t
* ctypedef npy_clongdouble clongdouble_t # <<<<<<<<<<<<<<
@@ -926,7 +688,7 @@ typedef npy_cdouble __pyx_t_5numpy_cdouble_t;
*/
typedef npy_clongdouble __pyx_t_5numpy_clongdouble_t;
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":768
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":766
* ctypedef npy_clongdouble clongdouble_t
*
* ctypedef npy_cdouble complex_t # <<<<<<<<<<<<<<
@@ -944,7 +706,7 @@ typedef npy_cdouble __pyx_t_5numpy_complex_t;
*/
typedef struct _SpecFile __pyx_t_4silx_2io_16specfile_wrapper_SpecFileHandle;
-/* "silx/io/specfile.pyx":644
+/* "silx/io/specfile.pyx":643
*
*
* cdef class SpecFile(object): # <<<<<<<<<<<<<<
@@ -974,7 +736,7 @@ struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct____iter__ {
};
-/* "silx/io/specfile.pyx":694
+/* "silx/io/specfile.pyx":698
* return specfile_wrapper.SfScanNo(self.handle)
*
* def __iter__(self): # <<<<<<<<<<<<<<
@@ -989,9 +751,6 @@ struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct_1___iter__ {
Py_ssize_t __pyx_t_1;
};
-
-/* --- Runtime support code (head) --- */
-/* Refnanny.proto */
#ifndef CYTHON_REFNANNY
#define CYTHON_REFNANNY 0
#endif
@@ -1008,19 +767,19 @@ struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct_1___iter__ {
static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname);
#define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL;
#ifdef WITH_THREAD
- #define __Pyx_RefNannySetupContext(name, acquire_gil)\
- if (acquire_gil) {\
- PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\
- __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\
- PyGILState_Release(__pyx_gilstate_save);\
- } else {\
- __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\
+ #define __Pyx_RefNannySetupContext(name, acquire_gil) \
+ if (acquire_gil) { \
+ PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure(); \
+ __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__); \
+ PyGILState_Release(__pyx_gilstate_save); \
+ } else { \
+ __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__); \
}
#else
- #define __Pyx_RefNannySetupContext(name, acquire_gil)\
+ #define __Pyx_RefNannySetupContext(name, acquire_gil) \
__pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__)
#endif
- #define __Pyx_RefNannyFinishContext()\
+ #define __Pyx_RefNannyFinishContext() \
__Pyx_RefNanny->FinishContext(&__pyx_refnanny)
#define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
#define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
@@ -1043,19 +802,18 @@ struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct_1___iter__ {
#define __Pyx_XGOTREF(r)
#define __Pyx_XGIVEREF(r)
#endif
-#define __Pyx_XDECREF_SET(r, v) do {\
- PyObject *tmp = (PyObject *) r;\
- r = v; __Pyx_XDECREF(tmp);\
+#define __Pyx_XDECREF_SET(r, v) do { \
+ PyObject *tmp = (PyObject *) r; \
+ r = v; __Pyx_XDECREF(tmp); \
} while (0)
-#define __Pyx_DECREF_SET(r, v) do {\
- PyObject *tmp = (PyObject *) r;\
- r = v; __Pyx_DECREF(tmp);\
+#define __Pyx_DECREF_SET(r, v) do { \
+ PyObject *tmp = (PyObject *) r; \
+ r = v; __Pyx_DECREF(tmp); \
} while (0)
#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0)
#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0)
-/* PyObjectGetAttrStr.proto */
-#if CYTHON_USE_TYPE_SLOTS
+#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) {
PyTypeObject* tp = Py_TYPE(obj);
if (likely(tp->tp_getattro))
@@ -1070,23 +828,18 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject
#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n)
#endif
-/* GetBuiltinName.proto */
static PyObject *__Pyx_GetBuiltinName(PyObject *name);
-/* RaiseArgTupleInvalid.proto */
static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found);
-/* RaiseDoubleKeywords.proto */
static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name);
-/* ParseKeywords.proto */
-static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\
- PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\
+static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[], \
+ PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, \
const char* function_name);
-/* PyObjectSetAttrStr.proto */
-#if CYTHON_USE_TYPE_SLOTS
+#if CYTHON_COMPILING_IN_CPYTHON
#define __Pyx_PyObject_DelAttrStr(o,n) __Pyx_PyObject_SetAttrStr(o,n,NULL)
static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value) {
PyTypeObject* tp = Py_TYPE(obj);
@@ -1103,54 +856,30 @@ static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr
#define __Pyx_PyObject_SetAttrStr(o,n,v) PyObject_SetAttr(o,n,v)
#endif
-/* PyCFunctionFastCall.proto */
-#if CYTHON_FAST_PYCCALL
-static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs);
-#else
-#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL)
-#endif
-
-/* PyFunctionFastCall.proto */
-#if CYTHON_FAST_PYCALL
-#define __Pyx_PyFunction_FastCall(func, args, nargs)\
- __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL)
-#if 1 || PY_VERSION_HEX < 0x030600B1
-static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs);
-#else
-#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs)
-#endif
-#endif
-
-/* PyObjectCall.proto */
#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw);
#else
#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw)
#endif
-/* PyObjectCallMethO.proto */
#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg);
#endif
-/* PyObjectCallOneArg.proto */
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg);
-/* PyObjectCallNoArg.proto */
#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func);
#else
#define __Pyx_PyObject_CallNoArg(func) __Pyx_PyObject_Call(func, __pyx_empty_tuple, NULL)
#endif
-/* PySequenceContains.proto */
-static CYTHON_INLINE int __Pyx_PySequence_ContainsTF(PyObject* item, PyObject* seq, int eq) {
+static CYTHON_INLINE int __Pyx_PySequence_Contains(PyObject* item, PyObject* seq, int eq) {
int result = PySequence_Contains(seq, item);
return unlikely(result < 0) ? result : (result == (eq == Py_EQ));
}
-/* ListCompAppend.proto */
-#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS
+#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) {
PyListObject* L = (PyListObject*) list;
Py_ssize_t len = Py_SIZE(list);
@@ -1166,20 +895,15 @@ static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) {
#define __Pyx_ListComp_Append(L,x) PyList_Append(L,x)
#endif
-/* RaiseTooManyValuesToUnpack.proto */
static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected);
-/* RaiseNeedMoreValuesToUnpack.proto */
static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index);
-/* IterFinish.proto */
static CYTHON_INLINE int __Pyx_IterFinish(void);
-/* UnpackItemEndCheck.proto */
static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected);
-/* ListAppend.proto */
-#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS
+#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) {
PyListObject* L = (PyListObject*) list;
Py_ssize_t len = Py_SIZE(list);
@@ -1195,35 +919,24 @@ static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) {
#define __Pyx_PyList_Append(L,x) PyList_Append(L,x)
#endif
-/* PyObjectCallMethod1.proto */
static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg);
-/* append.proto */
static CYTHON_INLINE int __Pyx_PyObject_Append(PyObject* L, PyObject* x);
-/* PyIntBinop.proto */
-#if !CYTHON_COMPILING_IN_PYPY
-static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace);
-#else
-#define __Pyx_PyInt_AddObjC(op1, op2, intval, inplace)\
- (inplace ? PyNumber_InPlaceAdd(op1, op2) : PyNumber_Add(op1, op2))
-#endif
-
-/* GetItemInt.proto */
-#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
- (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
- __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\
- (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\
+#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck) \
+ (__Pyx_fits_Py_ssize_t(i, type, is_signed) ? \
+ __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) : \
+ (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) : \
__Pyx_GetItemInt_Generic(o, to_py_func(i))))
-#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
- (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
- __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\
+#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck) \
+ (__Pyx_fits_Py_ssize_t(i, type, is_signed) ? \
+ __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) : \
(PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL))
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i,
int wraparound, int boundscheck);
-#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
- (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
- __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\
+#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck) \
+ (__Pyx_fits_Py_ssize_t(i, type, is_signed) ? \
+ __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) : \
(PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL))
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i,
int wraparound, int boundscheck);
@@ -1231,77 +944,49 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
int is_list, int wraparound, int boundscheck);
-/* PyIntBinop.proto */
-#if !CYTHON_COMPILING_IN_PYPY
-static PyObject* __Pyx_PyInt_SubtractObjC(PyObject *op1, PyObject *op2, long intval, int inplace);
-#else
-#define __Pyx_PyInt_SubtractObjC(op1, op2, intval, inplace)\
- (inplace ? PyNumber_InPlaceSubtract(op1, op2) : PyNumber_Subtract(op1, op2))
-#endif
+static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb);
+static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb);
-/* PyThreadStateGet.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate;
-#define __Pyx_PyThreadState_assign __pyx_tstate = PyThreadState_GET();
-#else
-#define __Pyx_PyThreadState_declare
-#define __Pyx_PyThreadState_assign
-#endif
+static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause);
-/* PyErrFetchRestore.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb)
-#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb)
-#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb)
-#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb)
-static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb);
-static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
-#else
-#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb)
-#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb)
-#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb)
-#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb)
-#endif
+static CYTHON_INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb);
+static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb);
-/* RaiseException.proto */
-static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause);
+static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb);
-/* SaveResetException.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb)
-static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
-#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb)
-static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb);
-#else
-#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb)
-#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb)
-#endif
+static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name);
-/* PyErrExceptionMatches.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err)
-static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err);
-#else
-#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err)
+#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02070000
+static CYTHON_INLINE PyObject* __Pyx_PyObject_LookupSpecial(PyObject* obj, PyObject* attr_name) {
+ PyObject *res;
+ PyTypeObject *tp = Py_TYPE(obj);
+#if PY_MAJOR_VERSION < 3
+ if (unlikely(PyInstance_Check(obj)))
+ return __Pyx_PyObject_GetAttrStr(obj, attr_name);
#endif
-
-/* GetException.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb)
-static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
+ res = _PyType_Lookup(tp, attr_name);
+ if (likely(res)) {
+ descrgetfunc f = Py_TYPE(res)->tp_descr_get;
+ if (!f) {
+ Py_INCREF(res);
+ } else {
+ res = f(res, obj, (PyObject *)tp);
+ }
+ } else {
+ PyErr_SetObject(PyExc_AttributeError, attr_name);
+ }
+ return res;
+}
#else
-static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb);
+#define __Pyx_PyObject_LookupSpecial(o,n) __Pyx_PyObject_GetAttrStr(o,n)
#endif
-/* GetModuleGlobalName.proto */
-static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name);
+static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname);
-/* WriteUnraisableException.proto */
static void __Pyx_WriteUnraisable(const char *name, int clineno,
int lineno, const char *filename,
- int full_traceback, int nogil);
+ int full_traceback);
-/* StringJoin.proto */
#if PY_MAJOR_VERSION < 3
#define __Pyx_PyString_Join __Pyx_PyBytes_Join
#define __Pyx_PyBaseString_Join(s, v) (PyUnicode_CheckExact(s) ? PyUnicode_Join(s, v) : __Pyx_PyBytes_Join(s, v))
@@ -1319,14 +1004,12 @@ static void __Pyx_WriteUnraisable(const char *name, int clineno,
static CYTHON_INLINE PyObject* __Pyx_PyBytes_Join(PyObject* sep, PyObject* values);
#endif
-/* PyDictContains.proto */
-static CYTHON_INLINE int __Pyx_PyDict_ContainsTF(PyObject* item, PyObject* dict, int eq) {
+static CYTHON_INLINE int __Pyx_PyDict_Contains(PyObject* item, PyObject* dict, int eq) {
int result = PyDict_Contains(dict, item);
return unlikely(result < 0) ? result : (result == (eq == Py_EQ));
}
-/* DictGetItem.proto */
-#if PY_MAJOR_VERSION >= 3 && !CYTHON_COMPILING_IN_PYPY
+#if PY_MAJOR_VERSION >= 3
static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
PyObject *value;
value = PyDict_GetItemWithError(d, key);
@@ -1346,13 +1029,11 @@ static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key)
#endif
-/* decode_c_bytes.proto */
static CYTHON_INLINE PyObject* __Pyx_decode_c_bytes(
const char* cstring, Py_ssize_t length, Py_ssize_t start, Py_ssize_t stop,
const char* encoding, const char* errors,
PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors));
-/* decode_bytes.proto */
static CYTHON_INLINE PyObject* __Pyx_decode_bytes(
PyObject* string, Py_ssize_t start, Py_ssize_t stop,
const char* encoding, const char* errors,
@@ -1362,67 +1043,47 @@ static CYTHON_INLINE PyObject* __Pyx_decode_bytes(
start, stop, encoding, errors, decode_func);
}
-/* PyIntBinop.proto */
-#if !CYTHON_COMPILING_IN_PYPY
-static PyObject* __Pyx_PyInt_EqObjC(PyObject *op1, PyObject *op2, long intval, int inplace);
-#else
-#define __Pyx_PyInt_EqObjC(op1, op2, intval, inplace)\
- PyObject_RichCompare(op1, op2, Py_EQ)
- #endif
-
-/* ExtTypeTest.proto */
static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type);
-/* SetItemInt.proto */
-#define __Pyx_SetItemInt(o, i, v, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
- (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
- __Pyx_SetItemInt_Fast(o, (Py_ssize_t)i, v, is_list, wraparound, boundscheck) :\
- (is_list ? (PyErr_SetString(PyExc_IndexError, "list assignment index out of range"), -1) :\
+#define __Pyx_SetItemInt(o, i, v, type, is_signed, to_py_func, is_list, wraparound, boundscheck) \
+ (__Pyx_fits_Py_ssize_t(i, type, is_signed) ? \
+ __Pyx_SetItemInt_Fast(o, (Py_ssize_t)i, v, is_list, wraparound, boundscheck) : \
+ (is_list ? (PyErr_SetString(PyExc_IndexError, "list assignment index out of range"), -1) : \
__Pyx_SetItemInt_Generic(o, to_py_func(i), v)))
static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v);
static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v,
int is_list, int wraparound, int boundscheck);
-/* IncludeStringH.proto */
#include <string.h>
-/* decode_c_string.proto */
static CYTHON_INLINE PyObject* __Pyx_decode_c_string(
const char* cstring, Py_ssize_t start, Py_ssize_t stop,
const char* encoding, const char* errors,
PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors));
-/* RaiseNoneIterError.proto */
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void);
-/* Import.proto */
-static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level);
-
-/* CalculateMetaclass.proto */
static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases);
-/* Py3ClassCreate.proto */
static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *qualname,
PyObject *mkw, PyObject *modname, PyObject *doc);
static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict,
PyObject *mkw, int calculate_metaclass, int allow_py2_metaclass);
-/* FetchCommonType.proto */
static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type);
-/* CythonFunction.proto */
#define __Pyx_CyFunction_USED 1
#include <structmember.h>
#define __Pyx_CYFUNCTION_STATICMETHOD 0x01
#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02
#define __Pyx_CYFUNCTION_CCLASS 0x04
-#define __Pyx_CyFunction_GetClosure(f)\
+#define __Pyx_CyFunction_GetClosure(f) \
(((__pyx_CyFunctionObject *) (f))->func_closure)
-#define __Pyx_CyFunction_GetClassObj(f)\
+#define __Pyx_CyFunction_GetClassObj(f) \
(((__pyx_CyFunctionObject *) (f))->func_classobj)
-#define __Pyx_CyFunction_Defaults(type, f)\
+#define __Pyx_CyFunction_Defaults(type, f) \
((type *)(((__pyx_CyFunctionObject *) (f))->defaults))
-#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\
+#define __Pyx_CyFunction_SetDefaultsGetter(f, g) \
((__pyx_CyFunctionObject *) (f))->defaults_getter = (g)
typedef struct {
PyCFunctionObject func;
@@ -1446,7 +1107,7 @@ typedef struct {
PyObject *func_annotations;
} __pyx_CyFunctionObject;
static PyTypeObject *__pyx_CyFunctionType = 0;
-#define __Pyx_CyFunction_NewEx(ml, flags, qualname, self, module, globals, code)\
+#define __Pyx_CyFunction_NewEx(ml, flags, qualname, self, module, globals, code) \
__Pyx_CyFunction_New(__pyx_CyFunctionType, ml, flags, qualname, self, module, globals, code)
static PyObject *__Pyx_CyFunction_New(PyTypeObject *, PyMethodDef *ml,
int flags, PyObject* qualname,
@@ -1462,12 +1123,11 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m,
PyObject *dict);
static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m,
PyObject *dict);
-static int __pyx_CyFunction_init(void);
+static int __Pyx_CyFunction_init(void);
-/* CodeObjectCache.proto */
typedef struct {
- PyCodeObject* code_object;
int code_line;
+ PyCodeObject* code_object;
} __Pyx_CodeObjectCacheEntry;
struct __Pyx_CodeObjectCache {
int count;
@@ -1479,17 +1139,19 @@ static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int co
static PyCodeObject *__pyx_find_code_object(int code_line);
static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object);
-/* AddTraceback.proto */
static void __Pyx_AddTraceback(const char *funcname, int c_line,
int py_line, const char *filename);
-/* CIntToPy.proto */
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level);
+
static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value);
-/* CIntToPy.proto */
+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *);
+
static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value);
-/* RealImag.proto */
+static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *);
+
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
#define __Pyx_CREAL(z) ((z).real())
@@ -1502,8 +1164,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value);
#define __Pyx_CREAL(z) ((z).real)
#define __Pyx_CIMAG(z) ((z).imag)
#endif
-#if defined(__cplusplus) && CYTHON_CCOMPLEX\
- && (defined(_WIN32) || defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 5 || __GNUC__ == 4 && __GNUC_MINOR__ >= 4 )) || __cplusplus >= 201103)
+#if (defined(_WIN32) || defined(__clang__)) && defined(__cplusplus) && CYTHON_CCOMPLEX
#define __Pyx_SET_CREAL(z,x) ((z).real(x))
#define __Pyx_SET_CIMAG(z,y) ((z).imag(y))
#else
@@ -1511,104 +1172,93 @@ static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value);
#define __Pyx_SET_CIMAG(z,y) __Pyx_CIMAG(z) = (y)
#endif
-/* Arithmetic.proto */
+static CYTHON_INLINE __pyx_t_float_complex __pyx_t_float_complex_from_parts(float, float);
+
#if CYTHON_CCOMPLEX
- #define __Pyx_c_eq_float(a, b) ((a)==(b))
- #define __Pyx_c_sum_float(a, b) ((a)+(b))
- #define __Pyx_c_diff_float(a, b) ((a)-(b))
- #define __Pyx_c_prod_float(a, b) ((a)*(b))
- #define __Pyx_c_quot_float(a, b) ((a)/(b))
- #define __Pyx_c_neg_float(a) (-(a))
+ #define __Pyx_c_eqf(a, b) ((a)==(b))
+ #define __Pyx_c_sumf(a, b) ((a)+(b))
+ #define __Pyx_c_difff(a, b) ((a)-(b))
+ #define __Pyx_c_prodf(a, b) ((a)*(b))
+ #define __Pyx_c_quotf(a, b) ((a)/(b))
+ #define __Pyx_c_negf(a) (-(a))
#ifdef __cplusplus
- #define __Pyx_c_is_zero_float(z) ((z)==(float)0)
- #define __Pyx_c_conj_float(z) (::std::conj(z))
+ #define __Pyx_c_is_zerof(z) ((z)==(float)0)
+ #define __Pyx_c_conjf(z) (::std::conj(z))
#if 1
- #define __Pyx_c_abs_float(z) (::std::abs(z))
- #define __Pyx_c_pow_float(a, b) (::std::pow(a, b))
+ #define __Pyx_c_absf(z) (::std::abs(z))
+ #define __Pyx_c_powf(a, b) (::std::pow(a, b))
#endif
#else
- #define __Pyx_c_is_zero_float(z) ((z)==0)
- #define __Pyx_c_conj_float(z) (conjf(z))
+ #define __Pyx_c_is_zerof(z) ((z)==0)
+ #define __Pyx_c_conjf(z) (conjf(z))
#if 1
- #define __Pyx_c_abs_float(z) (cabsf(z))
- #define __Pyx_c_pow_float(a, b) (cpowf(a, b))
+ #define __Pyx_c_absf(z) (cabsf(z))
+ #define __Pyx_c_powf(a, b) (cpowf(a, b))
#endif
#endif
#else
- static CYTHON_INLINE int __Pyx_c_eq_float(__pyx_t_float_complex, __pyx_t_float_complex);
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_sum_float(__pyx_t_float_complex, __pyx_t_float_complex);
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_diff_float(__pyx_t_float_complex, __pyx_t_float_complex);
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_prod_float(__pyx_t_float_complex, __pyx_t_float_complex);
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_quot_float(__pyx_t_float_complex, __pyx_t_float_complex);
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_neg_float(__pyx_t_float_complex);
- static CYTHON_INLINE int __Pyx_c_is_zero_float(__pyx_t_float_complex);
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_conj_float(__pyx_t_float_complex);
+ static CYTHON_INLINE int __Pyx_c_eqf(__pyx_t_float_complex, __pyx_t_float_complex);
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_sumf(__pyx_t_float_complex, __pyx_t_float_complex);
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_difff(__pyx_t_float_complex, __pyx_t_float_complex);
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_prodf(__pyx_t_float_complex, __pyx_t_float_complex);
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_quotf(__pyx_t_float_complex, __pyx_t_float_complex);
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_negf(__pyx_t_float_complex);
+ static CYTHON_INLINE int __Pyx_c_is_zerof(__pyx_t_float_complex);
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_conjf(__pyx_t_float_complex);
#if 1
- static CYTHON_INLINE float __Pyx_c_abs_float(__pyx_t_float_complex);
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_pow_float(__pyx_t_float_complex, __pyx_t_float_complex);
+ static CYTHON_INLINE float __Pyx_c_absf(__pyx_t_float_complex);
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_powf(__pyx_t_float_complex, __pyx_t_float_complex);
#endif
#endif
-/* Arithmetic.proto */
+static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double, double);
+
#if CYTHON_CCOMPLEX
- #define __Pyx_c_eq_double(a, b) ((a)==(b))
- #define __Pyx_c_sum_double(a, b) ((a)+(b))
- #define __Pyx_c_diff_double(a, b) ((a)-(b))
- #define __Pyx_c_prod_double(a, b) ((a)*(b))
- #define __Pyx_c_quot_double(a, b) ((a)/(b))
- #define __Pyx_c_neg_double(a) (-(a))
+ #define __Pyx_c_eq(a, b) ((a)==(b))
+ #define __Pyx_c_sum(a, b) ((a)+(b))
+ #define __Pyx_c_diff(a, b) ((a)-(b))
+ #define __Pyx_c_prod(a, b) ((a)*(b))
+ #define __Pyx_c_quot(a, b) ((a)/(b))
+ #define __Pyx_c_neg(a) (-(a))
#ifdef __cplusplus
- #define __Pyx_c_is_zero_double(z) ((z)==(double)0)
- #define __Pyx_c_conj_double(z) (::std::conj(z))
+ #define __Pyx_c_is_zero(z) ((z)==(double)0)
+ #define __Pyx_c_conj(z) (::std::conj(z))
#if 1
- #define __Pyx_c_abs_double(z) (::std::abs(z))
- #define __Pyx_c_pow_double(a, b) (::std::pow(a, b))
+ #define __Pyx_c_abs(z) (::std::abs(z))
+ #define __Pyx_c_pow(a, b) (::std::pow(a, b))
#endif
#else
- #define __Pyx_c_is_zero_double(z) ((z)==0)
- #define __Pyx_c_conj_double(z) (conj(z))
+ #define __Pyx_c_is_zero(z) ((z)==0)
+ #define __Pyx_c_conj(z) (conj(z))
#if 1
- #define __Pyx_c_abs_double(z) (cabs(z))
- #define __Pyx_c_pow_double(a, b) (cpow(a, b))
+ #define __Pyx_c_abs(z) (cabs(z))
+ #define __Pyx_c_pow(a, b) (cpow(a, b))
#endif
#endif
#else
- static CYTHON_INLINE int __Pyx_c_eq_double(__pyx_t_double_complex, __pyx_t_double_complex);
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_sum_double(__pyx_t_double_complex, __pyx_t_double_complex);
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_diff_double(__pyx_t_double_complex, __pyx_t_double_complex);
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_prod_double(__pyx_t_double_complex, __pyx_t_double_complex);
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_quot_double(__pyx_t_double_complex, __pyx_t_double_complex);
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_neg_double(__pyx_t_double_complex);
- static CYTHON_INLINE int __Pyx_c_is_zero_double(__pyx_t_double_complex);
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_conj_double(__pyx_t_double_complex);
+ static CYTHON_INLINE int __Pyx_c_eq(__pyx_t_double_complex, __pyx_t_double_complex);
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_sum(__pyx_t_double_complex, __pyx_t_double_complex);
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_diff(__pyx_t_double_complex, __pyx_t_double_complex);
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_prod(__pyx_t_double_complex, __pyx_t_double_complex);
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_quot(__pyx_t_double_complex, __pyx_t_double_complex);
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_neg(__pyx_t_double_complex);
+ static CYTHON_INLINE int __Pyx_c_is_zero(__pyx_t_double_complex);
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_conj(__pyx_t_double_complex);
#if 1
- static CYTHON_INLINE double __Pyx_c_abs_double(__pyx_t_double_complex);
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_pow_double(__pyx_t_double_complex, __pyx_t_double_complex);
+ static CYTHON_INLINE double __Pyx_c_abs(__pyx_t_double_complex);
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_pow(__pyx_t_double_complex, __pyx_t_double_complex);
#endif
#endif
-/* CIntToPy.proto */
-static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value);
-
-/* CIntFromPy.proto */
-static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *);
-
-/* CIntFromPy.proto */
-static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *);
-
-/* SwapException.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb)
-static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
-#else
static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb);
-#endif
-/* CoroutineBase.proto */
-typedef PyObject *(*__pyx_coroutine_body_t)(PyObject *, PyObject *);
+#define __Pyx_Generator_USED
+#include <structmember.h>
+#include <frameobject.h>
+typedef PyObject *(*__pyx_generator_body_t)(PyObject *, PyObject *);
typedef struct {
PyObject_HEAD
- __pyx_coroutine_body_t body;
+ __pyx_generator_body_t body;
PyObject *closure;
PyObject *exc_type;
PyObject *exc_value;
@@ -1618,39 +1268,21 @@ typedef struct {
PyObject *yieldfrom;
PyObject *gi_name;
PyObject *gi_qualname;
- PyObject *gi_modulename;
int resume_label;
char is_running;
-} __pyx_CoroutineObject;
-static __pyx_CoroutineObject *__Pyx__Coroutine_New(
- PyTypeObject *type, __pyx_coroutine_body_t body, PyObject *closure,
- PyObject *name, PyObject *qualname, PyObject *module_name);
-static int __Pyx_Coroutine_clear(PyObject *self);
+} __pyx_GeneratorObject;
+static __pyx_GeneratorObject *__Pyx_Generator_New(__pyx_generator_body_t body,
+ PyObject *closure, PyObject *name, PyObject *qualname);
+static int __pyx_Generator_init(void);
+static int __Pyx_Generator_clear(PyObject* self);
#if 1 || PY_VERSION_HEX < 0x030300B0
static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue);
#else
#define __Pyx_PyGen_FetchStopIterationValue(pvalue) PyGen_FetchStopIterationValue(pvalue)
#endif
-/* PatchModuleWithCoroutine.proto */
-static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code);
-
-/* PatchGeneratorABC.proto */
-static int __Pyx_patch_abc(void);
-
-/* Generator.proto */
-#define __Pyx_Generator_USED
-static PyTypeObject *__pyx_GeneratorType = 0;
-#define __Pyx_Generator_CheckExact(obj) (Py_TYPE(obj) == __pyx_GeneratorType)
-#define __Pyx_Generator_New(body, closure, name, qualname, module_name)\
- __Pyx__Coroutine_New(__pyx_GeneratorType, body, closure, name, qualname, module_name)
-static PyObject *__Pyx_Generator_Next(PyObject *self);
-static int __pyx_Generator_init(void);
-
-/* CheckBinaryVersion.proto */
static int __Pyx_check_binary_version(void);
-/* PyIdentifierFromString.proto */
#if !defined(__Pyx_PyIdentifier_FromString)
#if PY_MAJOR_VERSION < 3
#define __Pyx_PyIdentifier_FromString(s) PyString_FromString(s)
@@ -1659,33 +1291,28 @@ static int __Pyx_check_binary_version(void);
#endif
#endif
-/* ModuleImport.proto */
static PyObject *__Pyx_ImportModule(const char *name);
-/* TypeImport.proto */
static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class_name, size_t size, int strict);
-/* InitStrings.proto */
static int __Pyx_InitStrings(__Pyx_StringTabEntry *t);
/* Module declarations from 'cpython.buffer' */
+/* Module declarations from 'cpython.ref' */
+
/* Module declarations from 'libc.string' */
/* Module declarations from 'libc.stdio' */
+/* Module declarations from 'cpython.object' */
+
/* Module declarations from '__builtin__' */
/* Module declarations from 'cpython.type' */
static PyTypeObject *__pyx_ptype_7cpython_4type_type = 0;
-/* Module declarations from 'cpython' */
-
-/* Module declarations from 'cpython.object' */
-
-/* Module declarations from 'cpython.ref' */
-
/* Module declarations from 'libc.stdlib' */
/* Module declarations from 'numpy' */
@@ -1697,7 +1324,6 @@ static PyTypeObject *__pyx_ptype_5numpy_broadcast = 0;
static PyTypeObject *__pyx_ptype_5numpy_ndarray = 0;
static PyTypeObject *__pyx_ptype_5numpy_ufunc = 0;
static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *, char *, char *, int *); /*proto*/
-static CYTHON_INLINE int __pyx_f_5numpy_import_array(void); /*proto*/
/* Module declarations from 'cython' */
@@ -1711,6 +1337,7 @@ static PyTypeObject *__pyx_ptype_4silx_2io_8specfile___pyx_scope_struct_1___iter
int __pyx_module_is_main_silx__io__specfile = 0;
/* Implementation of 'silx.io.specfile' */
+static PyObject *__pyx_builtin_Exception;
static PyObject *__pyx_builtin_MemoryError;
static PyObject *__pyx_builtin_IOError;
static PyObject *__pyx_builtin_KeyError;
@@ -1725,256 +1352,337 @@ static PyObject *__pyx_builtin_enumerate;
static PyObject *__pyx_builtin_ValueError;
static PyObject *__pyx_builtin_AttributeError;
static PyObject *__pyx_builtin_RuntimeError;
-static PyObject *__pyx_builtin_ImportError;
-static const char __pyx_k_[] = "\n";
-static const char __pyx_k_2[] = " {2,}";
-static const char __pyx_k_3[] = "3";
-static const char __pyx_k_F[] = "#F ";
-static const char __pyx_k_L[] = "L";
-static const char __pyx_k_S[] = "#S ";
-static const char __pyx_k_f[] = "f";
-static const char __pyx_k_i[] = "i";
-static const char __pyx_k_w[] = "#(\\w+) *(.*)";
-static const char __pyx_k__7[] = "#";
-static const char __pyx_k_os[] = "os";
-static const char __pyx_k_re[] = "re";
-static const char __pyx_k_MCA[] = "MCA";
-static const char __pyx_k_MIT[] = "MIT";
-static const char __pyx_k__14[] = " ";
-static const char __pyx_k__25[] = ".";
-static const char __pyx_k__27[] = "', '";
-static const char __pyx_k__28[] = "'";
-static const char __pyx_k_d_d[] = "%d.%d";
-static const char __pyx_k_doc[] = "__doc__";
-static const char __pyx_k_key[] = "key";
-static const char __pyx_k_len[] = "__len__";
-static const char __pyx_k_map[] = "map";
-static const char __pyx_k_mca[] = "_mca";
-static const char __pyx_k_msg[] = "msg";
-static const char __pyx_k_ret[] = "ret";
-static const char __pyx_k_sub[] = "sub";
-static const char __pyx_k_sys[] = "sys";
-static const char __pyx_k_w_2[] = "#@(\\w+) *(.*)";
-static const char __pyx_k_Scan[] = "Scan";
-static const char __pyx_k_args[] = "args";
-static const char __pyx_k_data[] = "_data";
-static const char __pyx_k_date[] = "__date__";
-static const char __pyx_k_hkey[] = "hkey";
-static const char __pyx_k_init[] = "__init__";
-static const char __pyx_k_iter[] = "__iter__";
-static const char __pyx_k_join[] = "join";
-static const char __pyx_k_keys[] = "keys";
-static const char __pyx_k_line[] = "line";
-static const char __pyx_k_list[] = "_list";
-static const char __pyx_k_main[] = "__main__";
-static const char __pyx_k_name[] = "name";
-static const char __pyx_k_open[] = "open";
-static const char __pyx_k_path[] = "path";
-static const char __pyx_k_scan[] = "scan";
-static const char __pyx_k_self[] = "self";
-static const char __pyx_k_send[] = "send";
-static const char __pyx_k_stop[] = "stop";
-static const char __pyx_k_test[] = "__test__";
-static const char __pyx_k_CALIB[] = "CALIB";
-static const char __pyx_k_CHANN[] = "CHANN";
-static const char __pyx_k_ascii[] = "ascii";
-static const char __pyx_k_close[] = "close";
-static const char __pyx_k_dtype[] = "dtype";
-static const char __pyx_k_empty[] = "empty";
-static const char __pyx_k_group[] = "group";
-static const char __pyx_k_index[] = "index";
-static const char __pyx_k_label[] = "label";
-static const char __pyx_k_match[] = "match";
-static const char __pyx_k_mca_2[] = "mca";
-static const char __pyx_k_numpy[] = "numpy";
-static const char __pyx_k_order[] = "order";
-static const char __pyx_k_range[] = "range";
-static const char __pyx_k_shape[] = "shape";
-static const char __pyx_k_split[] = "split";
-static const char __pyx_k_start[] = "start";
-static const char __pyx_k_strip[] = "strip";
-static const char __pyx_k_throw[] = "throw";
-static const char __pyx_k_value[] = "value";
-static const char __pyx_k_ERRORS[] = "ERRORS";
-static const char __pyx_k_append[] = "append";
-static const char __pyx_k_data_2[] = "data";
-static const char __pyx_k_decode[] = "decode";
-static const char __pyx_k_double[] = "double";
-static const char __pyx_k_encode[] = "encode";
-static const char __pyx_k_header[] = "_header";
-static const char __pyx_k_hvalue[] = "hvalue";
-static const char __pyx_k_import[] = "__import__";
-static const char __pyx_k_isfile[] = "isfile";
-static const char __pyx_k_labels[] = "_labels";
-static const char __pyx_k_length[] = "length";
-static const char __pyx_k_logger[] = "_logger";
-static const char __pyx_k_lstrip[] = "lstrip";
-static const char __pyx_k_module[] = "__module__";
-static const char __pyx_k_name_2[] = "__name__";
-static const char __pyx_k_number[] = "number";
-static const char __pyx_k_object[] = "object";
-static const char __pyx_k_record[] = "record";
-static const char __pyx_k_scan_2[] = "_scan";
-static const char __pyx_k_search[] = "search";
-static const char __pyx_k_string[] = "string_";
-static const char __pyx_k_IOError[] = "IOError";
-static const char __pyx_k_SfError[] = "SfError";
-static const char __pyx_k_authors[] = "__authors__";
-static const char __pyx_k_get_mca[] = "get_mca";
-static const char __pyx_k_getitem[] = "__getitem__";
-static const char __pyx_k_index_2[] = "_index";
-static const char __pyx_k_license[] = "__license__";
-static const char __pyx_k_logging[] = "logging";
-static const char __pyx_k_order_2[] = "_order";
-static const char __pyx_k_os_path[] = "os.path";
-static const char __pyx_k_prepare[] = "__prepare__";
-static const char __pyx_k_version[] = "version";
-static const char __pyx_k_warning[] = "warning";
-static const char __pyx_k_KeyError[] = "KeyError";
-static const char __pyx_k_L_header[] = "L_header";
-static const char __pyx_k_P_Knobel[] = "P. Knobel";
-static const char __pyx_k_Scan_mca[] = "Scan.mca";
-static const char __pyx_k_channels[] = "channels";
-static const char __pyx_k_filename[] = "filename";
-static const char __pyx_k_header_2[] = "header";
-static const char __pyx_k_labels_2[] = "labels";
-static const char __pyx_k_number_2[] = "_number";
-static const char __pyx_k_property[] = "property";
-static const char __pyx_k_qualname[] = "__qualname__";
-static const char __pyx_k_specfile[] = "_specfile";
-static const char __pyx_k_MCA___len[] = "MCA.__len__";
-static const char __pyx_k_Scan_data[] = "Scan.data";
-static const char __pyx_k_TypeError[] = "TypeError";
-static const char __pyx_k_data_line[] = "data_line";
-static const char __pyx_k_enumerate[] = "enumerate";
-static const char __pyx_k_getLogger[] = "getLogger";
-static const char __pyx_k_increment[] = "increment";
-static const char __pyx_k_match_mca[] = "match_mca";
-static const char __pyx_k_mca_index[] = "mca_index";
-static const char __pyx_k_metaclass[] = "__metaclass__";
-static const char __pyx_k_transpose[] = "transpose";
-static const char __pyx_k_11_08_2017[] = "11/08/2017";
-static const char __pyx_k_IndexError[] = "IndexError";
-static const char __pyx_k_MCA___init[] = "MCA.__init__";
-static const char __pyx_k_MCA___iter[] = "MCA.__iter__";
-static const char __pyx_k_Scan_index[] = "Scan.index";
-static const char __pyx_k_Scan_order[] = "Scan.order";
-static const char __pyx_k_Valid_keys[] = "\nValid keys: '";
-static const char __pyx_k_ValueError[] = "ValueError";
-static const char __pyx_k_calib_line[] = "calib_line";
-static const char __pyx_k_chann_line[] = "chann_line";
-static const char __pyx_k_dictionary[] = "dictionary";
-static const char __pyx_k_line_index[] = "line_index";
-static const char __pyx_k_scan_index[] = "scan_index";
-static const char __pyx_k_scan_order[] = "scan_order";
-static const char __pyx_k_specfile_2[] = "specfile";
-static const char __pyx_k_startswith[] = "startswith";
-static const char __pyx_k_ImportError[] = "ImportError";
-static const char __pyx_k_MemoryError[] = "MemoryError";
-static const char __pyx_k_Scan___init[] = "Scan.__init__";
-static const char __pyx_k_Scan_header[] = "Scan.header";
-static const char __pyx_k_Scan_labels[] = "Scan.labels";
-static const char __pyx_k_Scan_number[] = "Scan.number";
-static const char __pyx_k_calib_lines[] = "calib_lines";
-static const char __pyx_k_calibration[] = "calibration";
-static const char __pyx_k_chann_lines[] = "chann_lines";
-static const char __pyx_k_file_header[] = "file_header";
-static const char __pyx_k_is_specfile[] = "is_specfile";
-static const char __pyx_k_motor_names[] = "motor_names";
-static const char __pyx_k_scan_header[] = "scan_header";
-static const char __pyx_k_scan_number[] = "scan_number";
-static const char __pyx_k_RuntimeError[] = "RuntimeError";
-static const char __pyx_k_SfNoMcaError[] = "SfNoMcaError";
-static const char __pyx_k_handle_error[] = "_handle_error";
-static const char __pyx_k_version_info[] = "version_info";
-static const char __pyx_k_MCA___getitem[] = "MCA.__getitem__";
-static const char __pyx_k_SfErrFileOpen[] = "SfErrFileOpen";
-static const char __pyx_k_SfErrFileRead[] = "SfErrFileRead";
-static const char __pyx_k_motor_names_2[] = "_motor_names";
-static const char __pyx_k_number_of_mca[] = "number_of_mca";
-static const char __pyx_k_AttributeError[] = "AttributeError";
-static const char __pyx_k_Scan_data_line[] = "Scan.data_line";
-static const char __pyx_k_SfErrFileClose[] = "SfErrFileClose";
-static const char __pyx_k_SfErrFileWrite[] = "SfErrFileWrite";
-static const char __pyx_k_SfErrLineEmpty[] = "SfErrLineEmpty";
-static const char __pyx_k_parse_channels[] = "_parse_channels";
-static const char __pyx_k_SpecFile___iter[] = "SpecFile.__iter__";
-static const char __pyx_k_mca_header_dict[] = "mca_header_dict";
-static const char __pyx_k_motor_positions[] = "motor_positions";
-static const char __pyx_k_SF_ERR_FILE_OPEN[] = "SF_ERR_FILE_OPEN";
-static const char __pyx_k_SF_ERR_NO_ERRORS[] = "SF_ERR_NO_ERRORS";
-static const char __pyx_k_Scan_file_header[] = "Scan.file_header";
-static const char __pyx_k_Scan_motor_names[] = "Scan.motor_names";
-static const char __pyx_k_Scan_scan_header[] = "Scan.scan_header";
-static const char __pyx_k_SfErrColNotFound[] = "SfErrColNotFound";
-static const char __pyx_k_SfErrMcaNotFound[] = "SfErrMcaNotFound";
-static const char __pyx_k_SfErrMemoryAlloc[] = "SfErrMemoryAlloc";
-static const char __pyx_k_all_calib_values[] = "all_calib_values";
-static const char __pyx_k_all_chann_values[] = "all_chann_values";
-static const char __pyx_k_file_header_dict[] = "_file_header_dict";
-static const char __pyx_k_get_error_string[] = "_get_error_string";
-static const char __pyx_k_scan_header_dict[] = "_scan_header_dict";
-static const char __pyx_k_silx_io_specfile[] = "silx.io.specfile";
-static const char __pyx_k_SfErrLineNotFound[] = "SfErrLineNotFound";
-static const char __pyx_k_SfErrScanNotFound[] = "SfErrScanNotFound";
-static const char __pyx_k_SfErrUserNotFound[] = "SfErrUserNotFound";
-static const char __pyx_k_file_header_lines[] = "_file_header_lines";
-static const char __pyx_k_mca_header_dict_2[] = "_mca_header_dict";
-static const char __pyx_k_motor_positions_2[] = "_motor_positions";
-static const char __pyx_k_parse_calibration[] = "_parse_calibration";
-static const char __pyx_k_scan_header_lines[] = "_scan_header_lines";
-static const char __pyx_k_SfErrLabelNotFound[] = "SfErrLabelNotFound";
-static const char __pyx_k_SfErrMotorNotFound[] = "SfErrMotorNotFound";
-static const char __pyx_k_SfNoMca_returned_1[] = "(SfNoMca returned -1)";
-static const char __pyx_k_add_or_concatenate[] = "_add_or_concatenate";
-static const char __pyx_k_file_header_dict_2[] = "file_header_dict";
-static const char __pyx_k_scan_header_dict_2[] = "scan_header_dict";
-static const char __pyx_k_MCA__parse_channels[] = "MCA._parse_channels";
-static const char __pyx_k_SfErrHeaderNotFound[] = "SfErrHeaderNotFound";
-static const char __pyx_k_data_column_by_name[] = "data_column_by_name";
-static const char __pyx_k_string_to_char_star[] = "_string_to_char_star";
-static const char __pyx_k_Scan_mca_header_dict[] = "Scan.mca_header_dict";
-static const char __pyx_k_Scan_motor_positions[] = "Scan.motor_positions";
-static const char __pyx_k_record_exists_in_hdr[] = "record_exists_in_hdr";
-static const char __pyx_k_SF_ERR_SCAN_NOT_FOUND[] = "SF_ERR_SCAN_NOT_FOUND";
-static const char __pyx_k_Scan_file_header_dict[] = "Scan.file_header_dict";
-static const char __pyx_k_Scan_scan_header_dict[] = "Scan.scan_header_dict";
-static const char __pyx_k_SfErrPositionNotFound[] = "SfErrPositionNotFound";
-static const char __pyx_k_one_line_calib_values[] = "one_line_calib_values";
-static const char __pyx_k_one_line_chann_values[] = "one_line_chann_values";
-static const char __pyx_k_MCA__parse_calibration[] = "MCA._parse_calibration";
-static const char __pyx_k_motor_position_by_name[] = "motor_position_by_name";
-static const char __pyx_k_Scan_data_column_by_name[] = "Scan.data_column_by_name";
-static const char __pyx_k_Scan_record_exists_in_hdr[] = "Scan.record_exists_in_hdr";
-static const char __pyx_k_Scan_motor_position_by_name[] = "Scan.motor_position_by_name";
-static const char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous";
-static const char __pyx_k_Error_while_closing_SpecFile[] = "Error while closing SpecFile";
-static const char __pyx_k_number_and_M_the_order_eg_2_3[] = " number and M the order (eg '2.3').";
-static const char __pyx_k_MCA_index_must_be_in_range_0_d[] = "MCA index must be in range 0-%d";
-static const char __pyx_k_param_specfile_Parent_SpecFile[] = "\n\n :param specfile: Parent SpecFile from which this scan is extracted.\n :type specfile: :class:`SpecFile`\n :param scan_index: Unique index defining the scan in the SpecFile\n :type scan_index: int\n\n Interface to access a SpecFile scan\n\n A scan is a block of descriptive header lines followed by a 2D data array.\n\n Following three ways of accessing a scan are equivalent::\n\n sf = SpecFile(\"/path/to/specfile.dat\")\n\n # Explicit class instantiation\n scan2 = Scan(sf, scan_index=2)\n\n # 0-based index on a SpecFile object\n scan2 = sf[2]\n\n # Using a \"n.m\" key (scan number starting with 1, scan order)\n scan2 = sf[\"3.1\"]\n ";
-static const char __pyx_k_Base_exception_inherited_by_all[] = "Base exception inherited by all exceptions raised when a\n C function from the legacy SpecFile library returns an error\n code.\n ";
-static const char __pyx_k_Scan_index_must_be_in_range_0_d[] = "Scan index must be in range 0-%d";
-static const char __pyx_k_The_scan_identification_key_can[] = "The scan identification key can be an integer representing ";
-static const char __pyx_k_This_module_is_a_cython_binding[] = "\nThis module is a cython binding to wrap the C SpecFile library, to access\nSpecFile data within a python program.\n\nDocumentation for the original C library SpecFile can be found on the ESRF\nwebsite:\n`The manual for the SpecFile Library <http://www.esrf.eu/files/live/sites/www/files/Instrumentation/software/beamline-control/BLISS/documentation/SpecFileManual.pdf>`_\n\nExamples\n========\n\nStart by importing :class:`SpecFile` and instantiate it:\n\n.. code-block:: python\n\n from silx.io.specfile import SpecFile\n\n sf = SpecFile(\"test.dat\")\n\nA :class:`SpecFile` instance can be accessed like a dictionary to obtain a\n:class:`Scan` instance.\n\nIf the key is a string representing two values\nseparated by a dot (e.g. ``\"1.2\"``), they will be treated as the scan number\n(``#S`` header line) and the scan order::\n\n # get second occurrence of scan \"#S 1\"\n myscan = sf[\"1.2\"]\n\n # access scan data as a numpy array\n nlines, ncolumns = myscan.data.shape\n\nIf the key is an integer, it will be treated as a 0-based index::\n\n first_scan = sf[0]\n second_scan = sf[1]\n\nIt is also possible to browse through all scans using :class:`SpecFile` as\nan iterator::\n\n for scan in sf:\n print(scan.scan_header_dict['S'])\n\nMCA spectra can be selectively loaded using an instance of :class:`MCA`\nprovided by :class:`Scan`::\n\n # Only one MCA spectrum is loaded in memory\n second_mca = first_scan.mca[1]\n\n # Iterating trough all MCA spectra in a scan:\n for mca_data in first_scan.mca:\n print(sum(mca_data))\n\nClasses\n=======\n\n- :class:`SpecFile`\n- :class:`Scan`\n- :class:`MCA`\n\nExceptions\n==========\n\n- :class:`SfError`\n- :class:`SfErrMemoryAlloc`\n- :class:`SfErrFileOpen`\n- :class:`SfErrFileClose`\n- :class:`SfErrFileRead`\n- :class:`SfErrFileWrite`\n- :class:`SfErrLineNotFound`\n- :class:`SfErrScanNotFound`\n- :class:`SfErrHeaderNotFound`\n- :class:`SfErrLabelNotFound`\n- :class:`SfErrMotorNotFound`""\n- :class:`SfErrPositionNotFound`\n- :class:`SfErrLineEmpty`\n- :class:`SfErrUserNotFound`\n- :class:`SfErrColNotFound`\n- :class:`SfErrMcaNotFound`\n\n";
-static const char __pyx_k_numpy_core_multiarray_failed_to[] = "numpy.core.multiarray failed to import";
-static const char __pyx_k_param_scan_Parent_Scan_instance[] = "\n\n :param scan: Parent Scan instance\n :type scan: :class:`Scan`\n\n :var calibration: MCA calibration :math:`(a, b, c)` (as in\n :math:`a + b x + c x\302\262`) from ``#@CALIB`` scan header.\n :type calibration: list of 3 floats, default ``[0., 1., 0.]``\n :var channels: MCA channels list from ``#@CHANN`` scan header.\n In the absence of a ``#@CHANN`` header, this attribute is a list\n ``[0, \342\200\246, N-1]`` where ``N`` is the length of the first spectrum.\n In the absence of MCA spectra, this attribute defaults to ``None``.\n :type channels: list of int\n\n This class provides access to Multi-Channel Analysis data. A :class:`MCA`\n instance can be indexed to access 1D numpy arrays representing single\n MCA\302\240spectra.\n\n To create a :class:`MCA` instance, you must provide a parent :class:`Scan`\n instance, which in turn will provide a reference to the original\n :class:`SpecFile` instance::\n\n sf = SpecFile(\"/path/to/specfile.dat\")\n scan2 = Scan(sf, scan_index=2)\n mcas_in_scan2 = MCA(scan2)\n for i in len(mcas_in_scan2):\n mca_data = mcas_in_scan2[i]\n ... # do some something with mca_data (1D numpy array)\n\n A more pythonic way to do the same work, without having to explicitly\n instantiate ``scan`` and ``mcas_in_scan``, would be::\n\n sf = SpecFile(\"specfilename.dat\")\n # scan2 from previous example can be referred to as sf[2]\n # mcas_in_scan2 from previous example can be referred to as scan2.mca\n for mca_data in sf[2].mca:\n ... # do some something with mca_data (1D numpy array)\n\n ";
-static const char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)";
-static const char __pyx_k_users_kieffer_workspace_400_rel[] = "/users/kieffer/workspace-400/release/silx/silx/io/specfile.pyx";
-static const char __pyx_k_Cannot_get_data_column_s_in_scan[] = "Cannot get data column %s in scan %d.%d";
-static const char __pyx_k_Custom_exception_raised_when_SfN[] = "Custom exception raised when ``SfNoMca()`` returns ``-1``\n ";
-static const char __pyx_k_Failed_to_retrieve_number_of_MCA[] = "Failed to retrieve number of MCA ";
-static const char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd";
-static const char __pyx_k_MCA_calibration_line_CALIB_not_f[] = "MCA calibration line (@CALIB) not found";
-static const char __pyx_k_MCA_index_should_be_an_integer_s[] = "MCA index should be an integer (%s provided)";
-static const char __pyx_k_No_MCA_spectrum_found_in_this_sc[] = "No MCA spectrum found in this scan";
-static const char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported";
-static const char __pyx_k_Parameter_value_must_be_a_string[] = "Parameter value must be a string.";
-static const char __pyx_k_Unable_to_parse_file_header_line[] = "Unable to parse file header line ";
-static const char __pyx_k_Unable_to_parse_scan_header_line[] = "Unable to parse scan header line ";
-static const char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous";
-static const char __pyx_k_numpy_core_umath_failed_to_impor[] = "numpy.core.umath failed to import";
-static const char __pyx_k_the_unique_scan_index_or_a_strin[] = "the unique scan index or a string 'N.M' with N being the scan";
-static const char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short.";
+static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_scan); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_6__len__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_key); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_10__iter__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile__add_or_concatenate(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_dictionary, PyObject *__pyx_v_key, PyObject *__pyx_v_value); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_specfile, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_2index(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_4number(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_6order(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_8header(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_10scan_header(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_12file_header(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_14scan_header_dict(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_16mca_header_dict(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_18file_header_dict(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_20labels(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_22data(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_24mca(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_26motor_names(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_28motor_positions(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_30record_exists_in_hdr(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_record); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_32data_line(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_line_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_label); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_36motor_position_by_name(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_name); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_2_string_to_char_star(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_string_); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_4is_specfile(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_filename); /* proto */
+static int __pyx_pf_4silx_2io_8specfile_8SpecFile___cinit__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_filename); /* proto */
+static int __pyx_pf_4silx_2io_8specfile_8SpecFile_2__init__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_filename); /* proto */
+static void __pyx_pf_4silx_2io_8specfile_8SpecFile_4__dealloc__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_6close(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
+static Py_ssize_t __pyx_pf_4silx_2io_8specfile_8SpecFile_8__len__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_10__iter__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13__getitem__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_key); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_15keys(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
+static int __pyx_pf_4silx_2io_8specfile_8SpecFile_17__contains__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_key); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_19_get_error_string(CYTHON_UNUSED struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_error_code); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_21_handle_error(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_error_code); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_23index(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_number, PyObject *__pyx_v_scan_order); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_25number(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_27order(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_29_list(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31list(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35data_column_by_name(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_label); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37scan_header(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_39file_header(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_41columns(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_43command(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45date(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47labels(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_names(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_positions(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_53motor_position_by_name(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_name); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55number_of_mca(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_57mca_calibration(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_59get_mca(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_mca_index); /* proto */
+static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */
+static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */
+static PyObject *__pyx_tp_new_4silx_2io_8specfile_SpecFile(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
+static PyObject *__pyx_tp_new_4silx_2io_8specfile___pyx_scope_struct____iter__(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
+static PyObject *__pyx_tp_new_4silx_2io_8specfile___pyx_scope_struct_1___iter__(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
+static char __pyx_k_[] = "\n";
+static char __pyx_k_2[] = " {2,}";
+static char __pyx_k_3[] = "3";
+static char __pyx_k_B[] = "B";
+static char __pyx_k_F[] = "#F ";
+static char __pyx_k_H[] = "H";
+static char __pyx_k_I[] = "I";
+static char __pyx_k_L[] = "L";
+static char __pyx_k_O[] = "O";
+static char __pyx_k_Q[] = "Q";
+static char __pyx_k_S[] = "#S ";
+static char __pyx_k_b[] = "b";
+static char __pyx_k_d[] = "d";
+static char __pyx_k_f[] = "f";
+static char __pyx_k_g[] = "g";
+static char __pyx_k_h[] = "h";
+static char __pyx_k_i[] = "i";
+static char __pyx_k_l[] = "l";
+static char __pyx_k_q[] = "q";
+static char __pyx_k_w[] = "#(\\w+) *(.*)";
+static char __pyx_k_Zd[] = "Zd";
+static char __pyx_k_Zf[] = "Zf";
+static char __pyx_k_Zg[] = "Zg";
+static char __pyx_k__7[] = "#";
+static char __pyx_k_os[] = "os";
+static char __pyx_k_rb[] = "rb";
+static char __pyx_k_re[] = "re";
+static char __pyx_k_MCA[] = "MCA";
+static char __pyx_k_MIT[] = "MIT";
+static char __pyx_k__14[] = " ";
+static char __pyx_k__28[] = ".";
+static char __pyx_k__30[] = "', '";
+static char __pyx_k__31[] = "'";
+static char __pyx_k__32[] = "";
+static char __pyx_k_d_d[] = "%d.%d";
+static char __pyx_k_doc[] = "__doc__";
+static char __pyx_k_key[] = "key";
+static char __pyx_k_len[] = "__len__";
+static char __pyx_k_map[] = "map";
+static char __pyx_k_mca[] = "_mca";
+static char __pyx_k_msg[] = "msg";
+static char __pyx_k_ret[] = "ret";
+static char __pyx_k_sub[] = "sub";
+static char __pyx_k_sys[] = "sys";
+static char __pyx_k_w_2[] = "#@(\\w+) *(.*)";
+static char __pyx_k_Scan[] = "Scan";
+static char __pyx_k_args[] = "args";
+static char __pyx_k_data[] = "_data";
+static char __pyx_k_date[] = "__date__";
+static char __pyx_k_exit[] = "__exit__";
+static char __pyx_k_hkey[] = "hkey";
+static char __pyx_k_init[] = "__init__";
+static char __pyx_k_iter[] = "__iter__";
+static char __pyx_k_join[] = "join";
+static char __pyx_k_keys[] = "keys";
+static char __pyx_k_line[] = "line";
+static char __pyx_k_list[] = "_list";
+static char __pyx_k_main[] = "__main__";
+static char __pyx_k_name[] = "name";
+static char __pyx_k_open[] = "open";
+static char __pyx_k_path[] = "path";
+static char __pyx_k_read[] = "read";
+static char __pyx_k_scan[] = "scan";
+static char __pyx_k_self[] = "self";
+static char __pyx_k_send[] = "send";
+static char __pyx_k_stop[] = "stop";
+static char __pyx_k_test[] = "__test__";
+static char __pyx_k_CALIB[] = "CALIB";
+static char __pyx_k_CHANN[] = "CHANN";
+static char __pyx_k_ascii[] = "ascii";
+static char __pyx_k_chunk[] = "chunk";
+static char __pyx_k_close[] = "close";
+static char __pyx_k_dtype[] = "dtype";
+static char __pyx_k_empty[] = "empty";
+static char __pyx_k_enter[] = "__enter__";
+static char __pyx_k_group[] = "group";
+static char __pyx_k_index[] = "index";
+static char __pyx_k_label[] = "label";
+static char __pyx_k_match[] = "match";
+static char __pyx_k_mca_2[] = "mca";
+static char __pyx_k_numpy[] = "numpy";
+static char __pyx_k_order[] = "order";
+static char __pyx_k_range[] = "range";
+static char __pyx_k_shape[] = "shape";
+static char __pyx_k_split[] = "split";
+static char __pyx_k_start[] = "start";
+static char __pyx_k_strip[] = "strip";
+static char __pyx_k_throw[] = "throw";
+static char __pyx_k_value[] = "value";
+static char __pyx_k_ERRORS[] = "ERRORS";
+static char __pyx_k_append[] = "append";
+static char __pyx_k_data_2[] = "data";
+static char __pyx_k_decode[] = "decode";
+static char __pyx_k_double[] = "double";
+static char __pyx_k_encode[] = "encode";
+static char __pyx_k_header[] = "_header";
+static char __pyx_k_hvalue[] = "hvalue";
+static char __pyx_k_import[] = "__import__";
+static char __pyx_k_isfile[] = "isfile";
+static char __pyx_k_labels[] = "_labels";
+static char __pyx_k_length[] = "length";
+static char __pyx_k_logger[] = "_logger";
+static char __pyx_k_lstrip[] = "lstrip";
+static char __pyx_k_module[] = "__module__";
+static char __pyx_k_name_2[] = "__name__";
+static char __pyx_k_number[] = "number";
+static char __pyx_k_object[] = "object";
+static char __pyx_k_record[] = "record";
+static char __pyx_k_scan_2[] = "_scan";
+static char __pyx_k_search[] = "search";
+static char __pyx_k_string[] = "string_";
+static char __pyx_k_IOError[] = "IOError";
+static char __pyx_k_SfError[] = "SfError";
+static char __pyx_k_authors[] = "__authors__";
+static char __pyx_k_get_mca[] = "get_mca";
+static char __pyx_k_getitem[] = "__getitem__";
+static char __pyx_k_index_2[] = "_index";
+static char __pyx_k_license[] = "__license__";
+static char __pyx_k_logging[] = "logging";
+static char __pyx_k_order_2[] = "_order";
+static char __pyx_k_os_path[] = "os.path";
+static char __pyx_k_prepare[] = "__prepare__";
+static char __pyx_k_version[] = "version";
+static char __pyx_k_warning[] = "warning";
+static char __pyx_k_KeyError[] = "KeyError";
+static char __pyx_k_L_header[] = "L_header";
+static char __pyx_k_P_Knobel[] = "P. Knobel";
+static char __pyx_k_Scan_mca[] = "Scan.mca";
+static char __pyx_k_channels[] = "channels";
+static char __pyx_k_filename[] = "filename";
+static char __pyx_k_header_2[] = "header";
+static char __pyx_k_labels_2[] = "labels";
+static char __pyx_k_number_2[] = "_number";
+static char __pyx_k_property[] = "property";
+static char __pyx_k_qualname[] = "__qualname__";
+static char __pyx_k_specfile[] = "_specfile";
+static char __pyx_k_Exception[] = "Exception";
+static char __pyx_k_MCA___len[] = "MCA.__len__";
+static char __pyx_k_Scan_data[] = "Scan.data";
+static char __pyx_k_TypeError[] = "TypeError";
+static char __pyx_k_data_line[] = "data_line";
+static char __pyx_k_enumerate[] = "enumerate";
+static char __pyx_k_getLogger[] = "getLogger";
+static char __pyx_k_increment[] = "increment";
+static char __pyx_k_match_mca[] = "match_mca";
+static char __pyx_k_mca_index[] = "mca_index";
+static char __pyx_k_metaclass[] = "__metaclass__";
+static char __pyx_k_transpose[] = "transpose";
+static char __pyx_k_11_08_2017[] = "11/08/2017";
+static char __pyx_k_IndexError[] = "IndexError";
+static char __pyx_k_MCA___init[] = "MCA.__init__";
+static char __pyx_k_MCA___iter[] = "MCA.__iter__";
+static char __pyx_k_Scan_index[] = "Scan.index";
+static char __pyx_k_Scan_order[] = "Scan.order";
+static char __pyx_k_Valid_keys[] = "\nValid keys: '";
+static char __pyx_k_ValueError[] = "ValueError";
+static char __pyx_k_calib_line[] = "calib_line";
+static char __pyx_k_chann_line[] = "chann_line";
+static char __pyx_k_dictionary[] = "dictionary";
+static char __pyx_k_line_index[] = "line_index";
+static char __pyx_k_scan_index[] = "scan_index";
+static char __pyx_k_scan_order[] = "scan_order";
+static char __pyx_k_specfile_2[] = "specfile";
+static char __pyx_k_startswith[] = "startswith";
+static char __pyx_k_MemoryError[] = "MemoryError";
+static char __pyx_k_Scan___init[] = "Scan.__init__";
+static char __pyx_k_Scan_header[] = "Scan.header";
+static char __pyx_k_Scan_labels[] = "Scan.labels";
+static char __pyx_k_Scan_number[] = "Scan.number";
+static char __pyx_k_calib_lines[] = "calib_lines";
+static char __pyx_k_calibration[] = "calibration";
+static char __pyx_k_chann_lines[] = "chann_lines";
+static char __pyx_k_file_header[] = "file_header";
+static char __pyx_k_is_specfile[] = "is_specfile";
+static char __pyx_k_motor_names[] = "motor_names";
+static char __pyx_k_scan_header[] = "scan_header";
+static char __pyx_k_scan_number[] = "scan_number";
+static char __pyx_k_RuntimeError[] = "RuntimeError";
+static char __pyx_k_SfNoMcaError[] = "SfNoMcaError";
+static char __pyx_k_handle_error[] = "_handle_error";
+static char __pyx_k_version_info[] = "version_info";
+static char __pyx_k_MCA___getitem[] = "MCA.__getitem__";
+static char __pyx_k_SfErrFileOpen[] = "SfErrFileOpen";
+static char __pyx_k_SfErrFileRead[] = "SfErrFileRead";
+static char __pyx_k_motor_names_2[] = "_motor_names";
+static char __pyx_k_number_of_mca[] = "number_of_mca";
+static char __pyx_k_AttributeError[] = "AttributeError";
+static char __pyx_k_Scan_data_line[] = "Scan.data_line";
+static char __pyx_k_SfErrFileClose[] = "SfErrFileClose";
+static char __pyx_k_SfErrFileWrite[] = "SfErrFileWrite";
+static char __pyx_k_SfErrLineEmpty[] = "SfErrLineEmpty";
+static char __pyx_k_parse_channels[] = "_parse_channels";
+static char __pyx_k_SpecFile___iter[] = "SpecFile.__iter__";
+static char __pyx_k_mca_header_dict[] = "mca_header_dict";
+static char __pyx_k_motor_positions[] = "motor_positions";
+static char __pyx_k_SF_ERR_FILE_OPEN[] = "SF_ERR_FILE_OPEN";
+static char __pyx_k_SF_ERR_NO_ERRORS[] = "SF_ERR_NO_ERRORS";
+static char __pyx_k_Scan_file_header[] = "Scan.file_header";
+static char __pyx_k_Scan_motor_names[] = "Scan.motor_names";
+static char __pyx_k_Scan_scan_header[] = "Scan.scan_header";
+static char __pyx_k_SfErrColNotFound[] = "SfErrColNotFound";
+static char __pyx_k_SfErrMcaNotFound[] = "SfErrMcaNotFound";
+static char __pyx_k_SfErrMemoryAlloc[] = "SfErrMemoryAlloc";
+static char __pyx_k_all_calib_values[] = "all_calib_values";
+static char __pyx_k_all_chann_values[] = "all_chann_values";
+static char __pyx_k_file_header_dict[] = "_file_header_dict";
+static char __pyx_k_get_error_string[] = "_get_error_string";
+static char __pyx_k_scan_header_dict[] = "_scan_header_dict";
+static char __pyx_k_silx_io_specfile[] = "silx.io.specfile";
+static char __pyx_k_SfErrLineNotFound[] = "SfErrLineNotFound";
+static char __pyx_k_SfErrScanNotFound[] = "SfErrScanNotFound";
+static char __pyx_k_SfErrUserNotFound[] = "SfErrUserNotFound";
+static char __pyx_k_file_header_lines[] = "_file_header_lines";
+static char __pyx_k_mca_header_dict_2[] = "_mca_header_dict";
+static char __pyx_k_motor_positions_2[] = "_motor_positions";
+static char __pyx_k_parse_calibration[] = "_parse_calibration";
+static char __pyx_k_scan_header_lines[] = "_scan_header_lines";
+static char __pyx_k_SfErrLabelNotFound[] = "SfErrLabelNotFound";
+static char __pyx_k_SfErrMotorNotFound[] = "SfErrMotorNotFound";
+static char __pyx_k_SfNoMca_returned_1[] = "(SfNoMca returned -1)";
+static char __pyx_k_add_or_concatenate[] = "_add_or_concatenate";
+static char __pyx_k_file_header_dict_2[] = "file_header_dict";
+static char __pyx_k_scan_header_dict_2[] = "scan_header_dict";
+static char __pyx_k_MCA__parse_channels[] = "MCA._parse_channels";
+static char __pyx_k_SfErrHeaderNotFound[] = "SfErrHeaderNotFound";
+static char __pyx_k_data_column_by_name[] = "data_column_by_name";
+static char __pyx_k_string_to_char_star[] = "_string_to_char_star";
+static char __pyx_k_Scan_mca_header_dict[] = "Scan.mca_header_dict";
+static char __pyx_k_Scan_motor_positions[] = "Scan.motor_positions";
+static char __pyx_k_record_exists_in_hdr[] = "record_exists_in_hdr";
+static char __pyx_k_SF_ERR_SCAN_NOT_FOUND[] = "SF_ERR_SCAN_NOT_FOUND";
+static char __pyx_k_Scan_file_header_dict[] = "Scan.file_header_dict";
+static char __pyx_k_Scan_scan_header_dict[] = "Scan.scan_header_dict";
+static char __pyx_k_SfErrPositionNotFound[] = "SfErrPositionNotFound";
+static char __pyx_k_one_line_calib_values[] = "one_line_calib_values";
+static char __pyx_k_one_line_chann_values[] = "one_line_chann_values";
+static char __pyx_k_MCA__parse_calibration[] = "MCA._parse_calibration";
+static char __pyx_k_motor_position_by_name[] = "motor_position_by_name";
+static char __pyx_k_Scan_data_column_by_name[] = "Scan.data_column_by_name";
+static char __pyx_k_Scan_record_exists_in_hdr[] = "Scan.record_exists_in_hdr";
+static char __pyx_k_Scan_motor_position_by_name[] = "Scan.motor_position_by_name";
+static char __pyx_k_ndarray_is_not_C_contiguous[] = "ndarray is not C contiguous";
+static char __pyx_k_Error_while_closing_SpecFile[] = "Error while closing SpecFile";
+static char __pyx_k_number_and_M_the_order_eg_2_3[] = " number and M the order (eg '2.3').";
+static char __pyx_k_MCA_index_must_be_in_range_0_d[] = "MCA index must be in range 0-%d";
+static char __pyx_k_param_specfile_Parent_SpecFile[] = "\n\n :param specfile: Parent SpecFile from which this scan is extracted.\n :type specfile: :class:`SpecFile`\n :param scan_index: Unique index defining the scan in the SpecFile\n :type scan_index: int\n\n Interface to access a SpecFile scan\n\n A scan is a block of descriptive header lines followed by a 2D data array.\n\n Following three ways of accessing a scan are equivalent::\n\n sf = SpecFile(\"/path/to/specfile.dat\")\n\n # Explicit class instantiation\n scan2 = Scan(sf, scan_index=2)\n\n # 0-based index on a SpecFile object\n scan2 = sf[2]\n\n # Using a \"n.m\" key (scan number starting with 1, scan order)\n scan2 = sf[\"3.1\"]\n ";
+static char __pyx_k_Base_exception_inherited_by_all[] = "Base exception inherited by all exceptions raised when a\n C function from the legacy SpecFile library returns an error\n code.\n ";
+static char __pyx_k_Scan_index_must_be_in_range_0_d[] = "Scan index must be in range 0-%d";
+static char __pyx_k_The_scan_identification_key_can[] = "The scan identification key can be an integer representing ";
+static char __pyx_k_This_module_is_a_cython_binding[] = "\nThis module is a cython binding to wrap the C SpecFile library, to access\nSpecFile data within a python program.\n\nDocumentation for the original C library SpecFile can be found on the ESRF\nwebsite:\n`The manual for the SpecFile Library <http://www.esrf.eu/files/live/sites/www/files/Instrumentation/software/beamline-control/BLISS/documentation/SpecFileManual.pdf>`_\n\nExamples\n========\n\nStart by importing :class:`SpecFile` and instantiate it:\n\n.. code-block:: python\n\n from silx.io.specfile import SpecFile\n\n sf = SpecFile(\"test.dat\")\n\nA :class:`SpecFile` instance can be accessed like a dictionary to obtain a\n:class:`Scan` instance.\n\nIf the key is a string representing two values\nseparated by a dot (e.g. ``\"1.2\"``), they will be treated as the scan number\n(``#S`` header line) and the scan order::\n\n # get second occurrence of scan \"#S 1\"\n myscan = sf[\"1.2\"]\n\n # access scan data as a numpy array\n nlines, ncolumns = myscan.data.shape\n\nIf the key is an integer, it will be treated as a 0-based index::\n\n first_scan = sf[0]\n second_scan = sf[1]\n\nIt is also possible to browse through all scans using :class:`SpecFile` as\nan iterator::\n\n for scan in sf:\n print(scan.scan_header_dict['S'])\n\nMCA spectra can be selectively loaded using an instance of :class:`MCA`\nprovided by :class:`Scan`::\n\n # Only one MCA spectrum is loaded in memory\n second_mca = first_scan.mca[1]\n\n # Iterating trough all MCA spectra in a scan:\n for mca_data in first_scan.mca:\n print(sum(mca_data))\n\nClasses\n=======\n\n- :class:`SpecFile`\n- :class:`Scan`\n- :class:`MCA`\n\nExceptions\n==========\n\n- :class:`SfError`\n- :class:`SfErrMemoryAlloc`\n- :class:`SfErrFileOpen`\n- :class:`SfErrFileClose`\n- :class:`SfErrFileRead`\n- :class:`SfErrFileWrite`\n- :class:`SfErrLineNotFound`\n- :class:`SfErrScanNotFound`\n- :class:`SfErrHeaderNotFound`\n- :class:`SfErrLabelNotFound`\n- :class:`SfErrMotorNotFound`""\n- :class:`SfErrPositionNotFound`\n- :class:`SfErrLineEmpty`\n- :class:`SfErrUserNotFound`\n- :class:`SfErrColNotFound`\n- :class:`SfErrMcaNotFound`\n\n";
+static char __pyx_k_param_scan_Parent_Scan_instance[] = "\n\n :param scan: Parent Scan instance\n :type scan: :class:`Scan`\n\n :var calibration: MCA calibration :math:`(a, b, c)` (as in\n :math:`a + b x + c x\302\262`) from ``#@CALIB`` scan header.\n :type calibration: list of 3 floats, default ``[0., 1., 0.]``\n :var channels: MCA channels list from ``#@CHANN`` scan header.\n In the absence of a ``#@CHANN`` header, this attribute is a list\n ``[0, \342\200\246, N-1]`` where ``N`` is the length of the first spectrum.\n In the absence of MCA spectra, this attribute defaults to ``None``.\n :type channels: list of int\n\n This class provides access to Multi-Channel Analysis data. A :class:`MCA`\n instance can be indexed to access 1D numpy arrays representing single\n MCA\302\240spectra.\n\n To create a :class:`MCA` instance, you must provide a parent :class:`Scan`\n instance, which in turn will provide a reference to the original\n :class:`SpecFile` instance::\n\n sf = SpecFile(\"/path/to/specfile.dat\")\n scan2 = Scan(sf, scan_index=2)\n mcas_in_scan2 = MCA(scan2)\n for i in len(mcas_in_scan2):\n mca_data = mcas_in_scan2[i]\n ... # do some something with mca_data (1D numpy array)\n\n A more pythonic way to do the same work, without having to explicitly\n instantiate ``scan`` and ``mcas_in_scan``, would be::\n\n sf = SpecFile(\"specfilename.dat\")\n # scan2 from previous example can be referred to as sf[2]\n # mcas_in_scan2 from previous example can be referred to as scan2.mca\n for mca_data in sf[2].mca:\n ... # do some something with mca_data (1D numpy array)\n\n ";
+static char __pyx_k_unknown_dtype_code_in_numpy_pxd[] = "unknown dtype code in numpy.pxd (%d)";
+static char __pyx_k_users_knobel_git_silx_silx_io_s[] = "/users/knobel/git/silx/silx/io/specfile.pyx";
+static char __pyx_k_Cannot_get_data_column_s_in_scan[] = "Cannot get data column %s in scan %d.%d";
+static char __pyx_k_Custom_exception_raised_when_SfN[] = "Custom exception raised when ``SfNoMca()`` returns ``-1``\n ";
+static char __pyx_k_Failed_to_retrieve_number_of_MCA[] = "Failed to retrieve number of MCA ";
+static char __pyx_k_Format_string_allocated_too_shor[] = "Format string allocated too short, see comment in numpy.pxd";
+static char __pyx_k_MCA_calibration_line_CALIB_not_f[] = "MCA calibration line (@CALIB) not found";
+static char __pyx_k_MCA_index_should_be_an_integer_s[] = "MCA index should be an integer (%s provided)";
+static char __pyx_k_No_MCA_spectrum_found_in_this_sc[] = "No MCA spectrum found in this scan";
+static char __pyx_k_Non_native_byte_order_not_suppor[] = "Non-native byte order not supported";
+static char __pyx_k_Parameter_value_must_be_a_string[] = "Parameter value must be a string.";
+static char __pyx_k_Unable_to_parse_file_header_line[] = "Unable to parse file header line ";
+static char __pyx_k_Unable_to_parse_scan_header_line[] = "Unable to parse scan header line ";
+static char __pyx_k_ndarray_is_not_Fortran_contiguou[] = "ndarray is not Fortran contiguous";
+static char __pyx_k_the_unique_scan_index_or_a_strin[] = "the unique scan index or a string 'N.M' with N being the scan";
+static char __pyx_k_Format_string_allocated_too_shor_2[] = "Format string allocated too short.";
+static PyObject *__pyx_kp_b_;
static PyObject *__pyx_kp_s_;
static PyObject *__pyx_kp_s_11_08_2017;
static PyObject *__pyx_kp_s_2;
@@ -1987,12 +1695,12 @@ static PyObject *__pyx_kp_s_Cannot_get_data_column_s_in_scan;
static PyObject *__pyx_kp_s_Custom_exception_raised_when_SfN;
static PyObject *__pyx_n_s_ERRORS;
static PyObject *__pyx_kp_s_Error_while_closing_SpecFile;
-static PyObject *__pyx_kp_s_F;
+static PyObject *__pyx_n_s_Exception;
+static PyObject *__pyx_kp_b_F;
static PyObject *__pyx_kp_s_Failed_to_retrieve_number_of_MCA;
static PyObject *__pyx_kp_u_Format_string_allocated_too_shor;
static PyObject *__pyx_kp_u_Format_string_allocated_too_shor_2;
static PyObject *__pyx_n_s_IOError;
-static PyObject *__pyx_n_s_ImportError;
static PyObject *__pyx_n_s_IndexError;
static PyObject *__pyx_n_s_KeyError;
static PyObject *__pyx_n_s_L;
@@ -2014,7 +1722,7 @@ static PyObject *__pyx_kp_u_Non_native_byte_order_not_suppor;
static PyObject *__pyx_kp_s_P_Knobel;
static PyObject *__pyx_kp_s_Parameter_value_must_be_a_string;
static PyObject *__pyx_n_s_RuntimeError;
-static PyObject *__pyx_kp_s_S;
+static PyObject *__pyx_kp_b_S;
static PyObject *__pyx_n_s_SF_ERR_FILE_OPEN;
static PyObject *__pyx_n_s_SF_ERR_NO_ERRORS;
static PyObject *__pyx_n_s_SF_ERR_SCAN_NOT_FOUND;
@@ -2065,9 +1773,9 @@ static PyObject *__pyx_kp_s_Unable_to_parse_scan_header_line;
static PyObject *__pyx_kp_s_Valid_keys;
static PyObject *__pyx_n_s_ValueError;
static PyObject *__pyx_kp_s__14;
-static PyObject *__pyx_kp_s__25;
-static PyObject *__pyx_kp_s__27;
static PyObject *__pyx_kp_s__28;
+static PyObject *__pyx_kp_s__30;
+static PyObject *__pyx_kp_s__31;
static PyObject *__pyx_kp_s__7;
static PyObject *__pyx_n_s_add_or_concatenate;
static PyObject *__pyx_n_s_all_calib_values;
@@ -2082,6 +1790,7 @@ static PyObject *__pyx_n_s_calibration;
static PyObject *__pyx_n_s_chann_line;
static PyObject *__pyx_n_s_chann_lines;
static PyObject *__pyx_n_s_channels;
+static PyObject *__pyx_n_s_chunk;
static PyObject *__pyx_n_s_close;
static PyObject *__pyx_kp_u_d_d;
static PyObject *__pyx_n_s_data;
@@ -2096,7 +1805,9 @@ static PyObject *__pyx_n_s_double;
static PyObject *__pyx_n_s_dtype;
static PyObject *__pyx_n_s_empty;
static PyObject *__pyx_n_s_encode;
+static PyObject *__pyx_n_s_enter;
static PyObject *__pyx_n_s_enumerate;
+static PyObject *__pyx_n_s_exit;
static PyObject *__pyx_n_s_f;
static PyObject *__pyx_n_s_file_header;
static PyObject *__pyx_n_s_file_header_dict;
@@ -2163,8 +1874,6 @@ static PyObject *__pyx_n_s_number_2;
static PyObject *__pyx_kp_s_number_and_M_the_order_eg_2_3;
static PyObject *__pyx_n_s_number_of_mca;
static PyObject *__pyx_n_s_numpy;
-static PyObject *__pyx_kp_s_numpy_core_multiarray_failed_to;
-static PyObject *__pyx_kp_s_numpy_core_umath_failed_to_impor;
static PyObject *__pyx_n_s_object;
static PyObject *__pyx_n_s_one_line_calib_values;
static PyObject *__pyx_n_s_one_line_chann_values;
@@ -2182,7 +1891,9 @@ static PyObject *__pyx_n_s_prepare;
static PyObject *__pyx_n_s_property;
static PyObject *__pyx_n_s_qualname;
static PyObject *__pyx_n_s_range;
+static PyObject *__pyx_n_s_rb;
static PyObject *__pyx_n_s_re;
+static PyObject *__pyx_n_s_read;
static PyObject *__pyx_n_s_record;
static PyObject *__pyx_n_s_record_exists_in_hdr;
static PyObject *__pyx_n_s_ret;
@@ -2216,75 +1927,13 @@ static PyObject *__pyx_kp_s_the_unique_scan_index_or_a_strin;
static PyObject *__pyx_n_s_throw;
static PyObject *__pyx_n_s_transpose;
static PyObject *__pyx_kp_u_unknown_dtype_code_in_numpy_pxd;
-static PyObject *__pyx_kp_s_users_kieffer_workspace_400_rel;
+static PyObject *__pyx_kp_s_users_knobel_git_silx_silx_io_s;
static PyObject *__pyx_n_s_value;
static PyObject *__pyx_n_s_version;
static PyObject *__pyx_n_s_version_info;
static PyObject *__pyx_kp_s_w;
static PyObject *__pyx_kp_s_w_2;
static PyObject *__pyx_n_s_warning;
-static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_scan); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_6__len__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_key); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_10__iter__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile__add_or_concatenate(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_dictionary, PyObject *__pyx_v_key, PyObject *__pyx_v_value); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_specfile, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_2index(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_4number(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_6order(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_8header(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_10scan_header(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_12file_header(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_14scan_header_dict(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_16mca_header_dict(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_18file_header_dict(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_20labels(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_22data(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_24mca(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_26motor_names(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_28motor_positions(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_30record_exists_in_hdr(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_record); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_32data_line(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_line_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_label); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_36motor_position_by_name(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_name); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_2_string_to_char_star(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_string_); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_4is_specfile(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_filename); /* proto */
-static int __pyx_pf_4silx_2io_8specfile_8SpecFile___cinit__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_filename); /* proto */
-static int __pyx_pf_4silx_2io_8specfile_8SpecFile_2__init__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_filename); /* proto */
-static void __pyx_pf_4silx_2io_8specfile_8SpecFile_4__dealloc__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
-static Py_ssize_t __pyx_pf_4silx_2io_8specfile_8SpecFile_6__len__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_8__iter__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_key); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
-static int __pyx_pf_4silx_2io_8specfile_8SpecFile_15__contains__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_key); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_17_get_error_string(CYTHON_UNUSED struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_error_code); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_19_handle_error(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_error_code); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_21index(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_number, PyObject *__pyx_v_scan_order); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_23number(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_25order(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_27_list(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_29list(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_label); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_39columns(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_41command(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_43date(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_positions(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_position_by_name(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_name); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_53number_of_mca(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55mca_calibration(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index); /* proto */
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_57get_mca(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_mca_index); /* proto */
-static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */
-static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_self, Py_buffer *__pyx_v_info); /* proto */
-static PyObject *__pyx_tp_new_4silx_2io_8specfile_SpecFile(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
-static PyObject *__pyx_tp_new_4silx_2io_8specfile___pyx_scope_struct____iter__(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
-static PyObject *__pyx_tp_new_4silx_2io_8specfile___pyx_scope_struct_1___iter__(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
static PyObject *__pyx_float_0_;
static PyObject *__pyx_float_1_;
static PyObject *__pyx_int_0;
@@ -2303,6 +1952,7 @@ static PyObject *__pyx_int_12;
static PyObject *__pyx_int_13;
static PyObject *__pyx_int_14;
static PyObject *__pyx_int_15;
+static PyObject *__pyx_int_2500;
static PyObject *__pyx_int_neg_1;
static PyObject *__pyx_tuple__2;
static PyObject *__pyx_tuple__3;
@@ -2325,11 +1975,10 @@ static PyObject *__pyx_tuple__21;
static PyObject *__pyx_tuple__22;
static PyObject *__pyx_tuple__23;
static PyObject *__pyx_tuple__24;
+static PyObject *__pyx_tuple__25;
static PyObject *__pyx_tuple__26;
+static PyObject *__pyx_tuple__27;
static PyObject *__pyx_tuple__29;
-static PyObject *__pyx_tuple__30;
-static PyObject *__pyx_tuple__31;
-static PyObject *__pyx_tuple__32;
static PyObject *__pyx_tuple__33;
static PyObject *__pyx_tuple__34;
static PyObject *__pyx_tuple__35;
@@ -2337,61 +1986,62 @@ static PyObject *__pyx_tuple__36;
static PyObject *__pyx_tuple__37;
static PyObject *__pyx_tuple__38;
static PyObject *__pyx_tuple__39;
-static PyObject *__pyx_tuple__41;
-static PyObject *__pyx_tuple__43;
-static PyObject *__pyx_tuple__45;
-static PyObject *__pyx_tuple__47;
-static PyObject *__pyx_tuple__49;
-static PyObject *__pyx_tuple__51;
-static PyObject *__pyx_tuple__53;
-static PyObject *__pyx_tuple__55;
-static PyObject *__pyx_tuple__57;
-static PyObject *__pyx_tuple__59;
-static PyObject *__pyx_tuple__61;
-static PyObject *__pyx_tuple__63;
-static PyObject *__pyx_tuple__65;
-static PyObject *__pyx_tuple__67;
-static PyObject *__pyx_tuple__69;
-static PyObject *__pyx_tuple__71;
-static PyObject *__pyx_tuple__73;
-static PyObject *__pyx_tuple__75;
-static PyObject *__pyx_tuple__77;
-static PyObject *__pyx_tuple__79;
-static PyObject *__pyx_tuple__81;
-static PyObject *__pyx_tuple__83;
-static PyObject *__pyx_tuple__85;
-static PyObject *__pyx_tuple__87;
-static PyObject *__pyx_tuple__89;
-static PyObject *__pyx_tuple__91;
-static PyObject *__pyx_tuple__93;
-static PyObject *__pyx_codeobj__40;
-static PyObject *__pyx_codeobj__42;
-static PyObject *__pyx_codeobj__44;
-static PyObject *__pyx_codeobj__46;
-static PyObject *__pyx_codeobj__48;
-static PyObject *__pyx_codeobj__50;
-static PyObject *__pyx_codeobj__52;
-static PyObject *__pyx_codeobj__54;
-static PyObject *__pyx_codeobj__56;
-static PyObject *__pyx_codeobj__58;
-static PyObject *__pyx_codeobj__60;
-static PyObject *__pyx_codeobj__62;
-static PyObject *__pyx_codeobj__64;
-static PyObject *__pyx_codeobj__66;
-static PyObject *__pyx_codeobj__68;
-static PyObject *__pyx_codeobj__70;
-static PyObject *__pyx_codeobj__72;
-static PyObject *__pyx_codeobj__74;
-static PyObject *__pyx_codeobj__76;
-static PyObject *__pyx_codeobj__78;
-static PyObject *__pyx_codeobj__80;
-static PyObject *__pyx_codeobj__82;
-static PyObject *__pyx_codeobj__84;
-static PyObject *__pyx_codeobj__86;
-static PyObject *__pyx_codeobj__88;
-static PyObject *__pyx_codeobj__90;
-static PyObject *__pyx_codeobj__92;
-static PyObject *__pyx_codeobj__94;
+static PyObject *__pyx_tuple__40;
+static PyObject *__pyx_tuple__42;
+static PyObject *__pyx_tuple__44;
+static PyObject *__pyx_tuple__46;
+static PyObject *__pyx_tuple__48;
+static PyObject *__pyx_tuple__50;
+static PyObject *__pyx_tuple__52;
+static PyObject *__pyx_tuple__54;
+static PyObject *__pyx_tuple__56;
+static PyObject *__pyx_tuple__58;
+static PyObject *__pyx_tuple__60;
+static PyObject *__pyx_tuple__62;
+static PyObject *__pyx_tuple__64;
+static PyObject *__pyx_tuple__66;
+static PyObject *__pyx_tuple__68;
+static PyObject *__pyx_tuple__70;
+static PyObject *__pyx_tuple__72;
+static PyObject *__pyx_tuple__74;
+static PyObject *__pyx_tuple__76;
+static PyObject *__pyx_tuple__78;
+static PyObject *__pyx_tuple__80;
+static PyObject *__pyx_tuple__82;
+static PyObject *__pyx_tuple__84;
+static PyObject *__pyx_tuple__86;
+static PyObject *__pyx_tuple__88;
+static PyObject *__pyx_tuple__90;
+static PyObject *__pyx_tuple__92;
+static PyObject *__pyx_tuple__94;
+static PyObject *__pyx_codeobj__41;
+static PyObject *__pyx_codeobj__43;
+static PyObject *__pyx_codeobj__45;
+static PyObject *__pyx_codeobj__47;
+static PyObject *__pyx_codeobj__49;
+static PyObject *__pyx_codeobj__51;
+static PyObject *__pyx_codeobj__53;
+static PyObject *__pyx_codeobj__55;
+static PyObject *__pyx_codeobj__57;
+static PyObject *__pyx_codeobj__59;
+static PyObject *__pyx_codeobj__61;
+static PyObject *__pyx_codeobj__63;
+static PyObject *__pyx_codeobj__65;
+static PyObject *__pyx_codeobj__67;
+static PyObject *__pyx_codeobj__69;
+static PyObject *__pyx_codeobj__71;
+static PyObject *__pyx_codeobj__73;
+static PyObject *__pyx_codeobj__75;
+static PyObject *__pyx_codeobj__77;
+static PyObject *__pyx_codeobj__79;
+static PyObject *__pyx_codeobj__81;
+static PyObject *__pyx_codeobj__83;
+static PyObject *__pyx_codeobj__85;
+static PyObject *__pyx_codeobj__87;
+static PyObject *__pyx_codeobj__89;
+static PyObject *__pyx_codeobj__91;
+static PyObject *__pyx_codeobj__93;
+static PyObject *__pyx_codeobj__95;
/* "silx/io/specfile.pyx":233
*
@@ -2408,6 +2058,9 @@ static PyMethodDef __pyx_mdef_4silx_2io_8specfile_3MCA_1__init__ = {"__init__",
static PyObject *__pyx_pw_4silx_2io_8specfile_3MCA_1__init__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_self = 0;
PyObject *__pyx_v_scan = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("__init__ (wrapper)", 0);
@@ -2431,11 +2084,11 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_3MCA_1__init__(PyObject *__pyx_sel
case 1:
if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_scan)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("__init__", 1, 2, 2, 1); __PYX_ERR(0, 233, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("__init__", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 233, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
goto __pyx_L5_argtuple_error;
@@ -2448,7 +2101,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_3MCA_1__init__(PyObject *__pyx_sel
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("__init__", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 233, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("__init__", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.MCA.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
@@ -2467,6 +2120,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA___init__(CYTHON_UNUSED PyObje
PyObject *__pyx_t_1 = NULL;
PyObject *__pyx_t_2 = NULL;
PyObject *__pyx_t_3 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__init__", 0);
/* "silx/io/specfile.pyx":234
@@ -2476,7 +2132,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA___init__(CYTHON_UNUSED PyObje
*
* # Header dict
*/
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_scan_2, __pyx_v_scan) < 0) __PYX_ERR(0, 234, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_scan_2, __pyx_v_scan) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":237
*
@@ -2485,9 +2141,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA___init__(CYTHON_UNUSED PyObje
*
* self.calibration = []
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_scan, __pyx_n_s_mca_header_dict); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 237, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_scan, __pyx_n_s_mca_header_dict); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_header, __pyx_t_1) < 0) __PYX_ERR(0, 237, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_header, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":239
@@ -2497,9 +2153,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA___init__(CYTHON_UNUSED PyObje
* """List of lists of calibration values,
* one list of 3 floats per MCA device or a single list applying to
*/
- __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 239, __pyx_L1_error)
+ __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 239; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_calibration, __pyx_t_1) < 0) __PYX_ERR(0, 239, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_calibration, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 239; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":243
@@ -2509,10 +2165,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA___init__(CYTHON_UNUSED PyObje
*
* self.channels = []
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_parse_calibration); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 243, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_parse_calibration); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_3 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -2522,10 +2178,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA___init__(CYTHON_UNUSED PyObje
}
}
if (__pyx_t_3) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 243, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
} else {
- __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 243, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 243; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -2538,9 +2194,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA___init__(CYTHON_UNUSED PyObje
* """List of lists of channels,
* one list of integers per MCA device or a single list applying to
*/
- __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 245, __pyx_L1_error)
+ __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_channels, __pyx_t_1) < 0) __PYX_ERR(0, 245, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_channels, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":249
@@ -2550,10 +2206,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA___init__(CYTHON_UNUSED PyObje
*
* def _parse_channels(self):
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_parse_channels); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 249, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_parse_channels); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 249; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_3 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -2563,10 +2219,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA___init__(CYTHON_UNUSED PyObje
}
}
if (__pyx_t_3) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 249, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 249; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
} else {
- __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 249, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 249; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -2642,6 +2298,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
PyObject *__pyx_t_11 = NULL;
PyObject *(*__pyx_t_12)(PyObject *);
int __pyx_t_13;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("_parse_channels", 0);
/* "silx/io/specfile.pyx":254
@@ -2651,9 +2310,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
* chann_lines = self._header["CHANN"].split("\n")
* all_chann_values = [chann_line.split() for chann_line in chann_lines]
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 254, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 254; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = (__Pyx_PySequence_ContainsTF(__pyx_n_s_CHANN, __pyx_t_1, Py_EQ)); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 254, __pyx_L1_error)
+ __pyx_t_2 = (__Pyx_PySequence_Contains(__pyx_n_s_CHANN, __pyx_t_1, Py_EQ)); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 254; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_3 = (__pyx_t_2 != 0);
if (__pyx_t_3) {
@@ -2665,15 +2324,15 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
* all_chann_values = [chann_line.split() for chann_line in chann_lines]
* for one_line_chann_values in all_chann_values:
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 255, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 255; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_4 = PyObject_GetItem(__pyx_t_1, __pyx_n_s_CHANN); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 255, __pyx_L1_error)
+ __pyx_t_4 = PyObject_GetItem(__pyx_t_1, __pyx_n_s_CHANN); if (unlikely(__pyx_t_4 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 255; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_split); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 255, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_split); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 255; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 255, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 255; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_chann_lines = __pyx_t_4;
@@ -2686,33 +2345,31 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
* for one_line_chann_values in all_chann_values:
* length, start, stop, increment = map(int, one_line_chann_values)
*/
- __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 256, __pyx_L1_error)
+ __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
if (likely(PyList_CheckExact(__pyx_v_chann_lines)) || PyTuple_CheckExact(__pyx_v_chann_lines)) {
__pyx_t_1 = __pyx_v_chann_lines; __Pyx_INCREF(__pyx_t_1); __pyx_t_5 = 0;
__pyx_t_6 = NULL;
} else {
- __pyx_t_5 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_chann_lines); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 256, __pyx_L1_error)
+ __pyx_t_5 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_chann_lines); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_6 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 256, __pyx_L1_error)
+ __pyx_t_6 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
for (;;) {
if (likely(!__pyx_t_6)) {
if (likely(PyList_CheckExact(__pyx_t_1))) {
if (__pyx_t_5 >= PyList_GET_SIZE(__pyx_t_1)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_7 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++; if (unlikely(0 < 0)) __PYX_ERR(0, 256, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_7 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_7 = PySequence_ITEM(__pyx_t_1, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 256, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
+ __pyx_t_7 = PySequence_ITEM(__pyx_t_1, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
} else {
if (__pyx_t_5 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_7 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++; if (unlikely(0 < 0)) __PYX_ERR(0, 256, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_7 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_7 = PySequence_ITEM(__pyx_t_1, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 256, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
+ __pyx_t_7 = PySequence_ITEM(__pyx_t_1, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
}
} else {
@@ -2721,7 +2378,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
PyObject* exc_type = PyErr_Occurred();
if (exc_type) {
if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
- else __PYX_ERR(0, 256, __pyx_L1_error)
+ else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
break;
}
@@ -2729,10 +2386,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
}
__Pyx_XDECREF_SET(__pyx_v_chann_line, __pyx_t_7);
__pyx_t_7 = 0;
- __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_chann_line, __pyx_n_s_split); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 256, __pyx_L1_error)
+ __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_chann_line, __pyx_n_s_split); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_8);
__pyx_t_9 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_8))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_8))) {
__pyx_t_9 = PyMethod_GET_SELF(__pyx_t_8);
if (likely(__pyx_t_9)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8);
@@ -2742,14 +2399,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
}
}
if (__pyx_t_9) {
- __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_9); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 256, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_9); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
} else {
- __pyx_t_7 = __Pyx_PyObject_CallNoArg(__pyx_t_8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 256, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_CallNoArg(__pyx_t_8); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- if (unlikely(__Pyx_ListComp_Append(__pyx_t_4, (PyObject*)__pyx_t_7))) __PYX_ERR(0, 256, __pyx_L1_error)
+ if (unlikely(__Pyx_ListComp_Append(__pyx_t_4, (PyObject*)__pyx_t_7))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 256; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -2766,11 +2423,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
__pyx_t_4 = __pyx_v_all_chann_values; __Pyx_INCREF(__pyx_t_4); __pyx_t_5 = 0;
for (;;) {
if (__pyx_t_5 >= PyList_GET_SIZE(__pyx_t_4)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_1 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_5); __Pyx_INCREF(__pyx_t_1); __pyx_t_5++; if (unlikely(0 < 0)) __PYX_ERR(0, 257, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_1 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_5); __Pyx_INCREF(__pyx_t_1); __pyx_t_5++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 257; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_1 = PySequence_ITEM(__pyx_t_4, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 257, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
+ __pyx_t_1 = PySequence_ITEM(__pyx_t_4, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 257; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
__Pyx_XDECREF_SET(__pyx_v_one_line_chann_values, __pyx_t_1);
__pyx_t_1 = 0;
@@ -2782,20 +2438,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
* self.channels.append(list(range(start, stop + 1, increment)))
* elif len(self):
*/
- __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 258, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_INCREF(((PyObject *)(&PyInt_Type)));
- __Pyx_GIVEREF(((PyObject *)(&PyInt_Type)));
- PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)(&PyInt_Type)));
+ __Pyx_INCREF(((PyObject *)((PyObject*)(&PyInt_Type))));
+ PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)((PyObject*)(&PyInt_Type))));
+ __Pyx_GIVEREF(((PyObject *)((PyObject*)(&PyInt_Type))));
__Pyx_INCREF(__pyx_v_one_line_chann_values);
- __Pyx_GIVEREF(__pyx_v_one_line_chann_values);
PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_v_one_line_chann_values);
- __pyx_t_7 = __Pyx_PyObject_Call(__pyx_builtin_map, __pyx_t_1, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 258, __pyx_L1_error)
+ __Pyx_GIVEREF(__pyx_v_one_line_chann_values);
+ __pyx_t_7 = __Pyx_PyObject_Call(__pyx_builtin_map, __pyx_t_1, NULL); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
if ((likely(PyTuple_CheckExact(__pyx_t_7))) || (PyList_CheckExact(__pyx_t_7))) {
PyObject* sequence = __pyx_t_7;
- #if !CYTHON_COMPILING_IN_PYPY
+ #if CYTHON_COMPILING_IN_CPYTHON
Py_ssize_t size = Py_SIZE(sequence);
#else
Py_ssize_t size = PySequence_Size(sequence);
@@ -2803,9 +2459,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
if (unlikely(size != 4)) {
if (size > 4) __Pyx_RaiseTooManyValuesError(4);
else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
- __PYX_ERR(0, 258, __pyx_L1_error)
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+ #if CYTHON_COMPILING_IN_CPYTHON
if (likely(PyTuple_CheckExact(sequence))) {
__pyx_t_1 = PyTuple_GET_ITEM(sequence, 0);
__pyx_t_8 = PyTuple_GET_ITEM(sequence, 1);
@@ -2826,7 +2482,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
Py_ssize_t i;
PyObject** temps[4] = {&__pyx_t_1,&__pyx_t_8,&__pyx_t_9,&__pyx_t_10};
for (i=0; i < 4; i++) {
- PyObject* item = PySequence_ITEM(sequence, i); if (unlikely(!item)) __PYX_ERR(0, 258, __pyx_L1_error)
+ PyObject* item = PySequence_ITEM(sequence, i); if (unlikely(!item)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(item);
*(temps[i]) = item;
}
@@ -2836,7 +2492,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
} else {
Py_ssize_t index = -1;
PyObject** temps[4] = {&__pyx_t_1,&__pyx_t_8,&__pyx_t_9,&__pyx_t_10};
- __pyx_t_11 = PyObject_GetIter(__pyx_t_7); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 258, __pyx_L1_error)
+ __pyx_t_11 = PyObject_GetIter(__pyx_t_7); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_11);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
__pyx_t_12 = Py_TYPE(__pyx_t_11)->tp_iternext;
@@ -2845,7 +2501,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
__Pyx_GOTREF(item);
*(temps[index]) = item;
}
- if (__Pyx_IternextUnpackEndCheck(__pyx_t_12(__pyx_t_11), 4) < 0) __PYX_ERR(0, 258, __pyx_L1_error)
+ if (__Pyx_IternextUnpackEndCheck(__pyx_t_12(__pyx_t_11), 4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_t_12 = NULL;
__Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
goto __pyx_L9_unpacking_done;
@@ -2853,7 +2509,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
__Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
__pyx_t_12 = NULL;
if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
- __PYX_ERR(0, 258, __pyx_L1_error)
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_L9_unpacking_done:;
}
__Pyx_XDECREF_SET(__pyx_v_length, __pyx_t_1);
@@ -2872,30 +2528,35 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
* elif len(self):
* # in the absence of #@CHANN, use shape of first MCA
*/
- __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_channels); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 259, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_channels); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 259; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
- __pyx_t_10 = __Pyx_PyInt_AddObjC(__pyx_v_stop, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 259, __pyx_L1_error)
+ __pyx_t_10 = PyNumber_Add(__pyx_v_stop, __pyx_int_1); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 259; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
- __pyx_t_9 = PyTuple_New(3); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 259, __pyx_L1_error)
+ __pyx_t_9 = PyTuple_New(3); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 259; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_9);
__Pyx_INCREF(__pyx_v_start);
- __Pyx_GIVEREF(__pyx_v_start);
PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_v_start);
- __Pyx_GIVEREF(__pyx_t_10);
+ __Pyx_GIVEREF(__pyx_v_start);
PyTuple_SET_ITEM(__pyx_t_9, 1, __pyx_t_10);
+ __Pyx_GIVEREF(__pyx_t_10);
__Pyx_INCREF(__pyx_v_increment);
- __Pyx_GIVEREF(__pyx_v_increment);
PyTuple_SET_ITEM(__pyx_t_9, 2, __pyx_v_increment);
+ __Pyx_GIVEREF(__pyx_v_increment);
__pyx_t_10 = 0;
- __pyx_t_10 = __Pyx_PyObject_Call(__pyx_builtin_range, __pyx_t_9, NULL); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 259, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_Call(__pyx_builtin_range, __pyx_t_9, NULL); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 259; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
- __pyx_t_9 = PySequence_List(__pyx_t_10); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 259, __pyx_L1_error)
+ __pyx_t_9 = PyTuple_New(1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 259; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_9);
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- __pyx_t_13 = __Pyx_PyObject_Append(__pyx_t_7, __pyx_t_9); if (unlikely(__pyx_t_13 == -1)) __PYX_ERR(0, 259, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+ PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_10);
+ __Pyx_GIVEREF(__pyx_t_10);
+ __pyx_t_10 = 0;
+ __pyx_t_10 = __Pyx_PyObject_Call(((PyObject *)((PyObject*)(&PyList_Type))), __pyx_t_9, NULL); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 259; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+ __pyx_t_13 = __Pyx_PyObject_Append(__pyx_t_7, __pyx_t_10); if (unlikely(__pyx_t_13 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 259; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+ __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
/* "silx/io/specfile.pyx":257
* chann_lines = self._header["CHANN"].split("\n")
@@ -2906,14 +2567,6 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
*/
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-
- /* "silx/io/specfile.pyx":254
- * """Fill :attr:`channels`"""
- * # Channels list
- * if "CHANN" in self._header: # <<<<<<<<<<<<<<
- * chann_lines = self._header["CHANN"].split("\n")
- * all_chann_values = [chann_line.split() for chann_line in chann_lines]
- */
goto __pyx_L3;
}
@@ -2924,7 +2577,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
* # in the absence of #@CHANN, use shape of first MCA
* length = self[0].shape[0]
*/
- __pyx_t_5 = PyObject_Length(__pyx_v_self); if (unlikely(__pyx_t_5 == -1)) __PYX_ERR(0, 260, __pyx_L1_error)
+ __pyx_t_5 = PyObject_Length(__pyx_v_self); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 260; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_t_3 = (__pyx_t_5 != 0);
if (__pyx_t_3) {
@@ -2935,14 +2588,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
* start, stop, increment = (0, length - 1, 1)
* self.channels.append(list(range(start, stop + 1, increment)))
*/
- __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_self, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 262, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_self, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(__pyx_t_4 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 262; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_shape); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_9);
+ __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_shape); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 262; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_4 = __Pyx_GetItemInt(__pyx_t_9, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 262, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_GetItemInt(__pyx_t_10, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(__pyx_t_4 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 262; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+ __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__pyx_v_length = __pyx_t_4;
__pyx_t_4 = 0;
@@ -2955,14 +2608,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
*/
__pyx_t_4 = __pyx_int_0;
__Pyx_INCREF(__pyx_t_4);
- __pyx_t_9 = __Pyx_PyInt_SubtractObjC(__pyx_v_length, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 263, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_9);
+ __pyx_t_10 = PyNumber_Subtract(__pyx_v_length, __pyx_int_1); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 263; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_10);
__pyx_t_7 = __pyx_int_1;
__Pyx_INCREF(__pyx_t_7);
__pyx_v_start = __pyx_t_4;
__pyx_t_4 = 0;
- __pyx_v_stop = __pyx_t_9;
- __pyx_t_9 = 0;
+ __pyx_v_stop = __pyx_t_10;
+ __pyx_t_10 = 0;
__pyx_v_increment = __pyx_t_7;
__pyx_t_7 = 0;
@@ -2973,38 +2626,36 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_2_parse_channels(CYTHON_UNUSE
*
* def _parse_calibration(self):
*/
- __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_channels); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 264, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_channels); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
- __pyx_t_9 = __Pyx_PyInt_AddObjC(__pyx_v_stop, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_9);
- __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 264, __pyx_L1_error)
+ __pyx_t_10 = PyNumber_Add(__pyx_v_stop, __pyx_int_1); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_10);
+ __pyx_t_4 = PyTuple_New(3); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_INCREF(__pyx_v_start);
- __Pyx_GIVEREF(__pyx_v_start);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_start);
- __Pyx_GIVEREF(__pyx_t_9);
- PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_9);
+ __Pyx_GIVEREF(__pyx_v_start);
+ PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_10);
+ __Pyx_GIVEREF(__pyx_t_10);
__Pyx_INCREF(__pyx_v_increment);
- __Pyx_GIVEREF(__pyx_v_increment);
PyTuple_SET_ITEM(__pyx_t_4, 2, __pyx_v_increment);
- __pyx_t_9 = 0;
- __pyx_t_9 = __Pyx_PyObject_Call(__pyx_builtin_range, __pyx_t_4, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_9);
+ __Pyx_GIVEREF(__pyx_v_increment);
+ __pyx_t_10 = 0;
+ __pyx_t_10 = __Pyx_PyObject_Call(__pyx_builtin_range, __pyx_t_4, NULL); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_4 = PySequence_List(__pyx_t_9); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 264, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
- __pyx_t_13 = __Pyx_PyObject_Append(__pyx_t_7, __pyx_t_4); if (unlikely(__pyx_t_13 == -1)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+ PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_10);
+ __Pyx_GIVEREF(__pyx_t_10);
+ __pyx_t_10 = 0;
+ __pyx_t_10 = __Pyx_PyObject_Call(((PyObject *)((PyObject*)(&PyList_Type))), __pyx_t_4, NULL); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-
- /* "silx/io/specfile.pyx":260
- * length, start, stop, increment = map(int, one_line_chann_values)
- * self.channels.append(list(range(start, stop + 1, increment)))
- * elif len(self): # <<<<<<<<<<<<<<
- * # in the absence of #@CHANN, use shape of first MCA
- * length = self[0].shape[0]
- */
+ __pyx_t_13 = __Pyx_PyObject_Append(__pyx_t_7, __pyx_t_10); if (unlikely(__pyx_t_13 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+ __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+ goto __pyx_L3;
}
__pyx_L3:;
@@ -3083,6 +2734,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UN
PyObject *__pyx_t_8 = NULL;
PyObject *__pyx_t_9 = NULL;
int __pyx_t_10;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("_parse_calibration", 0);
/* "silx/io/specfile.pyx":269
@@ -3092,9 +2746,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UN
* calib_lines = self._header["CALIB"].split("\n")
* all_calib_values = [calib_line.split() for calib_line in calib_lines]
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 269, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = (__Pyx_PySequence_ContainsTF(__pyx_n_s_CALIB, __pyx_t_1, Py_EQ)); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 269, __pyx_L1_error)
+ __pyx_t_2 = (__Pyx_PySequence_Contains(__pyx_n_s_CALIB, __pyx_t_1, Py_EQ)); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_3 = (__pyx_t_2 != 0);
if (__pyx_t_3) {
@@ -3106,15 +2760,15 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UN
* all_calib_values = [calib_line.split() for calib_line in calib_lines]
* for one_line_calib_values in all_calib_values:
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 270, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_4 = PyObject_GetItem(__pyx_t_1, __pyx_n_s_CALIB); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 270, __pyx_L1_error)
+ __pyx_t_4 = PyObject_GetItem(__pyx_t_1, __pyx_n_s_CALIB); if (unlikely(__pyx_t_4 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_split); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 270, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_split); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 270, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_calib_lines = __pyx_t_4;
@@ -3127,33 +2781,31 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UN
* for one_line_calib_values in all_calib_values:
* self.calibration.append(list(map(float, one_line_calib_values)))
*/
- __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 271, __pyx_L1_error)
+ __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
if (likely(PyList_CheckExact(__pyx_v_calib_lines)) || PyTuple_CheckExact(__pyx_v_calib_lines)) {
__pyx_t_1 = __pyx_v_calib_lines; __Pyx_INCREF(__pyx_t_1); __pyx_t_5 = 0;
__pyx_t_6 = NULL;
} else {
- __pyx_t_5 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_calib_lines); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 271, __pyx_L1_error)
+ __pyx_t_5 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_calib_lines); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_6 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 271, __pyx_L1_error)
+ __pyx_t_6 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
for (;;) {
if (likely(!__pyx_t_6)) {
if (likely(PyList_CheckExact(__pyx_t_1))) {
if (__pyx_t_5 >= PyList_GET_SIZE(__pyx_t_1)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_7 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++; if (unlikely(0 < 0)) __PYX_ERR(0, 271, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_7 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_7 = PySequence_ITEM(__pyx_t_1, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 271, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
+ __pyx_t_7 = PySequence_ITEM(__pyx_t_1, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
} else {
if (__pyx_t_5 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_7 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++; if (unlikely(0 < 0)) __PYX_ERR(0, 271, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_7 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_7 = PySequence_ITEM(__pyx_t_1, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 271, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
+ __pyx_t_7 = PySequence_ITEM(__pyx_t_1, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
}
} else {
@@ -3162,7 +2814,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UN
PyObject* exc_type = PyErr_Occurred();
if (exc_type) {
if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
- else __PYX_ERR(0, 271, __pyx_L1_error)
+ else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
break;
}
@@ -3170,10 +2822,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UN
}
__Pyx_XDECREF_SET(__pyx_v_calib_line, __pyx_t_7);
__pyx_t_7 = 0;
- __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_calib_line, __pyx_n_s_split); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 271, __pyx_L1_error)
+ __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_calib_line, __pyx_n_s_split); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_8);
__pyx_t_9 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_8))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_8))) {
__pyx_t_9 = PyMethod_GET_SELF(__pyx_t_8);
if (likely(__pyx_t_9)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8);
@@ -3183,14 +2835,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UN
}
}
if (__pyx_t_9) {
- __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_9); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 271, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_9); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
} else {
- __pyx_t_7 = __Pyx_PyObject_CallNoArg(__pyx_t_8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 271, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_CallNoArg(__pyx_t_8); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- if (unlikely(__Pyx_ListComp_Append(__pyx_t_4, (PyObject*)__pyx_t_7))) __PYX_ERR(0, 271, __pyx_L1_error)
+ if (unlikely(__Pyx_ListComp_Append(__pyx_t_4, (PyObject*)__pyx_t_7))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -3207,11 +2859,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UN
__pyx_t_4 = __pyx_v_all_calib_values; __Pyx_INCREF(__pyx_t_4); __pyx_t_5 = 0;
for (;;) {
if (__pyx_t_5 >= PyList_GET_SIZE(__pyx_t_4)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_1 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_5); __Pyx_INCREF(__pyx_t_1); __pyx_t_5++; if (unlikely(0 < 0)) __PYX_ERR(0, 272, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_1 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_5); __Pyx_INCREF(__pyx_t_1); __pyx_t_5++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 272; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_1 = PySequence_ITEM(__pyx_t_4, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 272, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
+ __pyx_t_1 = PySequence_ITEM(__pyx_t_4, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 272; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
__Pyx_XDECREF_SET(__pyx_v_one_line_calib_values, __pyx_t_1);
__pyx_t_1 = 0;
@@ -3223,25 +2874,30 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UN
* else:
* # in the absence of #@calib, use default
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_calibration); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 273, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_calibration); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 273; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 273, __pyx_L1_error)
+ __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 273; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
- __Pyx_INCREF(((PyObject *)(&PyFloat_Type)));
- __Pyx_GIVEREF(((PyObject *)(&PyFloat_Type)));
- PyTuple_SET_ITEM(__pyx_t_7, 0, ((PyObject *)(&PyFloat_Type)));
+ __Pyx_INCREF(((PyObject *)((PyObject*)(&PyFloat_Type))));
+ PyTuple_SET_ITEM(__pyx_t_7, 0, ((PyObject *)((PyObject*)(&PyFloat_Type))));
+ __Pyx_GIVEREF(((PyObject *)((PyObject*)(&PyFloat_Type))));
__Pyx_INCREF(__pyx_v_one_line_calib_values);
- __Pyx_GIVEREF(__pyx_v_one_line_calib_values);
PyTuple_SET_ITEM(__pyx_t_7, 1, __pyx_v_one_line_calib_values);
- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_map, __pyx_t_7, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 273, __pyx_L1_error)
+ __Pyx_GIVEREF(__pyx_v_one_line_calib_values);
+ __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_map, __pyx_t_7, NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 273; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_8);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- __pyx_t_7 = PySequence_List(__pyx_t_8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 273, __pyx_L1_error)
+ __pyx_t_7 = PyTuple_New(1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 273; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- __pyx_t_10 = __Pyx_PyObject_Append(__pyx_t_1, __pyx_t_7); if (unlikely(__pyx_t_10 == -1)) __PYX_ERR(0, 273, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_8);
+ __Pyx_GIVEREF(__pyx_t_8);
+ __pyx_t_8 = 0;
+ __pyx_t_8 = __Pyx_PyObject_Call(((PyObject *)((PyObject*)(&PyList_Type))), __pyx_t_7, NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 273; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+ __pyx_t_10 = __Pyx_PyObject_Append(__pyx_t_1, __pyx_t_8); if (unlikely(__pyx_t_10 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 273; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
/* "silx/io/specfile.pyx":272
* calib_lines = self._header["CALIB"].split("\n")
@@ -3252,41 +2908,33 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_4_parse_calibration(CYTHON_UN
*/
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-
- /* "silx/io/specfile.pyx":269
- * """Fill :attr:`calibration`"""
- * # Channels list
- * if "CALIB" in self._header: # <<<<<<<<<<<<<<
- * calib_lines = self._header["CALIB"].split("\n")
- * all_calib_values = [calib_line.split() for calib_line in calib_lines]
- */
goto __pyx_L3;
}
+ /*else*/ {
- /* "silx/io/specfile.pyx":276
+ /* "silx/io/specfile.pyx":276
* else:
* # in the absence of #@calib, use default
* self.calibration.append([0., 1., 0.]) # <<<<<<<<<<<<<<
*
* def __len__(self):
*/
- /*else*/ {
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_calibration); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 276, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_calibration); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_7 = PyList_New(3); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 276, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
+ __pyx_t_8 = PyList_New(3); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
__Pyx_INCREF(__pyx_float_0_);
+ PyList_SET_ITEM(__pyx_t_8, 0, __pyx_float_0_);
__Pyx_GIVEREF(__pyx_float_0_);
- PyList_SET_ITEM(__pyx_t_7, 0, __pyx_float_0_);
__Pyx_INCREF(__pyx_float_1_);
+ PyList_SET_ITEM(__pyx_t_8, 1, __pyx_float_1_);
__Pyx_GIVEREF(__pyx_float_1_);
- PyList_SET_ITEM(__pyx_t_7, 1, __pyx_float_1_);
__Pyx_INCREF(__pyx_float_0_);
+ PyList_SET_ITEM(__pyx_t_8, 2, __pyx_float_0_);
__Pyx_GIVEREF(__pyx_float_0_);
- PyList_SET_ITEM(__pyx_t_7, 2, __pyx_float_0_);
- __pyx_t_10 = __Pyx_PyObject_Append(__pyx_t_4, __pyx_t_7); if (unlikely(__pyx_t_10 == -1)) __PYX_ERR(0, 276, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_Append(__pyx_t_4, __pyx_t_8); if (unlikely(__pyx_t_10 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
}
__pyx_L3:;
@@ -3350,6 +2998,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_6__len__(CYTHON_UNUSED PyObje
PyObject *__pyx_t_3 = NULL;
PyObject *__pyx_t_4 = NULL;
PyObject *__pyx_t_5 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__len__", 0);
/* "silx/io/specfile.pyx":284
@@ -3360,21 +3011,21 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_6__len__(CYTHON_UNUSED PyObje
* def __getitem__(self, key):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 284, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_specfile); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 284, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_specfile); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_number_of_mca); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 284, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_number_of_mca); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 284, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_index); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 284, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_index); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_3 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -3384,39 +3035,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_6__len__(CYTHON_UNUSED PyObje
}
}
if (!__pyx_t_3) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 284, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_t_4};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 284, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_t_4};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 284, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- } else
- #endif
- {
- __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 284, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3); __pyx_t_3 = NULL;
- __Pyx_GIVEREF(__pyx_t_4);
- PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_t_4);
- __pyx_t_4 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 284, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- }
+ __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_5);
+ PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3); __Pyx_GIVEREF(__pyx_t_3); __pyx_t_3 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_t_4);
+ __Pyx_GIVEREF(__pyx_t_4);
+ __pyx_t_4 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_r = __pyx_t_1;
@@ -3461,6 +3092,9 @@ static PyMethodDef __pyx_mdef_4silx_2io_8specfile_3MCA_9__getitem__ = {"__getite
static PyObject *__pyx_pw_4silx_2io_8specfile_3MCA_9__getitem__(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_self = 0;
PyObject *__pyx_v_key = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0);
@@ -3484,11 +3118,11 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_3MCA_9__getitem__(PyObject *__pyx_
case 1:
if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_key)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("__getitem__", 1, 2, 2, 1); __PYX_ERR(0, 286, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("__getitem__", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__getitem__") < 0)) __PYX_ERR(0, 286, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__getitem__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
goto __pyx_L5_argtuple_error;
@@ -3501,7 +3135,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_3MCA_9__getitem__(PyObject *__pyx_
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("__getitem__", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 286, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("__getitem__", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.MCA.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
@@ -3527,8 +3161,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
PyObject *__pyx_t_6 = NULL;
PyObject *__pyx_t_7 = NULL;
PyObject *__pyx_t_8 = NULL;
- int __pyx_t_9;
- PyObject *__pyx_t_10 = NULL;
+ PyObject *__pyx_t_9 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__getitem__", 0);
/* "silx/io/specfile.pyx":295
@@ -3538,7 +3174,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
* raise IndexError("No MCA spectrum found in this scan")
*
*/
- __pyx_t_1 = PyObject_Length(__pyx_v_self); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 295, __pyx_L1_error)
+ __pyx_t_1 = PyObject_Length(__pyx_v_self); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 295; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_t_2 = ((!(__pyx_t_1 != 0)) != 0);
if (__pyx_t_2) {
@@ -3549,19 +3185,11 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
*
* if isinstance(key, (int, long)):
*/
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_IndexError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 296, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_IndexError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 296; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_Raise(__pyx_t_3, 0, 0, 0);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __PYX_ERR(0, 296, __pyx_L1_error)
-
- /* "silx/io/specfile.pyx":295
- * :rtype: 1D numpy array
- * """
- * if not len(self): # <<<<<<<<<<<<<<
- * raise IndexError("No MCA spectrum found in this scan")
- *
- */
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 296; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
/* "silx/io/specfile.pyx":298
@@ -3602,8 +3230,8 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
* mca_index = len(self) + mca_index
* else:
*/
- __pyx_t_3 = PyObject_RichCompare(__pyx_v_mca_index, __pyx_int_0, Py_LT); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 301, __pyx_L1_error)
- __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 301, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_v_mca_index, __pyx_int_0, Py_LT); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 301; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 301; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_4) {
@@ -3614,53 +3242,21 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
* else:
* raise TypeError("MCA index should be an integer (%s provided)" %
*/
- __pyx_t_1 = PyObject_Length(__pyx_v_self); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 302, __pyx_L1_error)
- __pyx_t_3 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 302, __pyx_L1_error)
+ __pyx_t_1 = PyObject_Length(__pyx_v_self); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 302; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_3 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 302; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_6 = PyNumber_Add(__pyx_t_3, __pyx_v_mca_index); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 302, __pyx_L1_error)
+ __pyx_t_6 = PyNumber_Add(__pyx_t_3, __pyx_v_mca_index); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 302; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF_SET(__pyx_v_mca_index, __pyx_t_6);
__pyx_t_6 = 0;
-
- /* "silx/io/specfile.pyx":301
- * mca_index = key
- * # allow negative index, like lists
- * if mca_index < 0: # <<<<<<<<<<<<<<
- * mca_index = len(self) + mca_index
- * else:
- */
+ goto __pyx_L7;
}
-
- /* "silx/io/specfile.pyx":298
- * raise IndexError("No MCA spectrum found in this scan")
- *
- * if isinstance(key, (int, long)): # <<<<<<<<<<<<<<
- * mca_index = key
- * # allow negative index, like lists
- */
+ __pyx_L7:;
goto __pyx_L4;
}
-
- /* "silx/io/specfile.pyx":304
- * mca_index = len(self) + mca_index
- * else:
- * raise TypeError("MCA index should be an integer (%s provided)" % # <<<<<<<<<<<<<<
- * (type(key)))
- *
- */
/*else*/ {
- /* "silx/io/specfile.pyx":305
- * else:
- * raise TypeError("MCA index should be an integer (%s provided)" %
- * (type(key))) # <<<<<<<<<<<<<<
- *
- * if not 0 <= mca_index < len(self):
- */
- __pyx_t_6 = __Pyx_PyString_Format(__pyx_kp_s_MCA_index_should_be_an_integer_s, ((PyObject *)Py_TYPE(__pyx_v_key))); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 304, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
-
/* "silx/io/specfile.pyx":304
* mca_index = len(self) + mca_index
* else:
@@ -3668,17 +3264,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
* (type(key)))
*
*/
- __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 304, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyString_Format(__pyx_kp_s_MCA_index_should_be_an_integer_s, ((PyObject *)Py_TYPE(__pyx_v_key))); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 304; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_6);
+ __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 304; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_6);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_6);
+ __Pyx_GIVEREF(__pyx_t_6);
__pyx_t_6 = 0;
- __pyx_t_6 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_t_3, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 304, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_t_3, NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 304; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_Raise(__pyx_t_6, 0, 0, 0);
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __PYX_ERR(0, 304, __pyx_L1_error)
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 304; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__pyx_L4:;
@@ -3689,16 +3287,16 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
* msg = "MCA index must be in range 0-%d" % (len(self) - 1)
* raise IndexError(msg)
*/
- __pyx_t_6 = PyObject_RichCompare(__pyx_int_0, __pyx_v_mca_index, Py_LE); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 307, __pyx_L1_error)
+ __pyx_t_6 = PyObject_RichCompare(__pyx_int_0, __pyx_v_mca_index, Py_LE); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 307; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
if (__Pyx_PyObject_IsTrue(__pyx_t_6)) {
__Pyx_DECREF(__pyx_t_6);
- __pyx_t_1 = PyObject_Length(__pyx_v_self); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 307, __pyx_L1_error)
- __pyx_t_3 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 307, __pyx_L1_error)
+ __pyx_t_1 = PyObject_Length(__pyx_v_self); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 307; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_3 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 307; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_6 = PyObject_RichCompare(__pyx_v_mca_index, __pyx_t_3, Py_LT); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 307, __pyx_L1_error)
+ __pyx_t_6 = PyObject_RichCompare(__pyx_v_mca_index, __pyx_t_3, Py_LT); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 307; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
}
- __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 307, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 307; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
__pyx_t_2 = ((!__pyx_t_4) != 0);
if (__pyx_t_2) {
@@ -3710,10 +3308,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
* raise IndexError(msg)
*
*/
- __pyx_t_1 = PyObject_Length(__pyx_v_self); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 308, __pyx_L1_error)
- __pyx_t_6 = PyInt_FromSsize_t((__pyx_t_1 - 1)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 308, __pyx_L1_error)
+ __pyx_t_1 = PyObject_Length(__pyx_v_self); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 308; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_6 = PyInt_FromSsize_t((__pyx_t_1 - 1)); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 308; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
- __pyx_t_3 = __Pyx_PyString_Format(__pyx_kp_s_MCA_index_must_be_in_range_0_d, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 308, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyString_Format(__pyx_kp_s_MCA_index_must_be_in_range_0_d, __pyx_t_6); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 308; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
__pyx_v_msg = __pyx_t_3;
@@ -3726,25 +3324,17 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
*
* return self._scan._specfile.get_mca(self._scan.index,
*/
- __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 309, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 309; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_INCREF(__pyx_v_msg);
- __Pyx_GIVEREF(__pyx_v_msg);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_msg);
- __pyx_t_6 = __Pyx_PyObject_Call(__pyx_builtin_IndexError, __pyx_t_3, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 309, __pyx_L1_error)
+ __Pyx_GIVEREF(__pyx_v_msg);
+ __pyx_t_6 = __Pyx_PyObject_Call(__pyx_builtin_IndexError, __pyx_t_3, NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 309; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_Raise(__pyx_t_6, 0, 0, 0);
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __PYX_ERR(0, 309, __pyx_L1_error)
-
- /* "silx/io/specfile.pyx":307
- * (type(key)))
- *
- * if not 0 <= mca_index < len(self): # <<<<<<<<<<<<<<
- * msg = "MCA index must be in range 0-%d" % (len(self) - 1)
- * raise IndexError(msg)
- */
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 309; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
/* "silx/io/specfile.pyx":311
@@ -3755,17 +3345,17 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
*
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 311, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 311; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_specfile); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 311, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_specfile); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 311; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_get_mca); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 311, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_get_mca); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 311; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 311, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 311; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
- __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_index); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 311, __pyx_L1_error)
+ __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_index); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 311; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_8);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
@@ -3777,51 +3367,31 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
* def __iter__(self):
*/
__pyx_t_7 = NULL;
- __pyx_t_9 = 0;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
+ __pyx_t_1 = 0;
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_7 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_7)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
__Pyx_INCREF(__pyx_t_7);
__Pyx_INCREF(function);
__Pyx_DECREF_SET(__pyx_t_3, function);
- __pyx_t_9 = 1;
+ __pyx_t_1 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_t_8, __pyx_v_mca_index};
- __pyx_t_6 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 311, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_t_8, __pyx_v_mca_index};
- __pyx_t_6 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 311, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- } else
- #endif
- {
- __pyx_t_10 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 311, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_10);
- if (__pyx_t_7) {
- __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_7); __pyx_t_7 = NULL;
- }
- __Pyx_GIVEREF(__pyx_t_8);
- PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_9, __pyx_t_8);
- __Pyx_INCREF(__pyx_v_mca_index);
- __Pyx_GIVEREF(__pyx_v_mca_index);
- PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_9, __pyx_v_mca_index);
- __pyx_t_8 = 0;
- __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_10, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 311, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+ __pyx_t_9 = PyTuple_New(2+__pyx_t_1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 311; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_9);
+ if (__pyx_t_7) {
+ PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __Pyx_GIVEREF(__pyx_t_7); __pyx_t_7 = NULL;
}
+ PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_1, __pyx_t_8);
+ __Pyx_GIVEREF(__pyx_t_8);
+ __Pyx_INCREF(__pyx_v_mca_index);
+ PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_1, __pyx_v_mca_index);
+ __Pyx_GIVEREF(__pyx_v_mca_index);
+ __pyx_t_8 = 0;
+ __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_9, NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 311; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_6);
+ __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_r = __pyx_t_6;
__pyx_t_6 = 0;
@@ -3841,7 +3411,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
__Pyx_XDECREF(__pyx_t_6);
__Pyx_XDECREF(__pyx_t_7);
__Pyx_XDECREF(__pyx_t_8);
- __Pyx_XDECREF(__pyx_t_10);
+ __Pyx_XDECREF(__pyx_t_9);
__Pyx_AddTraceback("silx.io.specfile.MCA.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
__pyx_r = NULL;
__pyx_L0:;
@@ -3851,7 +3421,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_8__getitem__(CYTHON_UNUSED Py
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_gb_4silx_2io_8specfile_3MCA_12generator(__pyx_CoroutineObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+static PyObject *__pyx_gb_4silx_2io_8specfile_3MCA_12generator(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
/* "silx/io/specfile.pyx":314
* mca_index)
@@ -3880,20 +3450,21 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_10__iter__(CYTHON_UNUSED PyOb
struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct____iter__ *__pyx_cur_scope;
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__iter__", 0);
__pyx_cur_scope = (struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct____iter__ *)__pyx_tp_new_4silx_2io_8specfile___pyx_scope_struct____iter__(__pyx_ptype_4silx_2io_8specfile___pyx_scope_struct____iter__, __pyx_empty_tuple, NULL);
if (unlikely(!__pyx_cur_scope)) {
- __pyx_cur_scope = ((struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct____iter__ *)Py_None);
- __Pyx_INCREF(Py_None);
- __PYX_ERR(0, 314, __pyx_L1_error)
- } else {
- __Pyx_GOTREF(__pyx_cur_scope);
+ __Pyx_RefNannyFinishContext();
+ return NULL;
}
+ __Pyx_GOTREF(__pyx_cur_scope);
__pyx_cur_scope->__pyx_v_self = __pyx_v_self;
__Pyx_INCREF(__pyx_cur_scope->__pyx_v_self);
__Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_self);
{
- __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_4silx_2io_8specfile_3MCA_12generator, (PyObject *) __pyx_cur_scope, __pyx_n_s_iter, __pyx_n_s_MCA___iter, __pyx_n_s_silx_io_specfile); if (unlikely(!gen)) __PYX_ERR(0, 314, __pyx_L1_error)
+ __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_4silx_2io_8specfile_3MCA_12generator, (PyObject *) __pyx_cur_scope, __pyx_n_s_iter, __pyx_n_s_MCA___iter); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 314; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_cur_scope);
__Pyx_RefNannyFinishContext();
return (PyObject *) gen;
@@ -3909,7 +3480,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_3MCA_10__iter__(CYTHON_UNUSED PyOb
return __pyx_r;
}
-static PyObject *__pyx_gb_4silx_2io_8specfile_3MCA_12generator(__pyx_CoroutineObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+static PyObject *__pyx_gb_4silx_2io_8specfile_3MCA_12generator(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
{
struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct____iter__ *__pyx_cur_scope = ((struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct____iter__ *)__pyx_generator->closure);
PyObject *__pyx_r = NULL;
@@ -3920,8 +3491,11 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_3MCA_12generator(__pyx_CoroutineOb
PyObject *__pyx_t_5 = NULL;
PyObject *__pyx_t_6 = NULL;
PyObject *__pyx_t_7 = NULL;
- int __pyx_t_8;
+ Py_ssize_t __pyx_t_8;
PyObject *__pyx_t_9 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("None", 0);
switch (__pyx_generator->resume_label) {
@@ -3932,7 +3506,7 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_3MCA_12generator(__pyx_CoroutineOb
return NULL;
}
__pyx_L3_first_run:;
- if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 314, __pyx_L1_error)
+ if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 314; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":320
* :rtype: 1D numpy array
@@ -3941,7 +3515,7 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_3MCA_12generator(__pyx_CoroutineOb
* yield self._scan._specfile.get_mca(self._scan.index, mca_index)
*
*/
- __pyx_t_1 = PyObject_Length(__pyx_cur_scope->__pyx_v_self); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 320, __pyx_L1_error)
+ __pyx_t_1 = PyObject_Length(__pyx_cur_scope->__pyx_v_self); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 320; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
__pyx_cur_scope->__pyx_v_mca_index = __pyx_t_2;
@@ -3952,24 +3526,24 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_3MCA_12generator(__pyx_CoroutineOb
*
*
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 321, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_specfile); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 321, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_specfile); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_get_mca); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 321, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_get_mca); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 321, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_cur_scope->__pyx_v_self, __pyx_n_s_scan_2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_index); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 321, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_index); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_5 = PyInt_FromSsize_t(__pyx_cur_scope->__pyx_v_mca_index); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 321, __pyx_L1_error)
+ __pyx_t_5 = PyInt_FromSsize_t(__pyx_cur_scope->__pyx_v_mca_index); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_7 = NULL;
__pyx_t_8 = 0;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_7 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_7)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -3979,42 +3553,20 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_3MCA_12generator(__pyx_CoroutineOb
__pyx_t_8 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_t_6, __pyx_t_5};
- __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 321, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_t_6, __pyx_t_5};
- __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 321, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 321, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_9);
- if (__pyx_t_7) {
- __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL;
- }
- __Pyx_GIVEREF(__pyx_t_6);
- PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_t_6);
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_t_5);
- __pyx_t_6 = 0;
- __pyx_t_5 = 0;
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 321, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+ __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_9);
+ if (__pyx_t_7) {
+ PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __Pyx_GIVEREF(__pyx_t_7); __pyx_t_7 = NULL;
}
+ PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_t_6);
+ __Pyx_GIVEREF(__pyx_t_6);
+ PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_6 = 0;
+ __pyx_t_5 = 0;
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_9, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_3);
+ __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__pyx_r = __pyx_t_3;
__pyx_t_3 = 0;
@@ -4028,9 +3580,8 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_3MCA_12generator(__pyx_CoroutineOb
__pyx_L6_resume_from_yield:;
__pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
__pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
- if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 321, __pyx_L1_error)
+ if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 321; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope);
/* "silx/io/specfile.pyx":314
* mca_index)
@@ -4052,11 +3603,11 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_3MCA_12generator(__pyx_CoroutineOb
__Pyx_XDECREF(__pyx_t_9);
__Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
__pyx_L0:;
- __Pyx_XDECREF(__pyx_r); __pyx_r = 0;
+ __Pyx_XDECREF(__pyx_r);
__pyx_generator->resume_label = -1;
- __Pyx_Coroutine_clear((PyObject*)__pyx_generator);
+ __Pyx_Generator_clear((PyObject*)__pyx_generator);
__Pyx_RefNannyFinishContext();
- return __pyx_r;
+ return NULL;
}
/* "silx/io/specfile.pyx":324
@@ -4075,6 +3626,9 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_1_add_or_concatenate(PyObject *__p
PyObject *__pyx_v_dictionary = 0;
PyObject *__pyx_v_key = 0;
PyObject *__pyx_v_value = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("_add_or_concatenate (wrapper)", 0);
@@ -4099,16 +3653,16 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_1_add_or_concatenate(PyObject *__p
case 1:
if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_key)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("_add_or_concatenate", 1, 3, 3, 1); __PYX_ERR(0, 324, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("_add_or_concatenate", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 324; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
case 2:
if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_value)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("_add_or_concatenate", 1, 3, 3, 2); __PYX_ERR(0, 324, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("_add_or_concatenate", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 324; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_add_or_concatenate") < 0)) __PYX_ERR(0, 324, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "_add_or_concatenate") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 324; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 3) {
goto __pyx_L5_argtuple_error;
@@ -4123,7 +3677,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_1_add_or_concatenate(PyObject *__p
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("_add_or_concatenate", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 324, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("_add_or_concatenate", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 324; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile._add_or_concatenate", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
@@ -4149,6 +3703,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile__add_or_concatenate(CYTHON_UNUSED
PyObject *__pyx_t_8 = NULL;
PyObject *__pyx_t_9 = NULL;
int __pyx_t_10;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("_add_or_concatenate", 0);
/* "silx/io/specfile.pyx":328
@@ -4159,8 +3716,6 @@ static PyObject *__pyx_pf_4silx_2io_8specfile__add_or_concatenate(CYTHON_UNUSED
* dictionary[key] = value
*/
{
- __Pyx_PyThreadState_declare
- __Pyx_PyThreadState_assign
__Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3);
__Pyx_XGOTREF(__pyx_t_1);
__Pyx_XGOTREF(__pyx_t_2);
@@ -4174,7 +3729,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile__add_or_concatenate(CYTHON_UNUSED
* dictionary[key] = value
* else:
*/
- __pyx_t_4 = (__Pyx_PySequence_ContainsTF(__pyx_v_key, __pyx_v_dictionary, Py_NE)); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 329, __pyx_L3_error)
+ __pyx_t_4 = (__Pyx_PySequence_Contains(__pyx_v_key, __pyx_v_dictionary, Py_NE)); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 329; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_t_5 = (__pyx_t_4 != 0);
if (__pyx_t_5) {
@@ -4185,56 +3740,39 @@ static PyObject *__pyx_pf_4silx_2io_8specfile__add_or_concatenate(CYTHON_UNUSED
* else:
* dictionary[key] += "\n" + value
*/
- if (unlikely(PyObject_SetItem(__pyx_v_dictionary, __pyx_v_key, __pyx_v_value) < 0)) __PYX_ERR(0, 330, __pyx_L3_error)
-
- /* "silx/io/specfile.pyx":329
- * """
- * try:
- * if key not in dictionary: # <<<<<<<<<<<<<<
- * dictionary[key] = value
- * else:
- */
+ if (unlikely(PyObject_SetItem(__pyx_v_dictionary, __pyx_v_key, __pyx_v_value) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 330; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
goto __pyx_L11;
}
+ /*else*/ {
- /* "silx/io/specfile.pyx":332
+ /* "silx/io/specfile.pyx":332
* dictionary[key] = value
* else:
* dictionary[key] += "\n" + value # <<<<<<<<<<<<<<
* except TypeError:
* raise TypeError("Parameter value must be a string.")
*/
- /*else*/ {
__Pyx_INCREF(__pyx_v_key);
__pyx_t_6 = __pyx_v_key;
- __pyx_t_7 = PyObject_GetItem(__pyx_v_dictionary, __pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 332, __pyx_L3_error)
+ __pyx_t_7 = PyObject_GetItem(__pyx_v_dictionary, __pyx_t_6); if (unlikely(__pyx_t_7 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 332; __pyx_clineno = __LINE__; goto __pyx_L3_error;};
__Pyx_GOTREF(__pyx_t_7);
- __pyx_t_8 = PyNumber_Add(__pyx_kp_s_, __pyx_v_value); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 332, __pyx_L3_error)
+ __pyx_t_8 = PyNumber_Add(__pyx_kp_s_, __pyx_v_value); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 332; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__Pyx_GOTREF(__pyx_t_8);
- __pyx_t_9 = PyNumber_InPlaceAdd(__pyx_t_7, __pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 332, __pyx_L3_error)
+ __pyx_t_9 = PyNumber_InPlaceAdd(__pyx_t_7, __pyx_t_8); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 332; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__Pyx_GOTREF(__pyx_t_9);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- if (unlikely(PyObject_SetItem(__pyx_v_dictionary, __pyx_t_6, __pyx_t_9) < 0)) __PYX_ERR(0, 332, __pyx_L3_error)
+ if (unlikely(PyObject_SetItem(__pyx_v_dictionary, __pyx_t_6, __pyx_t_9) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 332; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
}
__pyx_L11:;
-
- /* "silx/io/specfile.pyx":328
- * Else append/concatenate the new value to the existing one
- * """
- * try: # <<<<<<<<<<<<<<
- * if key not in dictionary:
- * dictionary[key] = value
- */
}
__Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
goto __pyx_L10_try_end;
__pyx_L3_error:;
- __Pyx_PyThreadState_assign
__Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
__Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
__Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
@@ -4247,10 +3785,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile__add_or_concatenate(CYTHON_UNUSED
* raise TypeError("Parameter value must be a string.")
*
*/
- __pyx_t_10 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_TypeError);
+ __pyx_t_10 = PyErr_ExceptionMatches(__pyx_builtin_TypeError);
if (__pyx_t_10) {
__Pyx_AddTraceback("silx.io.specfile._add_or_concatenate", __pyx_clineno, __pyx_lineno, __pyx_filename);
- if (__Pyx_GetException(&__pyx_t_6, &__pyx_t_9, &__pyx_t_8) < 0) __PYX_ERR(0, 333, __pyx_L5_except_error)
+ if (__Pyx_GetException(&__pyx_t_6, &__pyx_t_9, &__pyx_t_8) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 333; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
__Pyx_GOTREF(__pyx_t_6);
__Pyx_GOTREF(__pyx_t_9);
__Pyx_GOTREF(__pyx_t_8);
@@ -4262,23 +3800,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile__add_or_concatenate(CYTHON_UNUSED
*
*
*/
- __pyx_t_7 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 334, __pyx_L5_except_error)
+ __pyx_t_7 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__5, NULL); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 334; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
__Pyx_GOTREF(__pyx_t_7);
__Pyx_Raise(__pyx_t_7, 0, 0, 0);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- __PYX_ERR(0, 334, __pyx_L5_except_error)
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 334; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
}
goto __pyx_L5_except_error;
__pyx_L5_except_error:;
-
- /* "silx/io/specfile.pyx":328
- * Else append/concatenate the new value to the existing one
- * """
- * try: # <<<<<<<<<<<<<<
- * if key not in dictionary:
- * dictionary[key] = value
- */
- __Pyx_PyThreadState_assign
__Pyx_XGIVEREF(__pyx_t_1);
__Pyx_XGIVEREF(__pyx_t_2);
__Pyx_XGIVEREF(__pyx_t_3);
@@ -4327,6 +3856,9 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_1__init__(PyObject *__pyx_se
PyObject *__pyx_v_self = 0;
PyObject *__pyx_v_specfile = 0;
PyObject *__pyx_v_scan_index = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("__init__ (wrapper)", 0);
@@ -4351,16 +3883,16 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_1__init__(PyObject *__pyx_se
case 1:
if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_specfile_2)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 1); __PYX_ERR(0, 362, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 362; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
case 2:
if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_scan_index)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 2); __PYX_ERR(0, 362, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 362; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 362, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 362; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 3) {
goto __pyx_L5_argtuple_error;
@@ -4375,7 +3907,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_1__init__(PyObject *__pyx_se
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 362, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 362; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.Scan.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
@@ -4405,13 +3937,17 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
int __pyx_t_6;
Py_ssize_t __pyx_t_7;
PyObject *(*__pyx_t_8)(PyObject *);
- int __pyx_t_9;
+ Py_ssize_t __pyx_t_9;
PyObject *__pyx_t_10 = NULL;
PyObject *__pyx_t_11 = NULL;
PyObject *__pyx_t_12 = NULL;
PyObject *__pyx_t_13 = NULL;
- PyObject *__pyx_t_14 = NULL;
+ int __pyx_t_14;
PyObject *__pyx_t_15 = NULL;
+ PyObject *__pyx_t_16 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__init__", 0);
/* "silx/io/specfile.pyx":363
@@ -4421,7 +3957,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
*
* self._index = scan_index
*/
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_specfile, __pyx_v_specfile) < 0) __PYX_ERR(0, 363, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_specfile, __pyx_v_specfile) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 363; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":365
* self._specfile = specfile
@@ -4430,7 +3966,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* self._number = specfile.number(scan_index)
* self._order = specfile.order(scan_index)
*/
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_index_2, __pyx_v_scan_index) < 0) __PYX_ERR(0, 365, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_index_2, __pyx_v_scan_index) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 365; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":366
*
@@ -4439,10 +3975,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* self._order = specfile.order(scan_index)
*
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_specfile, __pyx_n_s_number); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 366, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_specfile, __pyx_n_s_number); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 366; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_3 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -4452,39 +3988,21 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (!__pyx_t_3) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_scan_index); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 366, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_scan_index); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 366; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_scan_index};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 366, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_scan_index};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 366, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 366, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL;
- __Pyx_INCREF(__pyx_v_scan_index);
- __Pyx_GIVEREF(__pyx_v_scan_index);
- PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_scan_index);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 366, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- }
+ __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 366; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __Pyx_GIVEREF(__pyx_t_3); __pyx_t_3 = NULL;
+ __Pyx_INCREF(__pyx_v_scan_index);
+ PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_scan_index);
+ __Pyx_GIVEREF(__pyx_v_scan_index);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 366; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_number_2, __pyx_t_1) < 0) __PYX_ERR(0, 366, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_number_2, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 366; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":367
@@ -4494,10 +4012,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
*
* self._scan_header_lines = self._specfile.scan_header(self._index)
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_specfile, __pyx_n_s_order); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 367, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_specfile, __pyx_n_s_order); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 367; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -4507,39 +4025,21 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (!__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_scan_index); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 367, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_scan_index); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 367; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_v_scan_index};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 367, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_v_scan_index};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 367, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 367, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_4); __pyx_t_4 = NULL;
- __Pyx_INCREF(__pyx_v_scan_index);
- __Pyx_GIVEREF(__pyx_v_scan_index);
- PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_v_scan_index);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_3, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 367, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- }
+ __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 367; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_3);
+ PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
+ __Pyx_INCREF(__pyx_v_scan_index);
+ PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_v_scan_index);
+ __Pyx_GIVEREF(__pyx_v_scan_index);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_3, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 367; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_order_2, __pyx_t_1) < 0) __PYX_ERR(0, 367, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_order_2, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 367; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":369
@@ -4549,15 +4049,15 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* self._file_header_lines = self._specfile.file_header(self._index)
*
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 369, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_scan_header); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 369, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_scan_header); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 369, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -4567,42 +4067,22 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (!__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 369, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_2};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 369, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_2};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 369, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- } else
- #endif
- {
- __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 369, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __pyx_t_4 = NULL;
- __Pyx_GIVEREF(__pyx_t_2);
- PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_t_2);
- __pyx_t_2 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 369, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- }
+ __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_5);
+ PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
+ __pyx_t_2 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_lines, __pyx_t_1) < 0) __PYX_ERR(0, 369, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_lines, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 369; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":370
@@ -4612,15 +4092,15 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
*
* if self._file_header_lines == self._scan_header_lines:
*/
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 370, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 370; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_file_header); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 370, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_file_header); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 370; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 370, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 370; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__pyx_t_2 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_5))) {
__pyx_t_2 = PyMethod_GET_SELF(__pyx_t_5);
if (likely(__pyx_t_2)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
@@ -4630,42 +4110,22 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (!__pyx_t_2) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 370, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 370; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_3};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 370, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_3};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 370, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- } else
- #endif
- {
- __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 370, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __pyx_t_2 = NULL;
- __Pyx_GIVEREF(__pyx_t_3);
- PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_3);
- __pyx_t_3 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 370, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- }
+ __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 370; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); __pyx_t_2 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_3);
+ __Pyx_GIVEREF(__pyx_t_3);
+ __pyx_t_3 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 370; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines, __pyx_t_1) < 0) __PYX_ERR(0, 370, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 370; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":372
@@ -4675,14 +4135,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* self._file_header_lines = []
* self._header = self._file_header_lines + self._scan_header_lines
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 372, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_lines); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 372, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_lines); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_4 = PyObject_RichCompare(__pyx_t_1, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 372, __pyx_L1_error)
+ __pyx_t_4 = PyObject_RichCompare(__pyx_t_1, __pyx_t_5, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 372, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 372; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (__pyx_t_6) {
@@ -4693,19 +4153,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* self._header = self._file_header_lines + self._scan_header_lines
*
*/
- __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 373, __pyx_L1_error)
+ __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 373; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines, __pyx_t_4) < 0) __PYX_ERR(0, 373, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 373; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-
- /* "silx/io/specfile.pyx":372
- * self._file_header_lines = self._specfile.file_header(self._index)
- *
- * if self._file_header_lines == self._scan_header_lines: # <<<<<<<<<<<<<<
- * self._file_header_lines = []
- * self._header = self._file_header_lines + self._scan_header_lines
- */
+ goto __pyx_L3;
}
+ __pyx_L3:;
/* "silx/io/specfile.pyx":374
* if self._file_header_lines == self._scan_header_lines:
@@ -4714,15 +4168,15 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
*
* self._scan_header_dict = {}
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 374, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 374; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_lines); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 374, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_lines); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 374; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_1 = PyNumber_Add(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 374, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 374; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_header, __pyx_t_1) < 0) __PYX_ERR(0, 374, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_header, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 374; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":376
@@ -4732,9 +4186,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* self._mca_header_dict = {}
* for line in self._scan_header_lines:
*/
- __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 376, __pyx_L1_error)
+ __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 376; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_dict, __pyx_t_1) < 0) __PYX_ERR(0, 376, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_dict, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 376; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":377
@@ -4744,9 +4198,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* for line in self._scan_header_lines:
* match = re.search(r"#(\w+) *(.*)", line)
*/
- __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 377, __pyx_L1_error)
+ __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 377; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_mca_header_dict_2, __pyx_t_1) < 0) __PYX_ERR(0, 377, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_mca_header_dict_2, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 377; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":378
@@ -4756,34 +4210,32 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* match = re.search(r"#(\w+) *(.*)", line)
* match_mca = re.search(r"#@(\w+) *(.*)", line)
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_lines); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 378, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_lines); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) {
__pyx_t_5 = __pyx_t_1; __Pyx_INCREF(__pyx_t_5); __pyx_t_7 = 0;
__pyx_t_8 = NULL;
} else {
- __pyx_t_7 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 378, __pyx_L1_error)
+ __pyx_t_7 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_8 = Py_TYPE(__pyx_t_5)->tp_iternext; if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 378, __pyx_L1_error)
+ __pyx_t_8 = Py_TYPE(__pyx_t_5)->tp_iternext; if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
for (;;) {
if (likely(!__pyx_t_8)) {
if (likely(PyList_CheckExact(__pyx_t_5))) {
if (__pyx_t_7 >= PyList_GET_SIZE(__pyx_t_5)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_1 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_7); __Pyx_INCREF(__pyx_t_1); __pyx_t_7++; if (unlikely(0 < 0)) __PYX_ERR(0, 378, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_1 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_7); __Pyx_INCREF(__pyx_t_1); __pyx_t_7++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_1 = PySequence_ITEM(__pyx_t_5, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 378, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
+ __pyx_t_1 = PySequence_ITEM(__pyx_t_5, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
} else {
if (__pyx_t_7 >= PyTuple_GET_SIZE(__pyx_t_5)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_7); __Pyx_INCREF(__pyx_t_1); __pyx_t_7++; if (unlikely(0 < 0)) __PYX_ERR(0, 378, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_7); __Pyx_INCREF(__pyx_t_1); __pyx_t_7++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_1 = PySequence_ITEM(__pyx_t_5, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 378, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
+ __pyx_t_1 = PySequence_ITEM(__pyx_t_5, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
}
} else {
@@ -4792,7 +4244,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
PyObject* exc_type = PyErr_Occurred();
if (exc_type) {
if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
- else __PYX_ERR(0, 378, __pyx_L1_error)
+ else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 378; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
break;
}
@@ -4808,14 +4260,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* match_mca = re.search(r"#@(\w+) *(.*)", line)
* if match:
*/
- __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_re); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 379, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_re); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 379; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_search); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 379, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_search); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 379; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__pyx_t_4 = NULL;
__pyx_t_9 = 0;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -4825,38 +4277,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
__pyx_t_9 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[3] = {__pyx_t_4, __pyx_kp_s_w, __pyx_v_line};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 379, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[3] = {__pyx_t_4, __pyx_kp_s_w, __pyx_v_line};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 379, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_2 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 379, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- if (__pyx_t_4) {
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_4); __pyx_t_4 = NULL;
- }
- __Pyx_INCREF(__pyx_kp_s_w);
- __Pyx_GIVEREF(__pyx_kp_s_w);
- PyTuple_SET_ITEM(__pyx_t_2, 0+__pyx_t_9, __pyx_kp_s_w);
- __Pyx_INCREF(__pyx_v_line);
- __Pyx_GIVEREF(__pyx_v_line);
- PyTuple_SET_ITEM(__pyx_t_2, 1+__pyx_t_9, __pyx_v_line);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 379, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- }
+ __pyx_t_2 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 379; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ if (__pyx_t_4) {
+ PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
+ }
+ __Pyx_INCREF(__pyx_kp_s_w);
+ PyTuple_SET_ITEM(__pyx_t_2, 0+__pyx_t_9, __pyx_kp_s_w);
+ __Pyx_GIVEREF(__pyx_kp_s_w);
+ __Pyx_INCREF(__pyx_v_line);
+ PyTuple_SET_ITEM(__pyx_t_2, 1+__pyx_t_9, __pyx_v_line);
+ __Pyx_GIVEREF(__pyx_v_line);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 379; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_XDECREF_SET(__pyx_v_match, __pyx_t_1);
__pyx_t_1 = 0;
@@ -4868,14 +4302,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* if match:
* hkey = match.group(1).lstrip("#").strip()
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_re); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 380, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_re); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 380; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_search); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 380, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_search); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 380; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_3 = NULL;
__pyx_t_9 = 0;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -4885,38 +4319,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
__pyx_t_9 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[3] = {__pyx_t_3, __pyx_kp_s_w_2, __pyx_v_line};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 380, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[3] = {__pyx_t_3, __pyx_kp_s_w_2, __pyx_v_line};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 380, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_4 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 380, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- if (__pyx_t_3) {
- __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL;
- }
- __Pyx_INCREF(__pyx_kp_s_w_2);
- __Pyx_GIVEREF(__pyx_kp_s_w_2);
- PyTuple_SET_ITEM(__pyx_t_4, 0+__pyx_t_9, __pyx_kp_s_w_2);
- __Pyx_INCREF(__pyx_v_line);
- __Pyx_GIVEREF(__pyx_v_line);
- PyTuple_SET_ITEM(__pyx_t_4, 1+__pyx_t_9, __pyx_v_line);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 380, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- }
+ __pyx_t_4 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 380; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ if (__pyx_t_3) {
+ PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __Pyx_GIVEREF(__pyx_t_3); __pyx_t_3 = NULL;
+ }
+ __Pyx_INCREF(__pyx_kp_s_w_2);
+ PyTuple_SET_ITEM(__pyx_t_4, 0+__pyx_t_9, __pyx_kp_s_w_2);
+ __Pyx_GIVEREF(__pyx_kp_s_w_2);
+ __Pyx_INCREF(__pyx_v_line);
+ PyTuple_SET_ITEM(__pyx_t_4, 1+__pyx_t_9, __pyx_v_line);
+ __Pyx_GIVEREF(__pyx_v_line);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 380; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_XDECREF_SET(__pyx_v_match_mca, __pyx_t_1);
__pyx_t_1 = 0;
@@ -4928,7 +4344,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* hkey = match.group(1).lstrip("#").strip()
* hvalue = match.group(2).strip()
*/
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_v_match); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 381, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_v_match); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 381; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
if (__pyx_t_6) {
/* "silx/io/specfile.pyx":382
@@ -4938,22 +4354,22 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* hvalue = match.group(2).strip()
* _add_or_concatenate(self._scan_header_dict, hkey, hvalue)
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_match, __pyx_n_s_group); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 382, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_match, __pyx_n_s_group); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 382; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 382, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__6, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 382; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_lstrip); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 382, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_lstrip); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 382; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 382, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__8, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 382; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_strip); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 382, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_strip); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 382; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -4963,10 +4379,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 382, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 382; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
} else {
- __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 382, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 382; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -4980,16 +4396,16 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* _add_or_concatenate(self._scan_header_dict, hkey, hvalue)
* elif match_mca:
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_match, __pyx_n_s_group); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 383, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_match, __pyx_n_s_group); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 383; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 383, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 383; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_strip); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 383, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_strip); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 383; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -4999,10 +4415,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 383, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 383; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
} else {
- __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 383, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 383; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -5016,13 +4432,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* elif match_mca:
* hkey = match_mca.group(1).lstrip("#").strip()
*/
- __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_add_or_concatenate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 384, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_add_or_concatenate); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 384; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_dict); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 384, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_dict); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 384; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__pyx_t_3 = NULL;
__pyx_t_9 = 0;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -5032,53 +4448,25 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
__pyx_t_9 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[4] = {__pyx_t_3, __pyx_t_4, __pyx_v_hkey, __pyx_v_hvalue};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_9, 3+__pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 384, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[4] = {__pyx_t_3, __pyx_t_4, __pyx_v_hkey, __pyx_v_hvalue};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_9, 3+__pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 384, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- } else
- #endif
- {
- __pyx_t_10 = PyTuple_New(3+__pyx_t_9); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 384, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_10);
- if (__pyx_t_3) {
- __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_3); __pyx_t_3 = NULL;
- }
- __Pyx_GIVEREF(__pyx_t_4);
- PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_9, __pyx_t_4);
- __Pyx_INCREF(__pyx_v_hkey);
- __Pyx_GIVEREF(__pyx_v_hkey);
- PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_9, __pyx_v_hkey);
- __Pyx_INCREF(__pyx_v_hvalue);
- __Pyx_GIVEREF(__pyx_v_hvalue);
- PyTuple_SET_ITEM(__pyx_t_10, 2+__pyx_t_9, __pyx_v_hvalue);
- __pyx_t_4 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_10, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 384, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+ __pyx_t_10 = PyTuple_New(3+__pyx_t_9); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 384; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_10);
+ if (__pyx_t_3) {
+ PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_3); __Pyx_GIVEREF(__pyx_t_3); __pyx_t_3 = NULL;
}
+ PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_9, __pyx_t_4);
+ __Pyx_GIVEREF(__pyx_t_4);
+ __Pyx_INCREF(__pyx_v_hkey);
+ PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_9, __pyx_v_hkey);
+ __Pyx_GIVEREF(__pyx_v_hkey);
+ __Pyx_INCREF(__pyx_v_hvalue);
+ PyTuple_SET_ITEM(__pyx_t_10, 2+__pyx_t_9, __pyx_v_hvalue);
+ __Pyx_GIVEREF(__pyx_v_hvalue);
+ __pyx_t_4 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_10, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 384; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-
- /* "silx/io/specfile.pyx":381
- * match = re.search(r"#(\w+) *(.*)", line)
- * match_mca = re.search(r"#@(\w+) *(.*)", line)
- * if match: # <<<<<<<<<<<<<<
- * hkey = match.group(1).lstrip("#").strip()
- * hvalue = match.group(2).strip()
- */
goto __pyx_L6;
}
@@ -5089,7 +4477,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* hkey = match_mca.group(1).lstrip("#").strip()
* hvalue = match_mca.group(2).strip()
*/
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_v_match_mca); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 385, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_v_match_mca); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 385; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
if (__pyx_t_6) {
/* "silx/io/specfile.pyx":386
@@ -5099,22 +4487,22 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* hvalue = match_mca.group(2).strip()
* _add_or_concatenate(self._mca_header_dict, hkey, hvalue)
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_match_mca, __pyx_n_s_group); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 386, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_match_mca, __pyx_n_s_group); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 386; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 386, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__10, NULL); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 386; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_lstrip); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 386, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_lstrip); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 386; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__11, NULL); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 386, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__11, NULL); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 386; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_strip); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 386, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_strip); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 386; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__pyx_t_10 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_10 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_10)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -5124,10 +4512,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (__pyx_t_10) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_10); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 386, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_10); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 386; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
} else {
- __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 386, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 386; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -5141,16 +4529,16 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* _add_or_concatenate(self._mca_header_dict, hkey, hvalue)
* else:
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_match_mca, __pyx_n_s_group); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 387, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_match_mca, __pyx_n_s_group); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 387; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__12, NULL); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 387, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__12, NULL); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 387; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_strip); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 387, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_strip); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 387; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__pyx_t_10 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_10 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_10)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -5160,10 +4548,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (__pyx_t_10) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_10); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 387, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_10); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 387; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
} else {
- __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 387, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 387; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -5177,13 +4565,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* else:
* # this shouldn't happen
*/
- __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_add_or_concatenate); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 388, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_add_or_concatenate); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 388; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_mca_header_dict_2); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 388, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_mca_header_dict_2); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 388; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
__pyx_t_4 = NULL;
__pyx_t_9 = 0;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -5193,73 +4581,45 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
__pyx_t_9 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[4] = {__pyx_t_4, __pyx_t_10, __pyx_v_hkey, __pyx_v_hvalue};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_9, 3+__pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 388, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[4] = {__pyx_t_4, __pyx_t_10, __pyx_v_hkey, __pyx_v_hvalue};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-__pyx_t_9, 3+__pyx_t_9); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 388, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- } else
- #endif
- {
- __pyx_t_3 = PyTuple_New(3+__pyx_t_9); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 388, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- if (__pyx_t_4) {
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_4); __pyx_t_4 = NULL;
- }
- __Pyx_GIVEREF(__pyx_t_10);
- PyTuple_SET_ITEM(__pyx_t_3, 0+__pyx_t_9, __pyx_t_10);
- __Pyx_INCREF(__pyx_v_hkey);
- __Pyx_GIVEREF(__pyx_v_hkey);
- PyTuple_SET_ITEM(__pyx_t_3, 1+__pyx_t_9, __pyx_v_hkey);
- __Pyx_INCREF(__pyx_v_hvalue);
- __Pyx_GIVEREF(__pyx_v_hvalue);
- PyTuple_SET_ITEM(__pyx_t_3, 2+__pyx_t_9, __pyx_v_hvalue);
- __pyx_t_10 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_3, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 388, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+ __pyx_t_3 = PyTuple_New(3+__pyx_t_9); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 388; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_3);
+ if (__pyx_t_4) {
+ PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
}
+ PyTuple_SET_ITEM(__pyx_t_3, 0+__pyx_t_9, __pyx_t_10);
+ __Pyx_GIVEREF(__pyx_t_10);
+ __Pyx_INCREF(__pyx_v_hkey);
+ PyTuple_SET_ITEM(__pyx_t_3, 1+__pyx_t_9, __pyx_v_hkey);
+ __Pyx_GIVEREF(__pyx_v_hkey);
+ __Pyx_INCREF(__pyx_v_hvalue);
+ PyTuple_SET_ITEM(__pyx_t_3, 2+__pyx_t_9, __pyx_v_hvalue);
+ __Pyx_GIVEREF(__pyx_v_hvalue);
+ __pyx_t_10 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_3, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 388; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-
- /* "silx/io/specfile.pyx":385
- * hvalue = match.group(2).strip()
- * _add_or_concatenate(self._scan_header_dict, hkey, hvalue)
- * elif match_mca: # <<<<<<<<<<<<<<
- * hkey = match_mca.group(1).lstrip("#").strip()
- * hvalue = match_mca.group(2).strip()
- */
goto __pyx_L6;
}
+ /*else*/ {
- /* "silx/io/specfile.pyx":391
+ /* "silx/io/specfile.pyx":391
* else:
* # this shouldn't happen
* _logger.warning("Unable to parse scan header line " + line) # <<<<<<<<<<<<<<
*
* self._labels = []
*/
- /*else*/ {
- __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_logger); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 391, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_logger); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 391; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_warning); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 391, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_warning); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 391; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = PyNumber_Add(__pyx_kp_s_Unable_to_parse_scan_header_line, __pyx_v_line); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 391, __pyx_L1_error)
+ __pyx_t_2 = PyNumber_Add(__pyx_kp_s_Unable_to_parse_scan_header_line, __pyx_v_line); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 391; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_10 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_10 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_10)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -5269,39 +4629,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (!__pyx_t_10) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 391, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 391; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_10, __pyx_t_2};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 391, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_10, __pyx_t_2};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 391, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- } else
- #endif
- {
- __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 391, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_10); __pyx_t_10 = NULL;
- __Pyx_GIVEREF(__pyx_t_2);
- PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_2);
- __pyx_t_2 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 391, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- }
+ __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 391; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_10); __Pyx_GIVEREF(__pyx_t_10); __pyx_t_10 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
+ __pyx_t_2 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 391; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -5325,9 +4665,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* if self.record_exists_in_hdr('L'):
* try:
*/
- __pyx_t_5 = PyList_New(0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 393, __pyx_L1_error)
+ __pyx_t_5 = PyList_New(0); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 393; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_labels, __pyx_t_5) < 0) __PYX_ERR(0, 393, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_labels, __pyx_t_5) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 393; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
/* "silx/io/specfile.pyx":394
@@ -5337,12 +4677,12 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* try:
* self._labels = self._specfile.labels(self._index)
*/
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_record_exists_in_hdr); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 394, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_record_exists_in_hdr); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 394; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_tuple__13, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 394, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_tuple__13, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 394; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 394, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 394; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
if (__pyx_t_6) {
@@ -5354,8 +4694,6 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* except SfErrLineNotFound:
*/
{
- __Pyx_PyThreadState_declare
- __Pyx_PyThreadState_assign
__Pyx_ExceptionSave(&__pyx_t_11, &__pyx_t_12, &__pyx_t_13);
__Pyx_XGOTREF(__pyx_t_11);
__Pyx_XGOTREF(__pyx_t_12);
@@ -5369,15 +4707,15 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* except SfErrLineNotFound:
* # SpecFile.labels raises an IndexError when encountering
*/
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 396, __pyx_L8_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 396; __pyx_clineno = __LINE__; goto __pyx_L8_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_labels_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 396, __pyx_L8_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_labels_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 396; __pyx_clineno = __LINE__; goto __pyx_L8_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 396, __pyx_L8_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 396; __pyx_clineno = __LINE__; goto __pyx_L8_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -5387,58 +4725,29 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (!__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 396, __pyx_L8_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 396; __pyx_clineno = __LINE__; goto __pyx_L8_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 396, __pyx_L8_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 396, __pyx_L8_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_2 = PyTuple_New(1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 396, __pyx_L8_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_4); __pyx_t_4 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_2, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 396, __pyx_L8_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- }
+ __pyx_t_2 = PyTuple_New(1+1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 396; __pyx_clineno = __LINE__; goto __pyx_L8_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_2, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_2, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 396; __pyx_clineno = __LINE__; goto __pyx_L8_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_labels, __pyx_t_1) < 0) __PYX_ERR(0, 396, __pyx_L8_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_labels, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 396; __pyx_clineno = __LINE__; goto __pyx_L8_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-
- /* "silx/io/specfile.pyx":395
- * self._labels = []
- * if self.record_exists_in_hdr('L'):
- * try: # <<<<<<<<<<<<<<
- * self._labels = self._specfile.labels(self._index)
- * except SfErrLineNotFound:
- */
}
__Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0;
__Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0;
__Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0;
goto __pyx_L15_try_end;
__pyx_L8_error:;
- __Pyx_PyThreadState_assign
__Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
__Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
@@ -5453,13 +4762,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* # SpecFile.labels raises an IndexError when encountering
* # a Scan with no data, even if the header exists.
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrLineNotFound); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 397, __pyx_L10_except_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrLineNotFound); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 397; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_9 = __Pyx_PyErr_ExceptionMatches(__pyx_t_1);
+ __pyx_t_14 = PyErr_ExceptionMatches(__pyx_t_1);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- if (__pyx_t_9) {
+ if (__pyx_t_14) {
__Pyx_AddTraceback("silx.io.specfile.Scan.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- if (__Pyx_GetException(&__pyx_t_1, &__pyx_t_3, &__pyx_t_2) < 0) __PYX_ERR(0, 397, __pyx_L10_except_error)
+ if (__Pyx_GetException(&__pyx_t_1, &__pyx_t_3, &__pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 397; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_GOTREF(__pyx_t_3);
__Pyx_GOTREF(__pyx_t_2);
@@ -5471,9 +4780,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* self._scan_header_dict["L"])
* self._labels = L_header.split(" ")
*/
- __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_re); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 400, __pyx_L10_except_error)
+ __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_re); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_sub); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 400, __pyx_L10_except_error)
+ __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_sub); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
@@ -5484,60 +4793,40 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* self._labels = L_header.split(" ")
*
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_dict); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 401, __pyx_L10_except_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_dict); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 401; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_14 = PyObject_GetItem(__pyx_t_4, __pyx_n_s_L); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 401, __pyx_L10_except_error)
- __Pyx_GOTREF(__pyx_t_14);
+ __pyx_t_15 = PyObject_GetItem(__pyx_t_4, __pyx_n_s_L); if (unlikely(__pyx_t_15 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 401; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;};
+ __Pyx_GOTREF(__pyx_t_15);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__pyx_t_4 = NULL;
- __pyx_t_9 = 0;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_10))) {
+ __pyx_t_7 = 0;
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_10))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_10);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10);
__Pyx_INCREF(__pyx_t_4);
__Pyx_INCREF(function);
__Pyx_DECREF_SET(__pyx_t_10, function);
- __pyx_t_9 = 1;
+ __pyx_t_7 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_10)) {
- PyObject *__pyx_temp[4] = {__pyx_t_4, __pyx_kp_s_2, __pyx_kp_s__14, __pyx_t_14};
- __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_9, 3+__pyx_t_9); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 400, __pyx_L10_except_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_10)) {
- PyObject *__pyx_temp[4] = {__pyx_t_4, __pyx_kp_s_2, __pyx_kp_s__14, __pyx_t_14};
- __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_9, 3+__pyx_t_9); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 400, __pyx_L10_except_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
- } else
- #endif
- {
- __pyx_t_15 = PyTuple_New(3+__pyx_t_9); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 400, __pyx_L10_except_error)
- __Pyx_GOTREF(__pyx_t_15);
- if (__pyx_t_4) {
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_15, 0, __pyx_t_4); __pyx_t_4 = NULL;
- }
- __Pyx_INCREF(__pyx_kp_s_2);
- __Pyx_GIVEREF(__pyx_kp_s_2);
- PyTuple_SET_ITEM(__pyx_t_15, 0+__pyx_t_9, __pyx_kp_s_2);
- __Pyx_INCREF(__pyx_kp_s__14);
- __Pyx_GIVEREF(__pyx_kp_s__14);
- PyTuple_SET_ITEM(__pyx_t_15, 1+__pyx_t_9, __pyx_kp_s__14);
- __Pyx_GIVEREF(__pyx_t_14);
- PyTuple_SET_ITEM(__pyx_t_15, 2+__pyx_t_9, __pyx_t_14);
- __pyx_t_14 = 0;
- __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_15, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 400, __pyx_L10_except_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
+ __pyx_t_16 = PyTuple_New(3+__pyx_t_7); if (unlikely(!__pyx_t_16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
+ __Pyx_GOTREF(__pyx_t_16);
+ if (__pyx_t_4) {
+ PyTuple_SET_ITEM(__pyx_t_16, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
}
+ __Pyx_INCREF(__pyx_kp_s_2);
+ PyTuple_SET_ITEM(__pyx_t_16, 0+__pyx_t_7, __pyx_kp_s_2);
+ __Pyx_GIVEREF(__pyx_kp_s_2);
+ __Pyx_INCREF(__pyx_kp_s__14);
+ PyTuple_SET_ITEM(__pyx_t_16, 1+__pyx_t_7, __pyx_kp_s__14);
+ __Pyx_GIVEREF(__pyx_kp_s__14);
+ PyTuple_SET_ITEM(__pyx_t_16, 2+__pyx_t_7, __pyx_t_15);
+ __Pyx_GIVEREF(__pyx_t_15);
+ __pyx_t_15 = 0;
+ __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_16, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 400; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
+ __Pyx_GOTREF(__pyx_t_5);
+ __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__pyx_v_L_header = __pyx_t_5;
__pyx_t_5 = 0;
@@ -5549,12 +4838,12 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
*
* self._file_header_dict = {}
*/
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_L_header, __pyx_n_s_split); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 402, __pyx_L10_except_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_L_header, __pyx_n_s_split); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 402; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_tuple__15, NULL); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 402, __pyx_L10_except_error)
+ __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_tuple__15, NULL); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 402; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_labels, __pyx_t_10) < 0) __PYX_ERR(0, 402, __pyx_L10_except_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_labels, __pyx_t_10) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 402; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -5563,37 +4852,21 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
goto __pyx_L10_except_error;
__pyx_L10_except_error:;
-
- /* "silx/io/specfile.pyx":395
- * self._labels = []
- * if self.record_exists_in_hdr('L'):
- * try: # <<<<<<<<<<<<<<
- * self._labels = self._specfile.labels(self._index)
- * except SfErrLineNotFound:
- */
- __Pyx_PyThreadState_assign
__Pyx_XGIVEREF(__pyx_t_11);
__Pyx_XGIVEREF(__pyx_t_12);
__Pyx_XGIVEREF(__pyx_t_13);
__Pyx_ExceptionReset(__pyx_t_11, __pyx_t_12, __pyx_t_13);
goto __pyx_L1_error;
__pyx_L9_exception_handled:;
- __Pyx_PyThreadState_assign
__Pyx_XGIVEREF(__pyx_t_11);
__Pyx_XGIVEREF(__pyx_t_12);
__Pyx_XGIVEREF(__pyx_t_13);
__Pyx_ExceptionReset(__pyx_t_11, __pyx_t_12, __pyx_t_13);
__pyx_L15_try_end:;
}
-
- /* "silx/io/specfile.pyx":394
- *
- * self._labels = []
- * if self.record_exists_in_hdr('L'): # <<<<<<<<<<<<<<
- * try:
- * self._labels = self._specfile.labels(self._index)
- */
+ goto __pyx_L7;
}
+ __pyx_L7:;
/* "silx/io/specfile.pyx":404
* self._labels = L_header.split(" ")
@@ -5602,9 +4875,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* for line in self._file_header_lines:
* match = re.search(r"#(\w+) *(.*)", line)
*/
- __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 404, __pyx_L1_error)
+ __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 404; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_file_header_dict, __pyx_t_2) < 0) __PYX_ERR(0, 404, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_file_header_dict, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 404; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":405
@@ -5614,34 +4887,32 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* match = re.search(r"#(\w+) *(.*)", line)
* if match:
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 405, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 405; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) {
__pyx_t_3 = __pyx_t_2; __Pyx_INCREF(__pyx_t_3); __pyx_t_7 = 0;
__pyx_t_8 = NULL;
} else {
- __pyx_t_7 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 405, __pyx_L1_error)
+ __pyx_t_7 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 405; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_8 = Py_TYPE(__pyx_t_3)->tp_iternext; if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 405, __pyx_L1_error)
+ __pyx_t_8 = Py_TYPE(__pyx_t_3)->tp_iternext; if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 405; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
for (;;) {
if (likely(!__pyx_t_8)) {
if (likely(PyList_CheckExact(__pyx_t_3))) {
if (__pyx_t_7 >= PyList_GET_SIZE(__pyx_t_3)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_7); __Pyx_INCREF(__pyx_t_2); __pyx_t_7++; if (unlikely(0 < 0)) __PYX_ERR(0, 405, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_7); __Pyx_INCREF(__pyx_t_2); __pyx_t_7++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 405; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 405, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
+ __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 405; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
} else {
if (__pyx_t_7 >= PyTuple_GET_SIZE(__pyx_t_3)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_7); __Pyx_INCREF(__pyx_t_2); __pyx_t_7++; if (unlikely(0 < 0)) __PYX_ERR(0, 405, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_7); __Pyx_INCREF(__pyx_t_2); __pyx_t_7++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 405; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 405, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
+ __pyx_t_2 = PySequence_ITEM(__pyx_t_3, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 405; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
}
} else {
@@ -5650,7 +4921,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
PyObject* exc_type = PyErr_Occurred();
if (exc_type) {
if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
- else __PYX_ERR(0, 405, __pyx_L1_error)
+ else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 405; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
break;
}
@@ -5666,14 +4937,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* if match:
* # header type
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_re); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 406, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_re); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 406; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_search); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 406, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_search); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 406; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_1 = NULL;
__pyx_t_9 = 0;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_10))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_10))) {
__pyx_t_1 = PyMethod_GET_SELF(__pyx_t_10);
if (likely(__pyx_t_1)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10);
@@ -5683,38 +4954,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
__pyx_t_9 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_10)) {
- PyObject *__pyx_temp[3] = {__pyx_t_1, __pyx_kp_s_w, __pyx_v_line};
- __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 406, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_GOTREF(__pyx_t_2);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_10)) {
- PyObject *__pyx_temp[3] = {__pyx_t_1, __pyx_kp_s_w, __pyx_v_line};
- __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_9, 2+__pyx_t_9); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 406, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_GOTREF(__pyx_t_2);
- } else
- #endif
- {
- __pyx_t_5 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 406, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- if (__pyx_t_1) {
- __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1); __pyx_t_1 = NULL;
- }
- __Pyx_INCREF(__pyx_kp_s_w);
- __Pyx_GIVEREF(__pyx_kp_s_w);
- PyTuple_SET_ITEM(__pyx_t_5, 0+__pyx_t_9, __pyx_kp_s_w);
- __Pyx_INCREF(__pyx_v_line);
- __Pyx_GIVEREF(__pyx_v_line);
- PyTuple_SET_ITEM(__pyx_t_5, 1+__pyx_t_9, __pyx_v_line);
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_5, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 406, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- }
+ __pyx_t_5 = PyTuple_New(2+__pyx_t_9); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 406; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_5);
+ if (__pyx_t_1) {
+ PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1); __Pyx_GIVEREF(__pyx_t_1); __pyx_t_1 = NULL;
+ }
+ __Pyx_INCREF(__pyx_kp_s_w);
+ PyTuple_SET_ITEM(__pyx_t_5, 0+__pyx_t_9, __pyx_kp_s_w);
+ __Pyx_GIVEREF(__pyx_kp_s_w);
+ __Pyx_INCREF(__pyx_v_line);
+ PyTuple_SET_ITEM(__pyx_t_5, 1+__pyx_t_9, __pyx_v_line);
+ __Pyx_GIVEREF(__pyx_v_line);
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_5, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 406; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__Pyx_XDECREF_SET(__pyx_v_match, __pyx_t_2);
__pyx_t_2 = 0;
@@ -5726,7 +4979,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* # header type
* hkey = match.group(1).lstrip("#").strip()
*/
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_v_match); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 407, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_v_match); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 407; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
if (__pyx_t_6) {
/* "silx/io/specfile.pyx":409
@@ -5736,22 +4989,22 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* hvalue = match.group(2).strip()
* _add_or_concatenate(self._file_header_dict, hkey, hvalue)
*/
- __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_match, __pyx_n_s_group); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 409, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_match, __pyx_n_s_group); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
- __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_tuple__16, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 409, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_tuple__16, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_lstrip); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 409, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_lstrip); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_tuple__17, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 409, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_tuple__17, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_strip); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 409, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_strip); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_10))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_10))) {
__pyx_t_5 = PyMethod_GET_SELF(__pyx_t_10);
if (likely(__pyx_t_5)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10);
@@ -5761,10 +5014,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (__pyx_t_5) {
- __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_10, __pyx_t_5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 409, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_10, __pyx_t_5); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
} else {
- __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 409, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_10); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
@@ -5778,16 +5031,16 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* _add_or_concatenate(self._file_header_dict, hkey, hvalue)
* else:
*/
- __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_match, __pyx_n_s_group); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 410, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_match, __pyx_n_s_group); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 410; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
- __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_tuple__18, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 410, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_tuple__18, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 410; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_strip); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 410, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_strip); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 410; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_10))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_10))) {
__pyx_t_5 = PyMethod_GET_SELF(__pyx_t_10);
if (likely(__pyx_t_5)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10);
@@ -5797,10 +5050,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (__pyx_t_5) {
- __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_10, __pyx_t_5); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 410, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_10, __pyx_t_5); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 410; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
} else {
- __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 410, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_10); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 410; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
@@ -5814,13 +5067,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* else:
* _logger.warning("Unable to parse file header line " + line)
*/
- __pyx_t_10 = __Pyx_GetModuleGlobalName(__pyx_n_s_add_or_concatenate); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 411, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_GetModuleGlobalName(__pyx_n_s_add_or_concatenate); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 411; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_dict); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 411, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_dict); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 411; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_1 = NULL;
__pyx_t_9 = 0;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_10))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_10))) {
__pyx_t_1 = PyMethod_GET_SELF(__pyx_t_10);
if (likely(__pyx_t_1)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10);
@@ -5830,117 +5083,69 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
__pyx_t_9 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_10)) {
- PyObject *__pyx_temp[4] = {__pyx_t_1, __pyx_t_5, __pyx_v_hkey, __pyx_v_hvalue};
- __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_9, 3+__pyx_t_9); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 411, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_10)) {
- PyObject *__pyx_temp[4] = {__pyx_t_1, __pyx_t_5, __pyx_v_hkey, __pyx_v_hvalue};
- __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_9, 3+__pyx_t_9); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 411, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_15 = PyTuple_New(3+__pyx_t_9); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 411, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_15);
- if (__pyx_t_1) {
- __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_15, 0, __pyx_t_1); __pyx_t_1 = NULL;
- }
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_15, 0+__pyx_t_9, __pyx_t_5);
- __Pyx_INCREF(__pyx_v_hkey);
- __Pyx_GIVEREF(__pyx_v_hkey);
- PyTuple_SET_ITEM(__pyx_t_15, 1+__pyx_t_9, __pyx_v_hkey);
- __Pyx_INCREF(__pyx_v_hvalue);
- __Pyx_GIVEREF(__pyx_v_hvalue);
- PyTuple_SET_ITEM(__pyx_t_15, 2+__pyx_t_9, __pyx_v_hvalue);
- __pyx_t_5 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_15, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 411, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
+ __pyx_t_16 = PyTuple_New(3+__pyx_t_9); if (unlikely(!__pyx_t_16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 411; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_16);
+ if (__pyx_t_1) {
+ PyTuple_SET_ITEM(__pyx_t_16, 0, __pyx_t_1); __Pyx_GIVEREF(__pyx_t_1); __pyx_t_1 = NULL;
}
+ PyTuple_SET_ITEM(__pyx_t_16, 0+__pyx_t_9, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __Pyx_INCREF(__pyx_v_hkey);
+ PyTuple_SET_ITEM(__pyx_t_16, 1+__pyx_t_9, __pyx_v_hkey);
+ __Pyx_GIVEREF(__pyx_v_hkey);
+ __Pyx_INCREF(__pyx_v_hvalue);
+ PyTuple_SET_ITEM(__pyx_t_16, 2+__pyx_t_9, __pyx_v_hvalue);
+ __Pyx_GIVEREF(__pyx_v_hvalue);
+ __pyx_t_5 = 0;
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_16, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 411; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-
- /* "silx/io/specfile.pyx":407
- * for line in self._file_header_lines:
- * match = re.search(r"#(\w+) *(.*)", line)
- * if match: # <<<<<<<<<<<<<<
- * # header type
- * hkey = match.group(1).lstrip("#").strip()
- */
goto __pyx_L20;
}
+ /*else*/ {
- /* "silx/io/specfile.pyx":413
+ /* "silx/io/specfile.pyx":413
* _add_or_concatenate(self._file_header_dict, hkey, hvalue)
* else:
* _logger.warning("Unable to parse file header line " + line) # <<<<<<<<<<<<<<
*
* self._motor_names = self._specfile.motor_names(self._index)
*/
- /*else*/ {
- __pyx_t_10 = __Pyx_GetModuleGlobalName(__pyx_n_s_logger); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 413, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_GetModuleGlobalName(__pyx_n_s_logger); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 413; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
- __pyx_t_15 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_warning); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 413, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_15);
+ __pyx_t_16 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_warning); if (unlikely(!__pyx_t_16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 413; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_16);
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- __pyx_t_10 = PyNumber_Add(__pyx_kp_s_Unable_to_parse_file_header_line, __pyx_v_line); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 413, __pyx_L1_error)
+ __pyx_t_10 = PyNumber_Add(__pyx_kp_s_Unable_to_parse_file_header_line, __pyx_v_line); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 413; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
__pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_15))) {
- __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_15);
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_16))) {
+ __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_16);
if (likely(__pyx_t_5)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_15);
+ PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_16);
__Pyx_INCREF(__pyx_t_5);
__Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_15, function);
+ __Pyx_DECREF_SET(__pyx_t_16, function);
}
}
if (!__pyx_t_5) {
- __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_15, __pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 413, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_16, __pyx_t_10); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 413; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__Pyx_GOTREF(__pyx_t_2);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_15)) {
- PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_10};
- __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_15, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 413, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_15)) {
- PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_10};
- __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_15, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 413, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- } else
- #endif
- {
- __pyx_t_1 = PyTuple_New(1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 413, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_5); __pyx_t_5 = NULL;
- __Pyx_GIVEREF(__pyx_t_10);
- PyTuple_SET_ITEM(__pyx_t_1, 0+1, __pyx_t_10);
- __pyx_t_10 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_15, __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 413, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- }
+ __pyx_t_1 = PyTuple_New(1+1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 413; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_5); __Pyx_GIVEREF(__pyx_t_5); __pyx_t_5 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_1, 0+1, __pyx_t_10);
+ __Pyx_GIVEREF(__pyx_t_10);
+ __pyx_t_10 = 0;
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_16, __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 413; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
}
- __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
+ __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
}
__pyx_L20:;
@@ -5962,60 +5167,40 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* self._motor_positions = self._specfile.motor_positions(self._index)
*
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 415, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 415; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_15 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_motor_names); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 415, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_15);
+ __pyx_t_16 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_motor_names); if (unlikely(!__pyx_t_16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 415; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_16);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 415, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 415; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_1 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_15))) {
- __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_15);
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_16))) {
+ __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_16);
if (likely(__pyx_t_1)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_15);
+ PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_16);
__Pyx_INCREF(__pyx_t_1);
__Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_15, function);
+ __Pyx_DECREF_SET(__pyx_t_16, function);
}
}
if (!__pyx_t_1) {
- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_15, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 415, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_16, __pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 415; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_GOTREF(__pyx_t_3);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_15)) {
- PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_t_2};
- __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_15, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 415, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_15)) {
- PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_t_2};
- __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_15, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 415, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- } else
- #endif
- {
- __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 415, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_10);
- __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_1); __pyx_t_1 = NULL;
- __Pyx_GIVEREF(__pyx_t_2);
- PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_t_2);
- __pyx_t_2 = 0;
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_15, __pyx_t_10, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 415, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- }
+ __pyx_t_10 = PyTuple_New(1+1); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 415; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_10);
+ PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_1); __Pyx_GIVEREF(__pyx_t_1); __pyx_t_1 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_10, 0+1, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
+ __pyx_t_2 = 0;
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_16, __pyx_t_10, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 415; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_3);
+ __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
}
- __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_motor_names_2, __pyx_t_3) < 0) __PYX_ERR(0, 415, __pyx_L1_error)
+ __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_motor_names_2, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 415; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
/* "silx/io/specfile.pyx":416
@@ -6025,15 +5210,15 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
*
* self._data = None
*/
- __pyx_t_15 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 416, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_15);
- __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_15, __pyx_n_s_motor_positions); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 416, __pyx_L1_error)
+ __pyx_t_16 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_16);
+ __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_16, __pyx_n_s_motor_positions); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_10);
- __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
- __pyx_t_15 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 416, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_15);
+ __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
+ __pyx_t_16 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_16);
__pyx_t_2 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_10))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_10))) {
__pyx_t_2 = PyMethod_GET_SELF(__pyx_t_10);
if (likely(__pyx_t_2)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10);
@@ -6043,42 +5228,22 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
}
}
if (!__pyx_t_2) {
- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_10, __pyx_t_15); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 416, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
+ __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_10, __pyx_t_16); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
__Pyx_GOTREF(__pyx_t_3);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_10)) {
- PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_15};
- __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_10, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 416, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_10)) {
- PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_15};
- __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_10, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 416, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
- } else
- #endif
- {
- __pyx_t_1 = PyTuple_New(1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 416, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_2); __pyx_t_2 = NULL;
- __Pyx_GIVEREF(__pyx_t_15);
- PyTuple_SET_ITEM(__pyx_t_1, 0+1, __pyx_t_15);
- __pyx_t_15 = 0;
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_1, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 416, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- }
+ __pyx_t_1 = PyTuple_New(1+1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); __pyx_t_2 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_1, 0+1, __pyx_t_16);
+ __Pyx_GIVEREF(__pyx_t_16);
+ __pyx_t_16 = 0;
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_1, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_3);
+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
}
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_motor_positions_2, __pyx_t_3) < 0) __PYX_ERR(0, 416, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_motor_positions_2, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 416; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
/* "silx/io/specfile.pyx":418
@@ -6088,7 +5253,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
* self._mca = None
*
*/
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_data, Py_None) < 0) __PYX_ERR(0, 418, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_data, Py_None) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 418; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":419
*
@@ -6097,7 +5262,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
*
* @cython.embedsignature(False)
*/
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_mca, Py_None) < 0) __PYX_ERR(0, 419, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_mca, Py_None) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 419; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":362
* scan2 = sf["3.1"]
@@ -6117,8 +5282,8 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan___init__(CYTHON_UNUSED PyObj
__Pyx_XDECREF(__pyx_t_4);
__Pyx_XDECREF(__pyx_t_5);
__Pyx_XDECREF(__pyx_t_10);
- __Pyx_XDECREF(__pyx_t_14);
__Pyx_XDECREF(__pyx_t_15);
+ __Pyx_XDECREF(__pyx_t_16);
__Pyx_AddTraceback("silx.io.specfile.Scan.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
__pyx_r = NULL;
__pyx_L0:;
@@ -6160,6 +5325,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_2index(CYTHON_UNUSED PyObjec
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("index", 0);
/* "silx/io/specfile.pyx":429
@@ -6170,7 +5338,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_2index(CYTHON_UNUSED PyObjec
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 429, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 429; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -6222,6 +5390,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_4number(CYTHON_UNUSED PyObje
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("number", 0);
/* "silx/io/specfile.pyx":435
@@ -6232,7 +5403,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_4number(CYTHON_UNUSED PyObje
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_number_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 435, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_number_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 435; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -6284,6 +5455,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_6order(CYTHON_UNUSED PyObjec
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("order", 0);
/* "silx/io/specfile.pyx":441
@@ -6294,7 +5468,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_6order(CYTHON_UNUSED PyObjec
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_order_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 441, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_order_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 441; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -6346,6 +5520,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_8header(CYTHON_UNUSED PyObje
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("header", 0);
/* "silx/io/specfile.pyx":451
@@ -6356,7 +5533,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_8header(CYTHON_UNUSED PyObje
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 451, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 451; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -6408,6 +5585,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_10scan_header(CYTHON_UNUSED
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("scan_header", 0);
/* "silx/io/specfile.pyx":458
@@ -6418,7 +5598,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_10scan_header(CYTHON_UNUSED
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_lines); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 458, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_lines); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 458; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -6470,6 +5650,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_12file_header(CYTHON_UNUSED
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("file_header", 0);
/* "silx/io/specfile.pyx":465
@@ -6480,7 +5663,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_12file_header(CYTHON_UNUSED
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 465, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_lines); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 465; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -6532,6 +5715,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_14scan_header_dict(CYTHON_UN
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("scan_header_dict", 0);
/* "silx/io/specfile.pyx":475
@@ -6542,7 +5728,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_14scan_header_dict(CYTHON_UN
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_dict); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 475, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_scan_header_dict); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 475; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -6594,6 +5780,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_16mca_header_dict(CYTHON_UNU
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("mca_header_dict", 0);
/* "silx/io/specfile.pyx":484
@@ -6604,7 +5793,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_16mca_header_dict(CYTHON_UNU
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_mca_header_dict_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 484, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_mca_header_dict_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 484; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -6656,6 +5845,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_18file_header_dict(CYTHON_UN
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("file_header_dict", 0);
/* "silx/io/specfile.pyx":493
@@ -6666,7 +5858,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_18file_header_dict(CYTHON_UN
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_dict); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 493, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_file_header_dict); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 493; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -6718,6 +5910,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_20labels(CYTHON_UNUSED PyObj
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("labels", 0);
/* "silx/io/specfile.pyx":501
@@ -6728,7 +5923,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_20labels(CYTHON_UNUSED PyObj
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_labels); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 501, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_labels); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 501; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -6788,6 +5983,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_22data(CYTHON_UNUSED PyObjec
PyObject *__pyx_t_7 = NULL;
PyObject *__pyx_t_8 = NULL;
PyObject *__pyx_t_9 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("data", 0);
/* "silx/io/specfile.pyx":511
@@ -6797,7 +5995,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_22data(CYTHON_UNUSED PyObjec
* self._data = numpy.transpose(self._specfile.data(self._index))
*
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_data); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 511, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_data); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 511; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = (__pyx_t_1 == Py_None);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -6811,20 +6009,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_22data(CYTHON_UNUSED PyObjec
*
* return self._data
*/
- __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 512, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_transpose); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 512, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_transpose); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 512, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
- __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_data_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 512, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_data_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 512, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__pyx_t_8 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_7))) {
__pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7);
if (likely(__pyx_t_8)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7);
@@ -6834,43 +6032,23 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_22data(CYTHON_UNUSED PyObjec
}
}
if (!__pyx_t_8) {
- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 512, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_6); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
__Pyx_GOTREF(__pyx_t_4);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_7)) {
- PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6};
- __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 512, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) {
- PyObject *__pyx_temp[2] = {__pyx_t_8, __pyx_t_6};
- __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 512, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- } else
- #endif
- {
- __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 512, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_9);
- __Pyx_GIVEREF(__pyx_t_8); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __pyx_t_8 = NULL;
- __Pyx_GIVEREF(__pyx_t_6);
- PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_6);
- __pyx_t_6 = 0;
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 512, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
- }
+ __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_9);
+ PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_8); __Pyx_GIVEREF(__pyx_t_8); __pyx_t_8 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_6);
+ __Pyx_GIVEREF(__pyx_t_6);
+ __pyx_t_6 = 0;
+ __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_9, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
}
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
__pyx_t_7 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_5))) {
__pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5);
if (likely(__pyx_t_7)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
@@ -6880,52 +6058,26 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_22data(CYTHON_UNUSED PyObjec
}
}
if (!__pyx_t_7) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 512, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_4};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 512, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_4};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 512, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- } else
- #endif
- {
- __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 512, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_9);
- __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL;
- __Pyx_GIVEREF(__pyx_t_4);
- PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_4);
- __pyx_t_4 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 512, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
- }
+ __pyx_t_9 = PyTuple_New(1+1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_9);
+ PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __Pyx_GIVEREF(__pyx_t_7); __pyx_t_7 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_9, 0+1, __pyx_t_4);
+ __Pyx_GIVEREF(__pyx_t_4);
+ __pyx_t_4 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_data, __pyx_t_1) < 0) __PYX_ERR(0, 512, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_data, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 512; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-
- /* "silx/io/specfile.pyx":511
- * The first index is the detector, the second index is the sample index.
- * """
- * if self._data is None: # <<<<<<<<<<<<<<
- * self._data = numpy.transpose(self._specfile.data(self._index))
- *
- */
+ goto __pyx_L3;
}
+ __pyx_L3:;
/* "silx/io/specfile.pyx":514
* self._data = numpy.transpose(self._specfile.data(self._index))
@@ -6935,7 +6087,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_22data(CYTHON_UNUSED PyObjec
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_data); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 514, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_data); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 514; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -6998,6 +6150,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_24mca(CYTHON_UNUSED PyObject
PyObject *__pyx_t_4 = NULL;
PyObject *__pyx_t_5 = NULL;
PyObject *__pyx_t_6 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("mca", 0);
/* "silx/io/specfile.pyx":526
@@ -7007,7 +6162,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_24mca(CYTHON_UNUSED PyObject
* self._mca = MCA(self)
* return self._mca
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_mca); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 526, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_mca); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 526; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = (__pyx_t_1 == Py_None);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -7021,10 +6176,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_24mca(CYTHON_UNUSED PyObject
* return self._mca
*
*/
- __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_MCA); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 527, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_MCA); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 527; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_5)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -7034,49 +6189,25 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_24mca(CYTHON_UNUSED PyObject
}
}
if (!__pyx_t_5) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_v_self); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 527, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_v_self); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 527; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_v_self};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 527, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_v_self};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 527, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 527, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __pyx_t_5 = NULL;
- __Pyx_INCREF(__pyx_v_self);
- __Pyx_GIVEREF(__pyx_v_self);
- PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_v_self);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 527, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- }
+ __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 527; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_6);
+ PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __Pyx_GIVEREF(__pyx_t_5); __pyx_t_5 = NULL;
+ __Pyx_INCREF(__pyx_v_self);
+ PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_v_self);
+ __Pyx_GIVEREF(__pyx_v_self);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 527; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_mca, __pyx_t_1) < 0) __PYX_ERR(0, 527, __pyx_L1_error)
+ if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_n_s_mca, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 527; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-
- /* "silx/io/specfile.pyx":526
- * :rtype: :class:`MCA`
- * """
- * if self._mca is None: # <<<<<<<<<<<<<<
- * self._mca = MCA(self)
- * return self._mca
- */
+ goto __pyx_L3;
}
+ __pyx_L3:;
/* "silx/io/specfile.pyx":528
* if self._mca is None:
@@ -7086,7 +6217,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_24mca(CYTHON_UNUSED PyObject
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_mca); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 528, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_mca); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 528; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -7141,6 +6272,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_26motor_names(CYTHON_UNUSED
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("motor_names", 0);
/* "silx/io/specfile.pyx":535
@@ -7151,7 +6285,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_26motor_names(CYTHON_UNUSED
* @cython.embedsignature(False)
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_motor_names_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 535, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_motor_names_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 535; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -7203,6 +6337,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_28motor_positions(CYTHON_UNU
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("motor_positions", 0);
/* "silx/io/specfile.pyx":542
@@ -7213,7 +6350,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_28motor_positions(CYTHON_UNU
* def record_exists_in_hdr(self, record):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_motor_positions_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 542, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_motor_positions_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 542; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -7253,6 +6390,9 @@ static PyMethodDef __pyx_mdef_4silx_2io_8specfile_4Scan_31record_exists_in_hdr =
static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_31record_exists_in_hdr(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_self = 0;
PyObject *__pyx_v_record = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("record_exists_in_hdr (wrapper)", 0);
@@ -7276,11 +6416,11 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_31record_exists_in_hdr(PyObj
case 1:
if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_record)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("record_exists_in_hdr", 1, 2, 2, 1); __PYX_ERR(0, 544, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("record_exists_in_hdr", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 544; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "record_exists_in_hdr") < 0)) __PYX_ERR(0, 544, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "record_exists_in_hdr") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 544; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
goto __pyx_L5_argtuple_error;
@@ -7293,7 +6433,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_31record_exists_in_hdr(PyObj
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("record_exists_in_hdr", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 544, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("record_exists_in_hdr", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 544; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.Scan.record_exists_in_hdr", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
@@ -7319,6 +6459,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_30record_exists_in_hdr(CYTHO
PyObject *__pyx_t_7 = NULL;
PyObject *__pyx_t_8 = NULL;
int __pyx_t_9;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("record_exists_in_hdr", 0);
/* "silx/io/specfile.pyx":558
@@ -7328,34 +6471,32 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_30record_exists_in_hdr(CYTHO
* if line.startswith("#" + record):
* return True
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 558, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_header); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 558; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) {
__pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2); __pyx_t_3 = 0;
__pyx_t_4 = NULL;
} else {
- __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 558, __pyx_L1_error)
+ __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 558; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_4 = Py_TYPE(__pyx_t_2)->tp_iternext; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 558, __pyx_L1_error)
+ __pyx_t_4 = Py_TYPE(__pyx_t_2)->tp_iternext; if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 558; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
for (;;) {
if (likely(!__pyx_t_4)) {
if (likely(PyList_CheckExact(__pyx_t_2))) {
if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_2)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 558, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 558; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 558, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
+ __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 558; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
} else {
if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely(0 < 0)) __PYX_ERR(0, 558, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 558; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 558, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
+ __pyx_t_1 = PySequence_ITEM(__pyx_t_2, __pyx_t_3); __pyx_t_3++; if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 558; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
}
} else {
@@ -7364,7 +6505,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_30record_exists_in_hdr(CYTHO
PyObject* exc_type = PyErr_Occurred();
if (exc_type) {
if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
- else __PYX_ERR(0, 558, __pyx_L1_error)
+ else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 558; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
break;
}
@@ -7380,12 +6521,12 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_30record_exists_in_hdr(CYTHO
* return True
* return False
*/
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_line, __pyx_n_s_startswith); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 559, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_line, __pyx_n_s_startswith); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 559; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_6 = PyNumber_Add(__pyx_kp_s__7, __pyx_v_record); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 559, __pyx_L1_error)
+ __pyx_t_6 = PyNumber_Add(__pyx_kp_s__7, __pyx_v_record); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 559; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__pyx_t_7 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_5))) {
__pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5);
if (likely(__pyx_t_7)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
@@ -7395,42 +6536,22 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_30record_exists_in_hdr(CYTHO
}
}
if (!__pyx_t_7) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 559, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 559; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_6};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 559, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_6};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 559, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- } else
- #endif
- {
- __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 559, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL;
- __Pyx_GIVEREF(__pyx_t_6);
- PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_6);
- __pyx_t_6 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 559, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- }
+ __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 559; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
+ PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __Pyx_GIVEREF(__pyx_t_7); __pyx_t_7 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_6);
+ __Pyx_GIVEREF(__pyx_t_6);
+ __pyx_t_6 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 559; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_9 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_9 < 0)) __PYX_ERR(0, 559, __pyx_L1_error)
+ __pyx_t_9 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_9 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 559; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
if (__pyx_t_9) {
@@ -7446,14 +6567,6 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_30record_exists_in_hdr(CYTHO
__pyx_r = Py_True;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
goto __pyx_L0;
-
- /* "silx/io/specfile.pyx":559
- * """
- * for line in self._header:
- * if line.startswith("#" + record): # <<<<<<<<<<<<<<
- * return True
- * return False
- */
}
/* "silx/io/specfile.pyx":558
@@ -7518,6 +6631,9 @@ static PyMethodDef __pyx_mdef_4silx_2io_8specfile_4Scan_33data_line = {"data_lin
static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_33data_line(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_self = 0;
PyObject *__pyx_v_line_index = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("data_line (wrapper)", 0);
@@ -7541,11 +6657,11 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_33data_line(PyObject *__pyx_
case 1:
if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_line_index)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("data_line", 1, 2, 2, 1); __PYX_ERR(0, 563, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("data_line", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 563; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "data_line") < 0)) __PYX_ERR(0, 563, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "data_line") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 563; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
goto __pyx_L5_argtuple_error;
@@ -7558,7 +6674,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_33data_line(PyObject *__pyx_
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("data_line", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 563, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("data_line", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 563; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.Scan.data_line", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
@@ -7577,6 +6693,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_32data_line(CYTHON_UNUSED Py
PyObject *__pyx_t_1 = NULL;
PyObject *__pyx_t_2 = NULL;
PyObject *__pyx_t_3 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("data_line", 0);
/* "silx/io/specfile.pyx":581
@@ -7587,17 +6706,17 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_32data_line(CYTHON_UNUSED Py
* def data_column_by_name(self, label):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_data_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 581, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_data_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 581; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 581, __pyx_L1_error)
+ __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 581; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_INCREF(__pyx_slice__19);
- __Pyx_GIVEREF(__pyx_slice__19);
PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_slice__19);
+ __Pyx_GIVEREF(__pyx_slice__19);
__Pyx_INCREF(__pyx_v_line_index);
- __Pyx_GIVEREF(__pyx_v_line_index);
PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_v_line_index);
- __pyx_t_3 = PyObject_GetItem(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 581, __pyx_L1_error)
+ __Pyx_GIVEREF(__pyx_v_line_index);
+ __pyx_t_3 = PyObject_GetItem(__pyx_t_1, __pyx_t_2); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 581; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -7641,6 +6760,9 @@ static PyMethodDef __pyx_mdef_4silx_2io_8specfile_4Scan_35data_column_by_name =
static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_35data_column_by_name(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_self = 0;
PyObject *__pyx_v_label = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("data_column_by_name (wrapper)", 0);
@@ -7664,11 +6786,11 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_35data_column_by_name(PyObje
case 1:
if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_label)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("data_column_by_name", 1, 2, 2, 1); __PYX_ERR(0, 583, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("data_column_by_name", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 583; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "data_column_by_name") < 0)) __PYX_ERR(0, 583, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "data_column_by_name") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 583; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
goto __pyx_L5_argtuple_error;
@@ -7681,7 +6803,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_35data_column_by_name(PyObje
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("data_column_by_name", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 583, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("data_column_by_name", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 583; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.Scan.data_column_by_name", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
@@ -7705,12 +6827,16 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON
PyObject *__pyx_t_5 = NULL;
PyObject *__pyx_t_6 = NULL;
PyObject *__pyx_t_7 = NULL;
- int __pyx_t_8;
+ Py_ssize_t __pyx_t_8;
PyObject *__pyx_t_9 = NULL;
- PyObject *__pyx_t_10 = NULL;
+ int __pyx_t_10;
PyObject *__pyx_t_11 = NULL;
PyObject *__pyx_t_12 = NULL;
PyObject *__pyx_t_13 = NULL;
+ PyObject *__pyx_t_14 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("data_column_by_name", 0);
/* "silx/io/specfile.pyx":593
@@ -7721,8 +6847,6 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON
* except SfErrLineNotFound:
*/
{
- __Pyx_PyThreadState_declare
- __Pyx_PyThreadState_assign
__Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3);
__Pyx_XGOTREF(__pyx_t_1);
__Pyx_XGOTREF(__pyx_t_2);
@@ -7736,16 +6860,16 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON
* except SfErrLineNotFound:
* # Could be a "#C Scan aborted after 0 points"
*/
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 594, __pyx_L3_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 594; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_data_column_by_name); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 594, __pyx_L3_error)
+ __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_data_column_by_name); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 594; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__Pyx_GOTREF(__pyx_t_6);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 594, __pyx_L3_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 594; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_7 = NULL;
__pyx_t_8 = 0;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_6))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_6))) {
__pyx_t_7 = PyMethod_GET_SELF(__pyx_t_6);
if (likely(__pyx_t_7)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
@@ -7755,58 +6879,29 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON
__pyx_t_8 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_6)) {
- PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_t_5, __pyx_v_label};
- __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 594, __pyx_L3_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) {
- PyObject *__pyx_temp[3] = {__pyx_t_7, __pyx_t_5, __pyx_v_label};
- __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 594, __pyx_L3_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 594, __pyx_L3_error)
- __Pyx_GOTREF(__pyx_t_9);
- if (__pyx_t_7) {
- __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __pyx_t_7 = NULL;
- }
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_t_5);
- __Pyx_INCREF(__pyx_v_label);
- __Pyx_GIVEREF(__pyx_v_label);
- PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_v_label);
- __pyx_t_5 = 0;
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_9, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 594, __pyx_L3_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+ __pyx_t_9 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 594; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+ __Pyx_GOTREF(__pyx_t_9);
+ if (__pyx_t_7) {
+ PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_7); __Pyx_GIVEREF(__pyx_t_7); __pyx_t_7 = NULL;
}
+ PyTuple_SET_ITEM(__pyx_t_9, 0+__pyx_t_8, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __Pyx_INCREF(__pyx_v_label);
+ PyTuple_SET_ITEM(__pyx_t_9, 1+__pyx_t_8, __pyx_v_label);
+ __Pyx_GIVEREF(__pyx_v_label);
+ __pyx_t_5 = 0;
+ __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_9, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 594; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
__pyx_v_ret = __pyx_t_4;
__pyx_t_4 = 0;
-
- /* "silx/io/specfile.pyx":593
- * :rtype: numpy.ndarray
- * """
- * try: # <<<<<<<<<<<<<<
- * ret = self._specfile.data_column_by_name(self._index, label)
- * except SfErrLineNotFound:
- */
}
__Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
goto __pyx_L10_try_end;
__pyx_L3_error:;
- __Pyx_PyThreadState_assign
__Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
__Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
@@ -7820,13 +6915,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON
* # Could be a "#C Scan aborted after 0 points"
* _logger.warning("Cannot get data column %s in scan %d.%d",
*/
- __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrLineNotFound); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 595, __pyx_L5_except_error)
+ __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrLineNotFound); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 595; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_8 = __Pyx_PyErr_ExceptionMatches(__pyx_t_4);
+ __pyx_t_10 = PyErr_ExceptionMatches(__pyx_t_4);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (__pyx_t_8) {
+ if (__pyx_t_10) {
__Pyx_AddTraceback("silx.io.specfile.Scan.data_column_by_name", __pyx_clineno, __pyx_lineno, __pyx_filename);
- if (__Pyx_GetException(&__pyx_t_4, &__pyx_t_6, &__pyx_t_9) < 0) __PYX_ERR(0, 595, __pyx_L5_except_error)
+ if (__Pyx_GetException(&__pyx_t_4, &__pyx_t_6, &__pyx_t_9) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 595; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_GOTREF(__pyx_t_6);
__Pyx_GOTREF(__pyx_t_9);
@@ -7838,10 +6933,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON
* label, self.number, self.order)
* ret = numpy.empty((0, ), numpy.double)
*/
- __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_logger); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 597, __pyx_L5_except_error)
+ __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_logger); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 597; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
__Pyx_GOTREF(__pyx_t_7);
- __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_warning); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 597, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_10);
+ __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_warning); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 597; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
+ __Pyx_GOTREF(__pyx_t_11);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
/* "silx/io/specfile.pyx":598
@@ -7851,65 +6946,43 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON
* ret = numpy.empty((0, ), numpy.double)
* return ret
*/
- __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_number); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 598, __pyx_L5_except_error)
+ __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_number); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 598; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
__Pyx_GOTREF(__pyx_t_7);
- __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_order); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 598, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_11);
- __pyx_t_12 = NULL;
+ __pyx_t_12 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_order); if (unlikely(!__pyx_t_12)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 598; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
+ __Pyx_GOTREF(__pyx_t_12);
+ __pyx_t_13 = NULL;
__pyx_t_8 = 0;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_10))) {
- __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_10);
- if (likely(__pyx_t_12)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10);
- __Pyx_INCREF(__pyx_t_12);
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_11))) {
+ __pyx_t_13 = PyMethod_GET_SELF(__pyx_t_11);
+ if (likely(__pyx_t_13)) {
+ PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_11);
+ __Pyx_INCREF(__pyx_t_13);
__Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_10, function);
+ __Pyx_DECREF_SET(__pyx_t_11, function);
__pyx_t_8 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_10)) {
- PyObject *__pyx_temp[5] = {__pyx_t_12, __pyx_kp_s_Cannot_get_data_column_s_in_scan, __pyx_v_label, __pyx_t_7, __pyx_t_11};
- __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_8, 4+__pyx_t_8); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 597, __pyx_L5_except_error)
- __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0;
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_10)) {
- PyObject *__pyx_temp[5] = {__pyx_t_12, __pyx_kp_s_Cannot_get_data_column_s_in_scan, __pyx_v_label, __pyx_t_7, __pyx_t_11};
- __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_10, __pyx_temp+1-__pyx_t_8, 4+__pyx_t_8); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 597, __pyx_L5_except_error)
- __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0;
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
- } else
- #endif
- {
- __pyx_t_13 = PyTuple_New(4+__pyx_t_8); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 597, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_13);
- if (__pyx_t_12) {
- __Pyx_GIVEREF(__pyx_t_12); PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_12); __pyx_t_12 = NULL;
- }
- __Pyx_INCREF(__pyx_kp_s_Cannot_get_data_column_s_in_scan);
- __Pyx_GIVEREF(__pyx_kp_s_Cannot_get_data_column_s_in_scan);
- PyTuple_SET_ITEM(__pyx_t_13, 0+__pyx_t_8, __pyx_kp_s_Cannot_get_data_column_s_in_scan);
- __Pyx_INCREF(__pyx_v_label);
- __Pyx_GIVEREF(__pyx_v_label);
- PyTuple_SET_ITEM(__pyx_t_13, 1+__pyx_t_8, __pyx_v_label);
- __Pyx_GIVEREF(__pyx_t_7);
- PyTuple_SET_ITEM(__pyx_t_13, 2+__pyx_t_8, __pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_11);
- PyTuple_SET_ITEM(__pyx_t_13, 3+__pyx_t_8, __pyx_t_11);
- __pyx_t_7 = 0;
- __pyx_t_11 = 0;
- __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_t_13, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 597, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
+ __pyx_t_14 = PyTuple_New(4+__pyx_t_8); if (unlikely(!__pyx_t_14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 597; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
+ __Pyx_GOTREF(__pyx_t_14);
+ if (__pyx_t_13) {
+ PyTuple_SET_ITEM(__pyx_t_14, 0, __pyx_t_13); __Pyx_GIVEREF(__pyx_t_13); __pyx_t_13 = NULL;
}
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+ __Pyx_INCREF(__pyx_kp_s_Cannot_get_data_column_s_in_scan);
+ PyTuple_SET_ITEM(__pyx_t_14, 0+__pyx_t_8, __pyx_kp_s_Cannot_get_data_column_s_in_scan);
+ __Pyx_GIVEREF(__pyx_kp_s_Cannot_get_data_column_s_in_scan);
+ __Pyx_INCREF(__pyx_v_label);
+ PyTuple_SET_ITEM(__pyx_t_14, 1+__pyx_t_8, __pyx_v_label);
+ __Pyx_GIVEREF(__pyx_v_label);
+ PyTuple_SET_ITEM(__pyx_t_14, 2+__pyx_t_8, __pyx_t_7);
+ __Pyx_GIVEREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_14, 3+__pyx_t_8, __pyx_t_12);
+ __Pyx_GIVEREF(__pyx_t_12);
+ __pyx_t_7 = 0;
+ __pyx_t_12 = 0;
+ __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_14, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 597; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
+ __Pyx_GOTREF(__pyx_t_5);
+ __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
+ __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
/* "silx/io/specfile.pyx":599
@@ -7919,63 +6992,43 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON
* return ret
*
*/
- __pyx_t_10 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 599, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_10);
- __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_empty); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 599, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_13);
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- __pyx_t_10 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 599, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_10);
- __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_n_s_double); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 599, __pyx_L5_except_error)
+ __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 599; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
__Pyx_GOTREF(__pyx_t_11);
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- __pyx_t_10 = NULL;
+ __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_empty); if (unlikely(!__pyx_t_14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 599; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
+ __Pyx_GOTREF(__pyx_t_14);
+ __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+ __pyx_t_11 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 599; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
+ __Pyx_GOTREF(__pyx_t_11);
+ __pyx_t_12 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_n_s_double); if (unlikely(!__pyx_t_12)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 599; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
+ __Pyx_GOTREF(__pyx_t_12);
+ __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+ __pyx_t_11 = NULL;
__pyx_t_8 = 0;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_13))) {
- __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_13);
- if (likely(__pyx_t_10)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_13);
- __Pyx_INCREF(__pyx_t_10);
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_14))) {
+ __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_14);
+ if (likely(__pyx_t_11)) {
+ PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_14);
+ __Pyx_INCREF(__pyx_t_11);
__Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_13, function);
+ __Pyx_DECREF_SET(__pyx_t_14, function);
__pyx_t_8 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_13)) {
- PyObject *__pyx_temp[3] = {__pyx_t_10, __pyx_tuple__20, __pyx_t_11};
- __pyx_t_5 = __Pyx_PyFunction_FastCall(__pyx_t_13, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 599, __pyx_L5_except_error)
- __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_13)) {
- PyObject *__pyx_temp[3] = {__pyx_t_10, __pyx_tuple__20, __pyx_t_11};
- __pyx_t_5 = __Pyx_PyCFunction_FastCall(__pyx_t_13, __pyx_temp+1-__pyx_t_8, 2+__pyx_t_8); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 599, __pyx_L5_except_error)
- __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 599, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_7);
- if (__pyx_t_10) {
- __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_10); __pyx_t_10 = NULL;
- }
- __Pyx_INCREF(__pyx_tuple__20);
- __Pyx_GIVEREF(__pyx_tuple__20);
- PyTuple_SET_ITEM(__pyx_t_7, 0+__pyx_t_8, __pyx_tuple__20);
- __Pyx_GIVEREF(__pyx_t_11);
- PyTuple_SET_ITEM(__pyx_t_7, 1+__pyx_t_8, __pyx_t_11);
- __pyx_t_11 = 0;
- __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_13, __pyx_t_7, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 599, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+ __pyx_t_7 = PyTuple_New(2+__pyx_t_8); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 599; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ if (__pyx_t_11) {
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_11); __Pyx_GIVEREF(__pyx_t_11); __pyx_t_11 = NULL;
}
- __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
+ __Pyx_INCREF(__pyx_tuple__20);
+ PyTuple_SET_ITEM(__pyx_t_7, 0+__pyx_t_8, __pyx_tuple__20);
+ __Pyx_GIVEREF(__pyx_tuple__20);
+ PyTuple_SET_ITEM(__pyx_t_7, 1+__pyx_t_8, __pyx_t_12);
+ __Pyx_GIVEREF(__pyx_t_12);
+ __pyx_t_12 = 0;
+ __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_14, __pyx_t_7, NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 599; __pyx_clineno = __LINE__; goto __pyx_L5_except_error;}
+ __Pyx_GOTREF(__pyx_t_5);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+ __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
__Pyx_XDECREF_SET(__pyx_v_ret, __pyx_t_5);
__pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
@@ -7985,22 +7038,12 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON
}
goto __pyx_L5_except_error;
__pyx_L5_except_error:;
-
- /* "silx/io/specfile.pyx":593
- * :rtype: numpy.ndarray
- * """
- * try: # <<<<<<<<<<<<<<
- * ret = self._specfile.data_column_by_name(self._index, label)
- * except SfErrLineNotFound:
- */
- __Pyx_PyThreadState_assign
__Pyx_XGIVEREF(__pyx_t_1);
__Pyx_XGIVEREF(__pyx_t_2);
__Pyx_XGIVEREF(__pyx_t_3);
__Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3);
goto __pyx_L1_error;
__pyx_L4_exception_handled:;
- __Pyx_PyThreadState_assign
__Pyx_XGIVEREF(__pyx_t_1);
__Pyx_XGIVEREF(__pyx_t_2);
__Pyx_XGIVEREF(__pyx_t_3);
@@ -8035,10 +7078,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_34data_column_by_name(CYTHON
__Pyx_XDECREF(__pyx_t_6);
__Pyx_XDECREF(__pyx_t_7);
__Pyx_XDECREF(__pyx_t_9);
- __Pyx_XDECREF(__pyx_t_10);
__Pyx_XDECREF(__pyx_t_11);
__Pyx_XDECREF(__pyx_t_12);
__Pyx_XDECREF(__pyx_t_13);
+ __Pyx_XDECREF(__pyx_t_14);
__Pyx_AddTraceback("silx.io.specfile.Scan.data_column_by_name", __pyx_clineno, __pyx_lineno, __pyx_filename);
__pyx_r = NULL;
__pyx_L0:;
@@ -8063,6 +7106,9 @@ static PyMethodDef __pyx_mdef_4silx_2io_8specfile_4Scan_37motor_position_by_name
static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_37motor_position_by_name(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_self = 0;
PyObject *__pyx_v_name = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("motor_position_by_name (wrapper)", 0);
@@ -8086,11 +7132,11 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_37motor_position_by_name(PyO
case 1:
if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_name)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("motor_position_by_name", 1, 2, 2, 1); __PYX_ERR(0, 602, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("motor_position_by_name", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 602; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "motor_position_by_name") < 0)) __PYX_ERR(0, 602, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "motor_position_by_name") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 602; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
goto __pyx_L5_argtuple_error;
@@ -8103,7 +7149,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_4Scan_37motor_position_by_name(PyO
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("motor_position_by_name", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 602, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("motor_position_by_name", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 602; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.Scan.motor_position_by_name", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
@@ -8123,8 +7169,11 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_36motor_position_by_name(CYT
PyObject *__pyx_t_2 = NULL;
PyObject *__pyx_t_3 = NULL;
PyObject *__pyx_t_4 = NULL;
- int __pyx_t_5;
+ Py_ssize_t __pyx_t_5;
PyObject *__pyx_t_6 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("motor_position_by_name", 0);
/* "silx/io/specfile.pyx":612
@@ -8135,16 +7184,16 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_36motor_position_by_name(CYT
*
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 612, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_specfile); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 612; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_motor_position_by_name); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 612, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_motor_position_by_name); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 612; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 612, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_n_s_index_2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 612; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_4 = NULL;
__pyx_t_5 = 0;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -8154,40 +7203,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4Scan_36motor_position_by_name(CYT
__pyx_t_5 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[3] = {__pyx_t_4, __pyx_t_2, __pyx_v_name};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_5, 2+__pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 612, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[3] = {__pyx_t_4, __pyx_t_2, __pyx_v_name};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_5, 2+__pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 612, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- } else
- #endif
- {
- __pyx_t_6 = PyTuple_New(2+__pyx_t_5); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 612, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- if (__pyx_t_4) {
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_4); __pyx_t_4 = NULL;
- }
- __Pyx_GIVEREF(__pyx_t_2);
- PyTuple_SET_ITEM(__pyx_t_6, 0+__pyx_t_5, __pyx_t_2);
- __Pyx_INCREF(__pyx_v_name);
- __Pyx_GIVEREF(__pyx_v_name);
- PyTuple_SET_ITEM(__pyx_t_6, 1+__pyx_t_5, __pyx_v_name);
- __pyx_t_2 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 612, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+ __pyx_t_6 = PyTuple_New(2+__pyx_t_5); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 612; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_6);
+ if (__pyx_t_4) {
+ PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
}
+ PyTuple_SET_ITEM(__pyx_t_6, 0+__pyx_t_5, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
+ __Pyx_INCREF(__pyx_v_name);
+ PyTuple_SET_ITEM(__pyx_t_6, 1+__pyx_t_5, __pyx_v_name);
+ __Pyx_GIVEREF(__pyx_v_name);
+ __pyx_t_2 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 612; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
@@ -8247,6 +7276,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_2_string_to_char_star(CYTHON_UNUSE
PyObject *__pyx_t_3 = NULL;
int __pyx_t_4;
int __pyx_t_5;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("_string_to_char_star", 0);
/* "silx/io/specfile.pyx":617
@@ -8256,18 +7288,18 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_2_string_to_char_star(CYTHON_UNUSE
* return bytes(string_, "ascii")
* return string_
*/
- __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_sys); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 617, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_sys); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 617; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_version); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 617, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_version); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 617; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_startswith); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 617, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_startswith); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 617; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__21, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 617, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__21, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 617; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 617, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 617; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_4) {
} else {
@@ -8288,28 +7320,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_2_string_to_char_star(CYTHON_UNUSE
*
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 618, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 618; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_INCREF(__pyx_v_string_);
- __Pyx_GIVEREF(__pyx_v_string_);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_string_);
+ __Pyx_GIVEREF(__pyx_v_string_);
__Pyx_INCREF(__pyx_n_s_ascii);
- __Pyx_GIVEREF(__pyx_n_s_ascii);
PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_n_s_ascii);
- __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)(&PyBytes_Type)), __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 618, __pyx_L1_error)
+ __Pyx_GIVEREF(__pyx_n_s_ascii);
+ __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)((PyObject*)(&PyBytes_Type))), __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 618; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_r = __pyx_t_2;
__pyx_t_2 = 0;
goto __pyx_L0;
-
- /* "silx/io/specfile.pyx":617
- * def _string_to_char_star(string_):
- * """Convert a string to ASCII encoded bytes when using python3"""
- * if sys.version.startswith("3") and not isinstance(string_, bytes): # <<<<<<<<<<<<<<
- * return bytes(string_, "ascii")
- * return string_
- */
}
/* "silx/io/specfile.pyx":619
@@ -8369,6 +7393,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_5is_specfile(PyObject *__pyx_self,
static PyObject *__pyx_pf_4silx_2io_8specfile_4is_specfile(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_filename) {
PyObject *__pyx_v_f = NULL;
+ PyObject *__pyx_v_chunk = NULL;
PyObject *__pyx_v_i = NULL;
PyObject *__pyx_v_line = NULL;
PyObject *__pyx_r = NULL;
@@ -8379,9 +7404,16 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4is_specfile(CYTHON_UNUSED PyObjec
PyObject *__pyx_t_4 = NULL;
int __pyx_t_5;
int __pyx_t_6;
- Py_ssize_t __pyx_t_7;
- PyObject *(*__pyx_t_8)(PyObject *);
+ PyObject *__pyx_t_7 = NULL;
+ PyObject *__pyx_t_8 = NULL;
PyObject *__pyx_t_9 = NULL;
+ PyObject *__pyx_t_10 = NULL;
+ PyObject *__pyx_t_11 = NULL;
+ Py_ssize_t __pyx_t_12;
+ PyObject *(*__pyx_t_13)(PyObject *);
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("is_specfile", 0);
/* "silx/io/specfile.pyx":630
@@ -8389,18 +7421,18 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4is_specfile(CYTHON_UNUSED PyObjec
* """
* if not os.path.isfile(filename): # <<<<<<<<<<<<<<
* return False
- * # test for presence of #S or #F in first two lines
+ * # test for presence of #S or #F in first 10 lines
*/
- __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_os); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 630, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_os); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 630; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_path); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 630, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_path); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 630; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_isfile); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 630, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_isfile); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 630; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_3 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -8410,39 +7442,21 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4is_specfile(CYTHON_UNUSED PyObjec
}
}
if (!__pyx_t_3) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_filename); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 630, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_filename); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 630; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_filename};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 630, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_filename};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 630, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 630, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL;
- __Pyx_INCREF(__pyx_v_filename);
- __Pyx_GIVEREF(__pyx_v_filename);
- PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_filename);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 630, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- }
+ __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 630; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __Pyx_GIVEREF(__pyx_t_3); __pyx_t_3 = NULL;
+ __Pyx_INCREF(__pyx_v_filename);
+ PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_filename);
+ __Pyx_GIVEREF(__pyx_v_filename);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 630; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 630, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 630; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_6 = ((!__pyx_t_5) != 0);
if (__pyx_t_6) {
@@ -8451,161 +7465,261 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4is_specfile(CYTHON_UNUSED PyObjec
* """
* if not os.path.isfile(filename):
* return False # <<<<<<<<<<<<<<
- * # test for presence of #S or #F in first two lines
- * f = open(filename)
+ * # test for presence of #S or #F in first 10 lines
+ * with open(filename, "rb") as f:
*/
__Pyx_XDECREF(__pyx_r);
__Pyx_INCREF(Py_False);
__pyx_r = Py_False;
goto __pyx_L0;
-
- /* "silx/io/specfile.pyx":630
- * :rtype: bool
- * """
- * if not os.path.isfile(filename): # <<<<<<<<<<<<<<
- * return False
- * # test for presence of #S or #F in first two lines
- */
}
/* "silx/io/specfile.pyx":633
* return False
- * # test for presence of #S or #F in first two lines
- * f = open(filename) # <<<<<<<<<<<<<<
- * for i, line in enumerate(f):
- * if line.startswith("#S ") or line.startswith("#F "):
+ * # test for presence of #S or #F in first 10 lines
+ * with open(filename, "rb") as f: # <<<<<<<<<<<<<<
+ * chunk = f.read(2500)
+ * for i, line in enumerate(chunk.split(b"\n")):
*/
- __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 633, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_INCREF(__pyx_v_filename);
- __Pyx_GIVEREF(__pyx_v_filename);
- PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_filename);
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_open, __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 633, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_v_f = __pyx_t_2;
- __pyx_t_2 = 0;
+ /*with:*/ {
+ __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_INCREF(__pyx_v_filename);
+ PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_filename);
+ __Pyx_GIVEREF(__pyx_v_filename);
+ __Pyx_INCREF(__pyx_n_s_rb);
+ PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_n_s_rb);
+ __Pyx_GIVEREF(__pyx_n_s_rb);
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_open, __pyx_t_1, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+ __pyx_t_7 = __Pyx_PyObject_LookupSpecial(__pyx_t_2, __pyx_n_s_exit); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ __pyx_t_4 = __Pyx_PyObject_LookupSpecial(__pyx_t_2, __pyx_n_s_enter); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L4_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ __pyx_t_3 = NULL;
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
+ __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_4);
+ if (likely(__pyx_t_3)) {
+ PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
+ __Pyx_INCREF(__pyx_t_3);
+ __Pyx_INCREF(function);
+ __Pyx_DECREF_SET(__pyx_t_4, function);
+ }
+ }
+ if (__pyx_t_3) {
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L4_error;}
+ __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+ } else {
+ __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L4_error;}
+ }
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+ __pyx_t_4 = __pyx_t_1;
+ __pyx_t_1 = 0;
+ __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+ /*try:*/ {
+ {
+ __Pyx_ExceptionSave(&__pyx_t_8, &__pyx_t_9, &__pyx_t_10);
+ __Pyx_XGOTREF(__pyx_t_8);
+ __Pyx_XGOTREF(__pyx_t_9);
+ __Pyx_XGOTREF(__pyx_t_10);
+ /*try:*/ {
+ __pyx_v_f = __pyx_t_4;
+ __pyx_t_4 = 0;
- /* "silx/io/specfile.pyx":634
- * # test for presence of #S or #F in first two lines
- * f = open(filename)
- * for i, line in enumerate(f): # <<<<<<<<<<<<<<
- * if line.startswith("#S ") or line.startswith("#F "):
- * f.close()
+ /* "silx/io/specfile.pyx":634
+ * # test for presence of #S or #F in first 10 lines
+ * with open(filename, "rb") as f:
+ * chunk = f.read(2500) # <<<<<<<<<<<<<<
+ * for i, line in enumerate(chunk.split(b"\n")):
+ * if line.startswith(b"#S ") or line.startswith(b"#F "):
+ */
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_f, __pyx_n_s_read); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 634; __pyx_clineno = __LINE__; goto __pyx_L8_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_tuple__22, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 634; __pyx_clineno = __LINE__; goto __pyx_L8_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+ __pyx_v_chunk = __pyx_t_2;
+ __pyx_t_2 = 0;
+ }
+ __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
+ __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
+ __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
+ goto __pyx_L15_try_end;
+ __pyx_L8_error:;
+ __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
+ __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
+ __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
+ __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+ /* "silx/io/specfile.pyx":633
+ * return False
+ * # test for presence of #S or #F in first 10 lines
+ * with open(filename, "rb") as f: # <<<<<<<<<<<<<<
+ * chunk = f.read(2500)
+ * for i, line in enumerate(chunk.split(b"\n")):
+ */
+ /*except:*/ {
+ __Pyx_AddTraceback("silx.io.specfile.is_specfile", __pyx_clineno, __pyx_lineno, __pyx_filename);
+ if (__Pyx_GetException(&__pyx_t_2, &__pyx_t_4, &__pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ __Pyx_GOTREF(__pyx_t_4);
+ __Pyx_GOTREF(__pyx_t_1);
+ __pyx_t_3 = PyTuple_Pack(3, __pyx_t_2, __pyx_t_4, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
+ __Pyx_GOTREF(__pyx_t_3);
+ __pyx_t_11 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_3, NULL);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+ __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+ if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
+ __Pyx_GOTREF(__pyx_t_11);
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_11);
+ __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+ if (__pyx_t_6 < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
+ __pyx_t_5 = ((!(__pyx_t_6 != 0)) != 0);
+ if (__pyx_t_5) {
+ __Pyx_GIVEREF(__pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_4);
+ __Pyx_XGIVEREF(__pyx_t_1);
+ __Pyx_ErrRestore(__pyx_t_2, __pyx_t_4, __pyx_t_1);
+ __pyx_t_2 = 0; __pyx_t_4 = 0; __pyx_t_1 = 0;
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L10_except_error;}
+ }
+ __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+ goto __pyx_L9_exception_handled;
+ }
+ __pyx_L10_except_error:;
+ __Pyx_XGIVEREF(__pyx_t_8);
+ __Pyx_XGIVEREF(__pyx_t_9);
+ __Pyx_XGIVEREF(__pyx_t_10);
+ __Pyx_ExceptionReset(__pyx_t_8, __pyx_t_9, __pyx_t_10);
+ goto __pyx_L1_error;
+ __pyx_L9_exception_handled:;
+ __Pyx_XGIVEREF(__pyx_t_8);
+ __Pyx_XGIVEREF(__pyx_t_9);
+ __Pyx_XGIVEREF(__pyx_t_10);
+ __Pyx_ExceptionReset(__pyx_t_8, __pyx_t_9, __pyx_t_10);
+ __pyx_L15_try_end:;
+ }
+ }
+ /*finally:*/ {
+ /*normal exit:*/{
+ if (__pyx_t_7) {
+ __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_tuple__23, NULL);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+ if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_10);
+ __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+ }
+ goto __pyx_L7;
+ }
+ __pyx_L7:;
+ }
+ goto __pyx_L19;
+ __pyx_L4_error:;
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+ goto __pyx_L1_error;
+ __pyx_L19:;
+ }
+
+ /* "silx/io/specfile.pyx":635
+ * with open(filename, "rb") as f:
+ * chunk = f.read(2500)
+ * for i, line in enumerate(chunk.split(b"\n")): # <<<<<<<<<<<<<<
+ * if line.startswith(b"#S ") or line.startswith(b"#F "):
+ * return True
*/
__Pyx_INCREF(__pyx_int_0);
- __pyx_t_2 = __pyx_int_0;
- if (likely(PyList_CheckExact(__pyx_v_f)) || PyTuple_CheckExact(__pyx_v_f)) {
- __pyx_t_1 = __pyx_v_f; __Pyx_INCREF(__pyx_t_1); __pyx_t_7 = 0;
- __pyx_t_8 = NULL;
+ __pyx_t_1 = __pyx_int_0;
+ if (unlikely(!__pyx_v_chunk)) { __Pyx_RaiseUnboundLocalError("chunk"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_chunk, __pyx_n_s_split); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_tuple__24, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+ if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) {
+ __pyx_t_4 = __pyx_t_2; __Pyx_INCREF(__pyx_t_4); __pyx_t_12 = 0;
+ __pyx_t_13 = NULL;
} else {
- __pyx_t_7 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_f); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 634, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_8 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 634, __pyx_L1_error)
+ __pyx_t_12 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ __pyx_t_13 = Py_TYPE(__pyx_t_4)->tp_iternext; if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
+ __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
for (;;) {
- if (likely(!__pyx_t_8)) {
- if (likely(PyList_CheckExact(__pyx_t_1))) {
- if (__pyx_t_7 >= PyList_GET_SIZE(__pyx_t_1)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_7); __Pyx_INCREF(__pyx_t_4); __pyx_t_7++; if (unlikely(0 < 0)) __PYX_ERR(0, 634, __pyx_L1_error)
+ if (likely(!__pyx_t_13)) {
+ if (likely(PyList_CheckExact(__pyx_t_4))) {
+ if (__pyx_t_12 >= PyList_GET_SIZE(__pyx_t_4)) break;
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_2 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_12); __Pyx_INCREF(__pyx_t_2); __pyx_t_12++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 634, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
+ __pyx_t_2 = PySequence_ITEM(__pyx_t_4, __pyx_t_12); __pyx_t_12++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
} else {
- if (__pyx_t_7 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_7); __Pyx_INCREF(__pyx_t_4); __pyx_t_7++; if (unlikely(0 < 0)) __PYX_ERR(0, 634, __pyx_L1_error)
+ if (__pyx_t_12 >= PyTuple_GET_SIZE(__pyx_t_4)) break;
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_12); __Pyx_INCREF(__pyx_t_2); __pyx_t_12++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_7); __pyx_t_7++; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 634, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
+ __pyx_t_2 = PySequence_ITEM(__pyx_t_4, __pyx_t_12); __pyx_t_12++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
}
} else {
- __pyx_t_4 = __pyx_t_8(__pyx_t_1);
- if (unlikely(!__pyx_t_4)) {
+ __pyx_t_2 = __pyx_t_13(__pyx_t_4);
+ if (unlikely(!__pyx_t_2)) {
PyObject* exc_type = PyErr_Occurred();
if (exc_type) {
if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
- else __PYX_ERR(0, 634, __pyx_L1_error)
+ else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
break;
}
- __Pyx_GOTREF(__pyx_t_4);
+ __Pyx_GOTREF(__pyx_t_2);
}
- __Pyx_XDECREF_SET(__pyx_v_line, __pyx_t_4);
- __pyx_t_4 = 0;
- __Pyx_INCREF(__pyx_t_2);
- __Pyx_XDECREF_SET(__pyx_v_i, __pyx_t_2);
- __pyx_t_4 = __Pyx_PyInt_AddObjC(__pyx_t_2, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 634, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_2);
- __pyx_t_2 = __pyx_t_4;
- __pyx_t_4 = 0;
+ __Pyx_XDECREF_SET(__pyx_v_line, __pyx_t_2);
+ __pyx_t_2 = 0;
+ __Pyx_INCREF(__pyx_t_1);
+ __Pyx_XDECREF_SET(__pyx_v_i, __pyx_t_1);
+ __pyx_t_2 = PyNumber_Add(__pyx_t_1, __pyx_int_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ __Pyx_DECREF(__pyx_t_1);
+ __pyx_t_1 = __pyx_t_2;
+ __pyx_t_2 = 0;
- /* "silx/io/specfile.pyx":635
- * f = open(filename)
- * for i, line in enumerate(f):
- * if line.startswith("#S ") or line.startswith("#F "): # <<<<<<<<<<<<<<
- * f.close()
+ /* "silx/io/specfile.pyx":636
+ * chunk = f.read(2500)
+ * for i, line in enumerate(chunk.split(b"\n")):
+ * if line.startswith(b"#S ") or line.startswith(b"#F "): # <<<<<<<<<<<<<<
* return True
+ * if i >= 10:
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_line, __pyx_n_s_startswith); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 635, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_tuple__22, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 635, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_line, __pyx_n_s_startswith); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 636; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__25, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 636; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 635, __pyx_L1_error)
+ __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 636; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- if (!__pyx_t_5) {
+ if (!__pyx_t_6) {
} else {
- __pyx_t_6 = __pyx_t_5;
- goto __pyx_L7_bool_binop_done;
+ __pyx_t_5 = __pyx_t_6;
+ goto __pyx_L23_bool_binop_done;
}
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_line, __pyx_n_s_startswith); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 635, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_line, __pyx_n_s_startswith); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 636; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__23, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 635, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__26, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 636; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 635, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __pyx_t_5;
- __pyx_L7_bool_binop_done:;
- if (__pyx_t_6) {
-
- /* "silx/io/specfile.pyx":636
- * for i, line in enumerate(f):
- * if line.startswith("#S ") or line.startswith("#F "):
- * f.close() # <<<<<<<<<<<<<<
- * return True
- * if i >= 10:
- */
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_f, __pyx_n_s_close); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 636, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_9 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
- __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_3);
- if (likely(__pyx_t_9)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
- __Pyx_INCREF(__pyx_t_9);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_3, function);
- }
- }
- if (__pyx_t_9) {
- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_9); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 636, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
- } else {
- __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 636, __pyx_L1_error)
- }
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 636; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+ __pyx_t_5 = __pyx_t_6;
+ __pyx_L23_bool_binop_done:;
+ if (__pyx_t_5) {
/* "silx/io/specfile.pyx":637
- * if line.startswith("#S ") or line.startswith("#F "):
- * f.close()
+ * for i, line in enumerate(chunk.split(b"\n")):
+ * if line.startswith(b"#S ") or line.startswith(b"#F "):
* return True # <<<<<<<<<<<<<<
* if i >= 10:
* break
@@ -8614,92 +7728,47 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4is_specfile(CYTHON_UNUSED PyObjec
__Pyx_INCREF(Py_True);
__pyx_r = Py_True;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
goto __pyx_L0;
-
- /* "silx/io/specfile.pyx":635
- * f = open(filename)
- * for i, line in enumerate(f):
- * if line.startswith("#S ") or line.startswith("#F "): # <<<<<<<<<<<<<<
- * f.close()
- * return True
- */
}
/* "silx/io/specfile.pyx":638
- * f.close()
+ * if line.startswith(b"#S ") or line.startswith(b"#F "):
* return True
* if i >= 10: # <<<<<<<<<<<<<<
* break
- * f.close()
+ * return False
*/
- __pyx_t_4 = PyObject_RichCompare(__pyx_v_i, __pyx_int_10, Py_GE); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 638, __pyx_L1_error)
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 638, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (__pyx_t_6) {
+ __pyx_t_2 = PyObject_RichCompare(__pyx_v_i, __pyx_int_10, Py_GE); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 638; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 638; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+ if (__pyx_t_5) {
/* "silx/io/specfile.pyx":639
* return True
* if i >= 10:
* break # <<<<<<<<<<<<<<
- * f.close()
* return False
+ *
*/
- goto __pyx_L5_break;
-
- /* "silx/io/specfile.pyx":638
- * f.close()
- * return True
- * if i >= 10: # <<<<<<<<<<<<<<
- * break
- * f.close()
- */
+ goto __pyx_L21_break;
}
- /* "silx/io/specfile.pyx":634
- * # test for presence of #S or #F in first two lines
- * f = open(filename)
- * for i, line in enumerate(f): # <<<<<<<<<<<<<<
- * if line.startswith("#S ") or line.startswith("#F "):
- * f.close()
+ /* "silx/io/specfile.pyx":635
+ * with open(filename, "rb") as f:
+ * chunk = f.read(2500)
+ * for i, line in enumerate(chunk.split(b"\n")): # <<<<<<<<<<<<<<
+ * if line.startswith(b"#S ") or line.startswith(b"#F "):
+ * return True
*/
}
- __pyx_L5_break:;
+ __pyx_L21_break:;
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":640
* if i >= 10:
* break
- * f.close() # <<<<<<<<<<<<<<
- * return False
- *
- */
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_f, __pyx_n_s_close); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 640, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) {
- __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_1);
- if (likely(__pyx_t_4)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1);
- __Pyx_INCREF(__pyx_t_4);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_1, function);
- }
- }
- if (__pyx_t_4) {
- __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 640, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- } else {
- __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 640, __pyx_L1_error)
- }
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-
- /* "silx/io/specfile.pyx":641
- * break
- * f.close()
* return False # <<<<<<<<<<<<<<
*
*
@@ -8723,11 +7792,11 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4is_specfile(CYTHON_UNUSED PyObjec
__Pyx_XDECREF(__pyx_t_2);
__Pyx_XDECREF(__pyx_t_3);
__Pyx_XDECREF(__pyx_t_4);
- __Pyx_XDECREF(__pyx_t_9);
__Pyx_AddTraceback("silx.io.specfile.is_specfile", __pyx_clineno, __pyx_lineno, __pyx_filename);
__pyx_r = NULL;
__pyx_L0:;
__Pyx_XDECREF(__pyx_v_f);
+ __Pyx_XDECREF(__pyx_v_chunk);
__Pyx_XDECREF(__pyx_v_i);
__Pyx_XDECREF(__pyx_v_line);
__Pyx_XGIVEREF(__pyx_r);
@@ -8735,7 +7804,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4is_specfile(CYTHON_UNUSED PyObjec
return __pyx_r;
}
-/* "silx/io/specfile.pyx":657
+/* "silx/io/specfile.pyx":656
* str filename
*
* def __cinit__(self, filename): # <<<<<<<<<<<<<<
@@ -8747,6 +7816,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_4is_specfile(CYTHON_UNUSED PyObjec
static int __pyx_pw_4silx_2io_8specfile_8SpecFile_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static int __pyx_pw_4silx_2io_8specfile_8SpecFile_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_filename = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
int __pyx_r;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
@@ -8768,7 +7840,7 @@ static int __pyx_pw_4silx_2io_8specfile_8SpecFile_1__cinit__(PyObject *__pyx_v_s
else goto __pyx_L5_argtuple_error;
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) __PYX_ERR(0, 657, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 656; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
goto __pyx_L5_argtuple_error;
@@ -8779,7 +7851,7 @@ static int __pyx_pw_4silx_2io_8specfile_8SpecFile_1__cinit__(PyObject *__pyx_v_s
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 657, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 656; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.SpecFile.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
@@ -8804,23 +7876,26 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile___cinit__(struct __pyx_obj_4si
int __pyx_t_6;
char *__pyx_t_7;
PyObject *__pyx_t_8 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__cinit__", 0);
__Pyx_INCREF(__pyx_v_filename);
- /* "silx/io/specfile.pyx":658
+ /* "silx/io/specfile.pyx":657
*
* def __cinit__(self, filename):
* cdef int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
* self.handle = NULL
*
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 658, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 657; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 658, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 657; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":659
+ /* "silx/io/specfile.pyx":658
* def __cinit__(self, filename):
* cdef int error = SF_ERR_NO_ERRORS
* self.handle = NULL # <<<<<<<<<<<<<<
@@ -8829,17 +7904,17 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile___cinit__(struct __pyx_obj_4si
*/
__pyx_v_self->handle = NULL;
- /* "silx/io/specfile.pyx":661
+ /* "silx/io/specfile.pyx":660
* self.handle = NULL
*
* if is_specfile(filename): # <<<<<<<<<<<<<<
* filename = _string_to_char_star(filename)
* self.handle = specfile_wrapper.SfOpen(filename, &error)
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_is_specfile); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 661, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_is_specfile); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 660; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -8849,53 +7924,35 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile___cinit__(struct __pyx_obj_4si
}
}
if (!__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_filename); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 661, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_filename); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 660; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_v_filename};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 661, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_v_filename};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 661, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 661, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __pyx_t_4 = NULL;
- __Pyx_INCREF(__pyx_v_filename);
- __Pyx_GIVEREF(__pyx_v_filename);
- PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_v_filename);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 661, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- }
+ __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 660; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_5);
+ PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
+ __Pyx_INCREF(__pyx_v_filename);
+ PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_v_filename);
+ __Pyx_GIVEREF(__pyx_v_filename);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 660; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 661, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 660; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
if (__pyx_t_6) {
- /* "silx/io/specfile.pyx":662
+ /* "silx/io/specfile.pyx":661
*
* if is_specfile(filename):
* filename = _string_to_char_star(filename) # <<<<<<<<<<<<<<
* self.handle = specfile_wrapper.SfOpen(filename, &error)
* if error:
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_string_to_char_star); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 662, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_string_to_char_star); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 661; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_5 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_5)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -8905,52 +7962,34 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile___cinit__(struct __pyx_obj_4si
}
}
if (!__pyx_t_5) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_filename); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 662, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_filename); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 661; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_v_filename};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 662, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_v_filename};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 662, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 662, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_5); __pyx_t_5 = NULL;
- __Pyx_INCREF(__pyx_v_filename);
- __Pyx_GIVEREF(__pyx_v_filename);
- PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_filename);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 662, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- }
+ __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 661; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_5); __Pyx_GIVEREF(__pyx_t_5); __pyx_t_5 = NULL;
+ __Pyx_INCREF(__pyx_v_filename);
+ PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_filename);
+ __Pyx_GIVEREF(__pyx_v_filename);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 661; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF_SET(__pyx_v_filename, __pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":663
+ /* "silx/io/specfile.pyx":662
* if is_specfile(filename):
* filename = _string_to_char_star(filename)
* self.handle = specfile_wrapper.SfOpen(filename, &error) # <<<<<<<<<<<<<<
* if error:
* self._handle_error(error)
*/
- __pyx_t_7 = __Pyx_PyObject_AsString(__pyx_v_filename); if (unlikely((!__pyx_t_7) && PyErr_Occurred())) __PYX_ERR(0, 663, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_AsString(__pyx_v_filename); if (unlikely((!__pyx_t_7) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 662; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_v_self->handle = SfOpen(__pyx_t_7, (&__pyx_v_error));
- /* "silx/io/specfile.pyx":664
+ /* "silx/io/specfile.pyx":663
* filename = _string_to_char_star(filename)
* self.handle = specfile_wrapper.SfOpen(filename, &error)
* if error: # <<<<<<<<<<<<<<
@@ -8960,19 +7999,19 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile___cinit__(struct __pyx_obj_4si
__pyx_t_6 = (__pyx_v_error != 0);
if (__pyx_t_6) {
- /* "silx/io/specfile.pyx":665
+ /* "silx/io/specfile.pyx":664
* self.handle = specfile_wrapper.SfOpen(filename, &error)
* if error:
* self._handle_error(error) # <<<<<<<<<<<<<<
* else:
* # handle_error takes care of raising the correct error,
*/
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 665, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 664; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 665, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 664; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_5 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_5)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -8982,76 +8021,42 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile___cinit__(struct __pyx_obj_4si
}
}
if (!__pyx_t_5) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 665, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 664; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_4};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 665, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_4};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 665, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- } else
- #endif
- {
- __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 665, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_5); __pyx_t_5 = NULL;
- __Pyx_GIVEREF(__pyx_t_4);
- PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_4);
- __pyx_t_4 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 665, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- }
+ __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 664; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
+ PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_5); __Pyx_GIVEREF(__pyx_t_5); __pyx_t_5 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_4);
+ __Pyx_GIVEREF(__pyx_t_4);
+ __pyx_t_4 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 664; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-
- /* "silx/io/specfile.pyx":664
- * filename = _string_to_char_star(filename)
- * self.handle = specfile_wrapper.SfOpen(filename, &error)
- * if error: # <<<<<<<<<<<<<<
- * self._handle_error(error)
- * else:
- */
+ goto __pyx_L4;
}
-
- /* "silx/io/specfile.pyx":661
- * self.handle = NULL
- *
- * if is_specfile(filename): # <<<<<<<<<<<<<<
- * filename = _string_to_char_star(filename)
- * self.handle = specfile_wrapper.SfOpen(filename, &error)
- */
+ __pyx_L4:;
goto __pyx_L3;
}
+ /*else*/ {
- /* "silx/io/specfile.pyx":669
+ /* "silx/io/specfile.pyx":668
* # handle_error takes care of raising the correct error,
* # this causes the destructor to be called
* self._handle_error(SF_ERR_FILE_OPEN) # <<<<<<<<<<<<<<
*
* def __init__(self, filename):
*/
- /*else*/ {
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 669, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 668; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_FILE_OPEN); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 669, __pyx_L1_error)
+ __pyx_t_8 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_FILE_OPEN); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 668; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_8);
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -9061,46 +8066,26 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile___cinit__(struct __pyx_obj_4si
}
}
if (!__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_8); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 669, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_8); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 668; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_8};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 669, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_8};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 669, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- } else
- #endif
- {
- __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 669, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __pyx_t_4 = NULL;
- __Pyx_GIVEREF(__pyx_t_8);
- PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_t_8);
- __pyx_t_8 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 669, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- }
+ __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 668; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_5);
+ PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_t_8);
+ __Pyx_GIVEREF(__pyx_t_8);
+ __pyx_t_8 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 668; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
}
__pyx_L3:;
- /* "silx/io/specfile.pyx":657
+ /* "silx/io/specfile.pyx":656
* str filename
*
* def __cinit__(self, filename): # <<<<<<<<<<<<<<
@@ -9125,7 +8110,7 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile___cinit__(struct __pyx_obj_4si
return __pyx_r;
}
-/* "silx/io/specfile.pyx":671
+/* "silx/io/specfile.pyx":670
* self._handle_error(SF_ERR_FILE_OPEN)
*
* def __init__(self, filename): # <<<<<<<<<<<<<<
@@ -9137,6 +8122,9 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile___cinit__(struct __pyx_obj_4si
static int __pyx_pw_4silx_2io_8specfile_8SpecFile_3__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static int __pyx_pw_4silx_2io_8specfile_8SpecFile_3__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_filename = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
int __pyx_r;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("__init__ (wrapper)", 0);
@@ -9158,7 +8146,7 @@ static int __pyx_pw_4silx_2io_8specfile_8SpecFile_3__init__(PyObject *__pyx_v_se
else goto __pyx_L5_argtuple_error;
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) __PYX_ERR(0, 671, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 670; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
goto __pyx_L5_argtuple_error;
@@ -9169,7 +8157,7 @@ static int __pyx_pw_4silx_2io_8specfile_8SpecFile_3__init__(PyObject *__pyx_v_se
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("__init__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 671, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("__init__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 670; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.SpecFile.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
@@ -9190,9 +8178,12 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile_2__init__(struct __pyx_obj_4si
PyObject *__pyx_t_3 = NULL;
PyObject *__pyx_t_4 = NULL;
PyObject *__pyx_t_5 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__init__", 0);
- /* "silx/io/specfile.pyx":672
+ /* "silx/io/specfile.pyx":671
*
* def __init__(self, filename):
* if not isinstance(filename, str): # <<<<<<<<<<<<<<
@@ -9203,38 +8194,38 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile_2__init__(struct __pyx_obj_4si
__pyx_t_2 = ((!(__pyx_t_1 != 0)) != 0);
if (__pyx_t_2) {
- /* "silx/io/specfile.pyx":674
+ /* "silx/io/specfile.pyx":673
* if not isinstance(filename, str):
* # encode unicode to str in python 2
* if sys.version_info[0] < 3: # <<<<<<<<<<<<<<
* self.filename = filename.encode()
* # decode bytes to str in python 3
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_sys); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 674, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_sys); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 673; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_version_info); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 674, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_version_info); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 673; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_4, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 674, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetItemInt(__pyx_t_4, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 673; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_int_3, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 674, __pyx_L1_error)
+ __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_int_3, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 673; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 674, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 673; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (__pyx_t_2) {
- /* "silx/io/specfile.pyx":675
+ /* "silx/io/specfile.pyx":674
* # encode unicode to str in python 2
* if sys.version_info[0] < 3:
* self.filename = filename.encode() # <<<<<<<<<<<<<<
* # decode bytes to str in python 3
* elif sys.version_info[0] >= 3:
*/
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_filename, __pyx_n_s_encode); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 675, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_filename, __pyx_n_s_encode); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 674; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_5 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_5)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -9244,62 +8235,54 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile_2__init__(struct __pyx_obj_4si
}
}
if (__pyx_t_5) {
- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 675, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_5); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 674; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
} else {
- __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 675, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_CallNoArg(__pyx_t_3); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 674; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- if (!(likely(PyString_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_4)->tp_name), 0))) __PYX_ERR(0, 675, __pyx_L1_error)
+ if (!(likely(PyString_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_4)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 674; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GIVEREF(__pyx_t_4);
__Pyx_GOTREF(__pyx_v_self->filename);
__Pyx_DECREF(__pyx_v_self->filename);
__pyx_v_self->filename = ((PyObject*)__pyx_t_4);
__pyx_t_4 = 0;
-
- /* "silx/io/specfile.pyx":674
- * if not isinstance(filename, str):
- * # encode unicode to str in python 2
- * if sys.version_info[0] < 3: # <<<<<<<<<<<<<<
- * self.filename = filename.encode()
- * # decode bytes to str in python 3
- */
goto __pyx_L4;
}
- /* "silx/io/specfile.pyx":677
+ /* "silx/io/specfile.pyx":676
* self.filename = filename.encode()
* # decode bytes to str in python 3
* elif sys.version_info[0] >= 3: # <<<<<<<<<<<<<<
* self.filename = filename.decode()
* else:
*/
- __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_sys); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 677, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_sys); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 676; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_version_info); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 677, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_version_info); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 676; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_4 = __Pyx_GetItemInt(__pyx_t_3, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 677, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_GetItemInt(__pyx_t_3, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(__pyx_t_4 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 676; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_3 = PyObject_RichCompare(__pyx_t_4, __pyx_int_3, Py_GE); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 677, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_t_4, __pyx_int_3, Py_GE); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 676; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 677, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 676; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_2) {
- /* "silx/io/specfile.pyx":678
+ /* "silx/io/specfile.pyx":677
* # decode bytes to str in python 3
* elif sys.version_info[0] >= 3:
* self.filename = filename.decode() # <<<<<<<<<<<<<<
* else:
* self.filename = filename
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_filename, __pyx_n_s_decode); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 678, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_filename, __pyx_n_s_decode); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 677; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_5)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -9309,49 +8292,34 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile_2__init__(struct __pyx_obj_4si
}
}
if (__pyx_t_5) {
- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 678, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 677; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
} else {
- __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 678, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 677; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (!(likely(PyString_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(0, 678, __pyx_L1_error)
+ if (!(likely(PyString_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_t_3)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 677; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GIVEREF(__pyx_t_3);
__Pyx_GOTREF(__pyx_v_self->filename);
__Pyx_DECREF(__pyx_v_self->filename);
__pyx_v_self->filename = ((PyObject*)__pyx_t_3);
__pyx_t_3 = 0;
-
- /* "silx/io/specfile.pyx":677
- * self.filename = filename.encode()
- * # decode bytes to str in python 3
- * elif sys.version_info[0] >= 3: # <<<<<<<<<<<<<<
- * self.filename = filename.decode()
- * else:
- */
+ goto __pyx_L4;
}
__pyx_L4:;
-
- /* "silx/io/specfile.pyx":672
- *
- * def __init__(self, filename):
- * if not isinstance(filename, str): # <<<<<<<<<<<<<<
- * # encode unicode to str in python 2
- * if sys.version_info[0] < 3:
- */
goto __pyx_L3;
}
+ /*else*/ {
- /* "silx/io/specfile.pyx":680
+ /* "silx/io/specfile.pyx":679
* self.filename = filename.decode()
* else:
* self.filename = filename # <<<<<<<<<<<<<<
*
* def __dealloc__(self):
*/
- /*else*/ {
- if (!(likely(PyString_CheckExact(__pyx_v_filename))||((__pyx_v_filename) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_filename)->tp_name), 0))) __PYX_ERR(0, 680, __pyx_L1_error)
+ if (!(likely(PyString_CheckExact(__pyx_v_filename))||((__pyx_v_filename) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "str", Py_TYPE(__pyx_v_filename)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 679; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_t_3 = __pyx_v_filename;
__Pyx_INCREF(__pyx_t_3);
__Pyx_GIVEREF(__pyx_t_3);
@@ -9362,7 +8330,7 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile_2__init__(struct __pyx_obj_4si
}
__pyx_L3:;
- /* "silx/io/specfile.pyx":671
+ /* "silx/io/specfile.pyx":670
* self._handle_error(SF_ERR_FILE_OPEN)
*
* def __init__(self, filename): # <<<<<<<<<<<<<<
@@ -9384,12 +8352,12 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile_2__init__(struct __pyx_obj_4si
return __pyx_r;
}
-/* "silx/io/specfile.pyx":682
+/* "silx/io/specfile.pyx":681
* self.filename = filename
*
* def __dealloc__(self): # <<<<<<<<<<<<<<
* """Destructor: Calls SfClose(self.handle)"""
- * # handle is NULL if SfOpen failed
+ * self.close()
*/
/* Python wrapper */
@@ -9405,13 +8373,97 @@ static void __pyx_pw_4silx_2io_8specfile_8SpecFile_5__dealloc__(PyObject *__pyx_
static void __pyx_pf_4silx_2io_8specfile_8SpecFile_4__dealloc__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
__Pyx_RefNannyDeclarations
- int __pyx_t_1;
+ PyObject *__pyx_t_1 = NULL;
PyObject *__pyx_t_2 = NULL;
PyObject *__pyx_t_3 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__dealloc__", 0);
- /* "silx/io/specfile.pyx":685
+ /* "silx/io/specfile.pyx":683
+ * def __dealloc__(self):
* """Destructor: Calls SfClose(self.handle)"""
+ * self.close() # <<<<<<<<<<<<<<
+ *
+ * def close(self):
+ */
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_close); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 683; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_2);
+ __pyx_t_3 = NULL;
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
+ __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
+ if (likely(__pyx_t_3)) {
+ PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
+ __Pyx_INCREF(__pyx_t_3);
+ __Pyx_INCREF(function);
+ __Pyx_DECREF_SET(__pyx_t_2, function);
+ }
+ }
+ if (__pyx_t_3) {
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 683; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+ } else {
+ __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 683; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ }
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+ /* "silx/io/specfile.pyx":681
+ * self.filename = filename
+ *
+ * def __dealloc__(self): # <<<<<<<<<<<<<<
+ * """Destructor: Calls SfClose(self.handle)"""
+ * self.close()
+ */
+
+ /* function exit code */
+ goto __pyx_L0;
+ __pyx_L1_error:;
+ __Pyx_XDECREF(__pyx_t_1);
+ __Pyx_XDECREF(__pyx_t_2);
+ __Pyx_XDECREF(__pyx_t_3);
+ __Pyx_WriteUnraisable("silx.io.specfile.SpecFile.__dealloc__", __pyx_clineno, __pyx_lineno, __pyx_filename, 0);
+ __pyx_L0:;
+ __Pyx_RefNannyFinishContext();
+}
+
+/* "silx/io/specfile.pyx":685
+ * self.close()
+ *
+ * def close(self): # <<<<<<<<<<<<<<
+ * """Close the file descriptor"""
+ * # handle is NULL if SfOpen failed
+ */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_7close(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_6close[] = "SpecFile.close(self)\nClose the file descriptor";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_7close(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+ PyObject *__pyx_r = 0;
+ __Pyx_RefNannyDeclarations
+ __Pyx_RefNannySetupContext("close (wrapper)", 0);
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_6close(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self));
+
+ /* function exit code */
+ __Pyx_RefNannyFinishContext();
+ return __pyx_r;
+}
+
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_6close(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
+ PyObject *__pyx_r = NULL;
+ __Pyx_RefNannyDeclarations
+ int __pyx_t_1;
+ PyObject *__pyx_t_2 = NULL;
+ PyObject *__pyx_t_3 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
+ __Pyx_RefNannySetupContext("close", 0);
+
+ /* "silx/io/specfile.pyx":688
+ * """Close the file descriptor"""
* # handle is NULL if SfOpen failed
* if self.handle: # <<<<<<<<<<<<<<
* if specfile_wrapper.SfClose(self.handle):
@@ -9420,71 +8472,72 @@ static void __pyx_pf_4silx_2io_8specfile_8SpecFile_4__dealloc__(struct __pyx_obj
__pyx_t_1 = (__pyx_v_self->handle != 0);
if (__pyx_t_1) {
- /* "silx/io/specfile.pyx":686
+ /* "silx/io/specfile.pyx":689
* # handle is NULL if SfOpen failed
* if self.handle:
* if specfile_wrapper.SfClose(self.handle): # <<<<<<<<<<<<<<
* _logger.warning("Error while closing SpecFile")
- *
+ * self.handle = NULL
*/
__pyx_t_1 = (SfClose(__pyx_v_self->handle) != 0);
if (__pyx_t_1) {
- /* "silx/io/specfile.pyx":687
+ /* "silx/io/specfile.pyx":690
* if self.handle:
* if specfile_wrapper.SfClose(self.handle):
* _logger.warning("Error while closing SpecFile") # <<<<<<<<<<<<<<
+ * self.handle = NULL
*
- * def __len__(self):
*/
- __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_logger); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 687, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_logger); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 690; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_warning); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 687, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_warning); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 690; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__24, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 687, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__27, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 690; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-
- /* "silx/io/specfile.pyx":686
- * # handle is NULL if SfOpen failed
- * if self.handle:
- * if specfile_wrapper.SfClose(self.handle): # <<<<<<<<<<<<<<
- * _logger.warning("Error while closing SpecFile")
- *
- */
+ goto __pyx_L4;
}
+ __pyx_L4:;
- /* "silx/io/specfile.pyx":685
- * """Destructor: Calls SfClose(self.handle)"""
- * # handle is NULL if SfOpen failed
- * if self.handle: # <<<<<<<<<<<<<<
+ /* "silx/io/specfile.pyx":691
* if specfile_wrapper.SfClose(self.handle):
* _logger.warning("Error while closing SpecFile")
+ * self.handle = NULL # <<<<<<<<<<<<<<
+ *
+ * def __len__(self):
*/
+ __pyx_v_self->handle = NULL;
+ goto __pyx_L3;
}
+ __pyx_L3:;
- /* "silx/io/specfile.pyx":682
- * self.filename = filename
+ /* "silx/io/specfile.pyx":685
+ * self.close()
*
- * def __dealloc__(self): # <<<<<<<<<<<<<<
- * """Destructor: Calls SfClose(self.handle)"""
+ * def close(self): # <<<<<<<<<<<<<<
+ * """Close the file descriptor"""
* # handle is NULL if SfOpen failed
*/
/* function exit code */
+ __pyx_r = Py_None; __Pyx_INCREF(Py_None);
goto __pyx_L0;
__pyx_L1_error:;
__Pyx_XDECREF(__pyx_t_2);
__Pyx_XDECREF(__pyx_t_3);
- __Pyx_WriteUnraisable("silx.io.specfile.SpecFile.__dealloc__", __pyx_clineno, __pyx_lineno, __pyx_filename, 0, 0);
+ __Pyx_AddTraceback("silx.io.specfile.SpecFile.close", __pyx_clineno, __pyx_lineno, __pyx_filename);
+ __pyx_r = NULL;
__pyx_L0:;
+ __Pyx_XGIVEREF(__pyx_r);
__Pyx_RefNannyFinishContext();
+ return __pyx_r;
}
-/* "silx/io/specfile.pyx":689
- * _logger.warning("Error while closing SpecFile")
+/* "silx/io/specfile.pyx":693
+ * self.handle = NULL
*
* def __len__(self): # <<<<<<<<<<<<<<
* """Return the number of scans in the SpecFile
@@ -9492,28 +8545,28 @@ static void __pyx_pf_4silx_2io_8specfile_8SpecFile_4__dealloc__(struct __pyx_obj
*/
/* Python wrapper */
-static Py_ssize_t __pyx_pw_4silx_2io_8specfile_8SpecFile_7__len__(PyObject *__pyx_v_self); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_6__len__[] = "Return the number of scans in the SpecFile\n ";
+static Py_ssize_t __pyx_pw_4silx_2io_8specfile_8SpecFile_9__len__(PyObject *__pyx_v_self); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_8__len__[] = "Return the number of scans in the SpecFile\n ";
#if CYTHON_COMPILING_IN_CPYTHON
-struct wrapperbase __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_6__len__;
+struct wrapperbase __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_8__len__;
#endif
-static Py_ssize_t __pyx_pw_4silx_2io_8specfile_8SpecFile_7__len__(PyObject *__pyx_v_self) {
+static Py_ssize_t __pyx_pw_4silx_2io_8specfile_8SpecFile_9__len__(PyObject *__pyx_v_self) {
Py_ssize_t __pyx_r;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("__len__ (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_6__len__(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_8__len__(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static Py_ssize_t __pyx_pf_4silx_2io_8specfile_8SpecFile_6__len__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
+static Py_ssize_t __pyx_pf_4silx_2io_8specfile_8SpecFile_8__len__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
Py_ssize_t __pyx_r;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("__len__", 0);
- /* "silx/io/specfile.pyx":692
+ /* "silx/io/specfile.pyx":696
* """Return the number of scans in the SpecFile
* """
* return specfile_wrapper.SfScanNo(self.handle) # <<<<<<<<<<<<<<
@@ -9523,8 +8576,8 @@ static Py_ssize_t __pyx_pf_4silx_2io_8specfile_8SpecFile_6__len__(struct __pyx_o
__pyx_r = SfScanNo(__pyx_v_self->handle);
goto __pyx_L0;
- /* "silx/io/specfile.pyx":689
- * _logger.warning("Error while closing SpecFile")
+ /* "silx/io/specfile.pyx":693
+ * self.handle = NULL
*
* def __len__(self): # <<<<<<<<<<<<<<
* """Return the number of scans in the SpecFile
@@ -9536,9 +8589,9 @@ static Py_ssize_t __pyx_pf_4silx_2io_8specfile_8SpecFile_6__len__(struct __pyx_o
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_gb_4silx_2io_8specfile_8SpecFile_10generator1(__pyx_CoroutineObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+static PyObject *__pyx_gb_4silx_2io_8specfile_8SpecFile_12generator1(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
-/* "silx/io/specfile.pyx":694
+/* "silx/io/specfile.pyx":698
* return specfile_wrapper.SfScanNo(self.handle)
*
* def __iter__(self): # <<<<<<<<<<<<<<
@@ -9547,40 +8600,41 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_8SpecFile_10generator1(__pyx_Corou
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_9__iter__(PyObject *__pyx_v_self); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_8__iter__[] = "Return the next :class:`Scan` in a SpecFile each time this method\n is called.\n\n This usually happens when the python built-in function ``next()`` is\n called with a :class:`SpecFile` instance as a parameter, or when a\n :class:`SpecFile` instance is used as an iterator (e.g. in a ``for``\n loop).\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_11__iter__(PyObject *__pyx_v_self); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_10__iter__[] = "Return the next :class:`Scan` in a SpecFile each time this method\n is called.\n\n This usually happens when the python built-in function ``next()`` is\n called with a :class:`SpecFile` instance as a parameter, or when a\n :class:`SpecFile` instance is used as an iterator (e.g. in a ``for``\n loop).\n ";
#if CYTHON_COMPILING_IN_CPYTHON
-struct wrapperbase __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_8__iter__;
+struct wrapperbase __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_10__iter__;
#endif
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_9__iter__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_11__iter__(PyObject *__pyx_v_self) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("__iter__ (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_8__iter__(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_10__iter__(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_8__iter__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_10__iter__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct_1___iter__ *__pyx_cur_scope;
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__iter__", 0);
__pyx_cur_scope = (struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct_1___iter__ *)__pyx_tp_new_4silx_2io_8specfile___pyx_scope_struct_1___iter__(__pyx_ptype_4silx_2io_8specfile___pyx_scope_struct_1___iter__, __pyx_empty_tuple, NULL);
if (unlikely(!__pyx_cur_scope)) {
- __pyx_cur_scope = ((struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct_1___iter__ *)Py_None);
- __Pyx_INCREF(Py_None);
- __PYX_ERR(0, 694, __pyx_L1_error)
- } else {
- __Pyx_GOTREF(__pyx_cur_scope);
+ __Pyx_RefNannyFinishContext();
+ return NULL;
}
+ __Pyx_GOTREF(__pyx_cur_scope);
__pyx_cur_scope->__pyx_v_self = __pyx_v_self;
__Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
__Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
{
- __pyx_CoroutineObject *gen = __Pyx_Generator_New((__pyx_coroutine_body_t) __pyx_gb_4silx_2io_8specfile_8SpecFile_10generator1, (PyObject *) __pyx_cur_scope, __pyx_n_s_iter, __pyx_n_s_SpecFile___iter, __pyx_n_s_silx_io_specfile); if (unlikely(!gen)) __PYX_ERR(0, 694, __pyx_L1_error)
+ __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_4silx_2io_8specfile_8SpecFile_12generator1, (PyObject *) __pyx_cur_scope, __pyx_n_s_iter, __pyx_n_s_SpecFile___iter); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 698; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_cur_scope);
__Pyx_RefNannyFinishContext();
return (PyObject *) gen;
@@ -9596,7 +8650,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_8__iter__(struct __pyx_o
return __pyx_r;
}
-static PyObject *__pyx_gb_4silx_2io_8specfile_8SpecFile_10generator1(__pyx_CoroutineObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+static PyObject *__pyx_gb_4silx_2io_8specfile_8SpecFile_12generator1(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
{
struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct_1___iter__ *__pyx_cur_scope = ((struct __pyx_obj_4silx_2io_8specfile___pyx_scope_struct_1___iter__ *)__pyx_generator->closure);
PyObject *__pyx_r = NULL;
@@ -9606,8 +8660,11 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_8SpecFile_10generator1(__pyx_Corou
PyObject *__pyx_t_4 = NULL;
PyObject *__pyx_t_5 = NULL;
PyObject *__pyx_t_6 = NULL;
- int __pyx_t_7;
+ Py_ssize_t __pyx_t_7;
PyObject *__pyx_t_8 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("None", 0);
switch (__pyx_generator->resume_label) {
@@ -9618,33 +8675,33 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_8SpecFile_10generator1(__pyx_Corou
return NULL;
}
__pyx_L3_first_run:;
- if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 694, __pyx_L1_error)
+ if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 698; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
- /* "silx/io/specfile.pyx":703
+ /* "silx/io/specfile.pyx":707
* loop).
* """
* for scan_index in range(len(self)): # <<<<<<<<<<<<<<
* yield Scan(self, scan_index)
*
*/
- __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) __PYX_ERR(0, 703, __pyx_L1_error)
+ __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 707; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
__pyx_cur_scope->__pyx_v_scan_index = __pyx_t_2;
- /* "silx/io/specfile.pyx":704
+ /* "silx/io/specfile.pyx":708
* """
* for scan_index in range(len(self)):
* yield Scan(self, scan_index) # <<<<<<<<<<<<<<
*
* def __getitem__(self, key):
*/
- __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_Scan); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 704, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_Scan); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 708; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = PyInt_FromSsize_t(__pyx_cur_scope->__pyx_v_scan_index); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 704, __pyx_L1_error)
+ __pyx_t_5 = PyInt_FromSsize_t(__pyx_cur_scope->__pyx_v_scan_index); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 708; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
__pyx_t_7 = 0;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -9654,40 +8711,20 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_8SpecFile_10generator1(__pyx_Corou
__pyx_t_7 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_t_5};
- __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 704, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[3] = {__pyx_t_6, ((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_t_5};
- __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-__pyx_t_7, 2+__pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 704, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_8 = PyTuple_New(2+__pyx_t_7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 704, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- if (__pyx_t_6) {
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __pyx_t_6 = NULL;
- }
- __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_v_self));
- __Pyx_GIVEREF(((PyObject *)__pyx_cur_scope->__pyx_v_self));
- PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_7, ((PyObject *)__pyx_cur_scope->__pyx_v_self));
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_7, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 704, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- }
+ __pyx_t_8 = PyTuple_New(2+__pyx_t_7); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 708; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
+ if (__pyx_t_6) {
+ PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ }
+ __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_v_self));
+ PyTuple_SET_ITEM(__pyx_t_8, 0+__pyx_t_7, ((PyObject *)__pyx_cur_scope->__pyx_v_self));
+ __Pyx_GIVEREF(((PyObject *)__pyx_cur_scope->__pyx_v_self));
+ PyTuple_SET_ITEM(__pyx_t_8, 1+__pyx_t_7, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 708; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_3);
+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__pyx_r = __pyx_t_3;
__pyx_t_3 = 0;
@@ -9701,11 +8738,10 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_8SpecFile_10generator1(__pyx_Corou
__pyx_L6_resume_from_yield:;
__pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
__pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
- if (unlikely(!__pyx_sent_value)) __PYX_ERR(0, 704, __pyx_L1_error)
+ if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 708; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- CYTHON_MAYBE_UNUSED_VAR(__pyx_cur_scope);
- /* "silx/io/specfile.pyx":694
+ /* "silx/io/specfile.pyx":698
* return specfile_wrapper.SfScanNo(self.handle)
*
* def __iter__(self): # <<<<<<<<<<<<<<
@@ -9724,14 +8760,14 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_8SpecFile_10generator1(__pyx_Corou
__Pyx_XDECREF(__pyx_t_8);
__Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
__pyx_L0:;
- __Pyx_XDECREF(__pyx_r); __pyx_r = 0;
+ __Pyx_XDECREF(__pyx_r);
__pyx_generator->resume_label = -1;
- __Pyx_Coroutine_clear((PyObject*)__pyx_generator);
+ __Pyx_Generator_clear((PyObject*)__pyx_generator);
__Pyx_RefNannyFinishContext();
- return __pyx_r;
+ return NULL;
}
-/* "silx/io/specfile.pyx":706
+/* "silx/io/specfile.pyx":710
* yield Scan(self, scan_index)
*
* def __getitem__(self, key): # <<<<<<<<<<<<<<
@@ -9740,23 +8776,23 @@ static PyObject *__pyx_gb_4silx_2io_8specfile_8SpecFile_10generator1(__pyx_Corou
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_12__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_key); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_11__getitem__[] = "Return a :class:`Scan` object.\n\n This special method is called when a :class:`SpecFile` instance is\n accessed as a dictionary (e.g. ``sf[key]``).\n\n :param key: 0-based scan index or ``\"n.m\"`` key, where ``n`` is the scan\n number defined on the ``#S`` header line and ``m`` is the order\n :type key: int or str\n\n :return: Scan defined by its 0-based index or its ``\"n.m\"`` key\n :rtype: :class:`Scan`\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_14__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_key); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_13__getitem__[] = "Return a :class:`Scan` object.\n\n This special method is called when a :class:`SpecFile` instance is\n accessed as a dictionary (e.g. ``sf[key]``).\n\n :param key: 0-based scan index or ``\"n.m\"`` key, where ``n`` is the scan\n number defined on the ``#S`` header line and ``m`` is the order\n :type key: int or str\n\n :return: Scan defined by its 0-based index or its ``\"n.m\"`` key\n :rtype: :class:`Scan`\n ";
#if CYTHON_COMPILING_IN_CPYTHON
-struct wrapperbase __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_11__getitem__;
+struct wrapperbase __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_13__getitem__;
#endif
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_12__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_key) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_14__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_v_key) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_key));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_13__getitem__(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_key));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_key) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13__getitem__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_key) {
PyObject *__pyx_v_msg = NULL;
PyObject *__pyx_v_scan_index = NULL;
PyObject *__pyx_v_number = NULL;
@@ -9778,9 +8814,12 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
PyObject *__pyx_t_13 = NULL;
PyObject *__pyx_t_14 = NULL;
PyObject *__pyx_t_15 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__getitem__", 0);
- /* "silx/io/specfile.pyx":719
+ /* "silx/io/specfile.pyx":723
* :rtype: :class:`Scan`
* """
* msg = "The scan identification key can be an integer representing " # <<<<<<<<<<<<<<
@@ -9790,31 +8829,31 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
__Pyx_INCREF(__pyx_kp_s_The_scan_identification_key_can);
__pyx_v_msg = __pyx_kp_s_The_scan_identification_key_can;
- /* "silx/io/specfile.pyx":720
+ /* "silx/io/specfile.pyx":724
* """
* msg = "The scan identification key can be an integer representing "
* msg += "the unique scan index or a string 'N.M' with N being the scan" # <<<<<<<<<<<<<<
* msg += " number and M the order (eg '2.3')."
*
*/
- __pyx_t_1 = PyNumber_InPlaceAdd(__pyx_v_msg, __pyx_kp_s_the_unique_scan_index_or_a_strin); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 720, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_InPlaceAdd(__pyx_v_msg, __pyx_kp_s_the_unique_scan_index_or_a_strin); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 724; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF_SET(__pyx_v_msg, __pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":721
+ /* "silx/io/specfile.pyx":725
* msg = "The scan identification key can be an integer representing "
* msg += "the unique scan index or a string 'N.M' with N being the scan"
* msg += " number and M the order (eg '2.3')." # <<<<<<<<<<<<<<
*
* if isinstance(key, int):
*/
- __pyx_t_1 = PyNumber_InPlaceAdd(__pyx_v_msg, __pyx_kp_s_number_and_M_the_order_eg_2_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 721, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_InPlaceAdd(__pyx_v_msg, __pyx_kp_s_number_and_M_the_order_eg_2_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 725; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF_SET(__pyx_v_msg, __pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":723
+ /* "silx/io/specfile.pyx":727
* msg += " number and M the order (eg '2.3')."
*
* if isinstance(key, int): # <<<<<<<<<<<<<<
@@ -9825,7 +8864,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
__pyx_t_3 = (__pyx_t_2 != 0);
if (__pyx_t_3) {
- /* "silx/io/specfile.pyx":724
+ /* "silx/io/specfile.pyx":728
*
* if isinstance(key, int):
* scan_index = key # <<<<<<<<<<<<<<
@@ -9835,96 +8874,80 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
__Pyx_INCREF(__pyx_v_key);
__pyx_v_scan_index = __pyx_v_key;
- /* "silx/io/specfile.pyx":726
+ /* "silx/io/specfile.pyx":730
* scan_index = key
* # allow negative index, like lists
* if scan_index < 0: # <<<<<<<<<<<<<<
* scan_index = len(self) + scan_index
* else:
*/
- __pyx_t_1 = PyObject_RichCompare(__pyx_v_scan_index, __pyx_int_0, Py_LT); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 726, __pyx_L1_error)
- __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 726, __pyx_L1_error)
+ __pyx_t_1 = PyObject_RichCompare(__pyx_v_scan_index, __pyx_int_0, Py_LT); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 730; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 730; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
if (__pyx_t_3) {
- /* "silx/io/specfile.pyx":727
+ /* "silx/io/specfile.pyx":731
* # allow negative index, like lists
* if scan_index < 0:
* scan_index = len(self) + scan_index # <<<<<<<<<<<<<<
* else:
* try:
*/
- __pyx_t_4 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_4 == -1)) __PYX_ERR(0, 727, __pyx_L1_error)
- __pyx_t_1 = PyInt_FromSsize_t(__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 727, __pyx_L1_error)
+ __pyx_t_4 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 731; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_1 = PyInt_FromSsize_t(__pyx_t_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 731; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = PyNumber_Add(__pyx_t_1, __pyx_v_scan_index); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 727, __pyx_L1_error)
+ __pyx_t_5 = PyNumber_Add(__pyx_t_1, __pyx_v_scan_index); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 731; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF_SET(__pyx_v_scan_index, __pyx_t_5);
__pyx_t_5 = 0;
-
- /* "silx/io/specfile.pyx":726
- * scan_index = key
- * # allow negative index, like lists
- * if scan_index < 0: # <<<<<<<<<<<<<<
- * scan_index = len(self) + scan_index
- * else:
- */
+ goto __pyx_L4;
}
-
- /* "silx/io/specfile.pyx":723
- * msg += " number and M the order (eg '2.3')."
- *
- * if isinstance(key, int): # <<<<<<<<<<<<<<
- * scan_index = key
- * # allow negative index, like lists
- */
+ __pyx_L4:;
goto __pyx_L3;
}
+ /*else*/ {
- /* "silx/io/specfile.pyx":729
+ /* "silx/io/specfile.pyx":733
* scan_index = len(self) + scan_index
* else:
* try: # <<<<<<<<<<<<<<
* (number, order) = map(int, key.split("."))
* scan_index = self.index(number, order)
*/
- /*else*/ {
{
- __Pyx_PyThreadState_declare
- __Pyx_PyThreadState_assign
__Pyx_ExceptionSave(&__pyx_t_6, &__pyx_t_7, &__pyx_t_8);
__Pyx_XGOTREF(__pyx_t_6);
__Pyx_XGOTREF(__pyx_t_7);
__Pyx_XGOTREF(__pyx_t_8);
/*try:*/ {
- /* "silx/io/specfile.pyx":730
+ /* "silx/io/specfile.pyx":734
* else:
* try:
* (number, order) = map(int, key.split(".")) # <<<<<<<<<<<<<<
* scan_index = self.index(number, order)
* except (ValueError, SfErrScanNotFound, KeyError):
*/
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_key, __pyx_n_s_split); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 730, __pyx_L5_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_key, __pyx_n_s_split); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 734; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_tuple__26, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 730, __pyx_L5_error)
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_tuple__29, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 734; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 730, __pyx_L5_error)
+ __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 734; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
__Pyx_GOTREF(__pyx_t_5);
- __Pyx_INCREF(((PyObject *)(&PyInt_Type)));
- __Pyx_GIVEREF(((PyObject *)(&PyInt_Type)));
- PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)(&PyInt_Type)));
- __Pyx_GIVEREF(__pyx_t_1);
+ __Pyx_INCREF(((PyObject *)((PyObject*)(&PyInt_Type))));
+ PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)((PyObject*)(&PyInt_Type))));
+ __Pyx_GIVEREF(((PyObject *)((PyObject*)(&PyInt_Type))));
PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_1);
+ __Pyx_GIVEREF(__pyx_t_1);
__pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_map, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 730, __pyx_L5_error)
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_map, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 734; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) {
PyObject* sequence = __pyx_t_1;
- #if !CYTHON_COMPILING_IN_PYPY
+ #if CYTHON_COMPILING_IN_CPYTHON
Py_ssize_t size = Py_SIZE(sequence);
#else
Py_ssize_t size = PySequence_Size(sequence);
@@ -9932,9 +8955,9 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
if (unlikely(size != 2)) {
if (size > 2) __Pyx_RaiseTooManyValuesError(2);
else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
- __PYX_ERR(0, 730, __pyx_L5_error)
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 734; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
}
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+ #if CYTHON_COMPILING_IN_CPYTHON
if (likely(PyTuple_CheckExact(sequence))) {
__pyx_t_5 = PyTuple_GET_ITEM(sequence, 0);
__pyx_t_9 = PyTuple_GET_ITEM(sequence, 1);
@@ -9945,15 +8968,15 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
__Pyx_INCREF(__pyx_t_5);
__Pyx_INCREF(__pyx_t_9);
#else
- __pyx_t_5 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 730, __pyx_L5_error)
+ __pyx_t_5 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 734; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_9 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 730, __pyx_L5_error)
+ __pyx_t_9 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 734; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
__Pyx_GOTREF(__pyx_t_9);
#endif
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
} else {
Py_ssize_t index = -1;
- __pyx_t_10 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 730, __pyx_L5_error)
+ __pyx_t_10 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 734; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_11 = Py_TYPE(__pyx_t_10)->tp_iternext;
@@ -9961,7 +8984,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
__Pyx_GOTREF(__pyx_t_5);
index = 1; __pyx_t_9 = __pyx_t_11(__pyx_t_10); if (unlikely(!__pyx_t_9)) goto __pyx_L13_unpacking_failed;
__Pyx_GOTREF(__pyx_t_9);
- if (__Pyx_IternextUnpackEndCheck(__pyx_t_11(__pyx_t_10), 2) < 0) __PYX_ERR(0, 730, __pyx_L5_error)
+ if (__Pyx_IternextUnpackEndCheck(__pyx_t_11(__pyx_t_10), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 734; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
__pyx_t_11 = NULL;
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
goto __pyx_L14_unpacking_done;
@@ -9969,7 +8992,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__pyx_t_11 = NULL;
if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
- __PYX_ERR(0, 730, __pyx_L5_error)
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 734; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
__pyx_L14_unpacking_done:;
}
__pyx_v_number = __pyx_t_5;
@@ -9977,121 +9000,94 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
__pyx_v_order = __pyx_t_9;
__pyx_t_9 = 0;
- /* "silx/io/specfile.pyx":731
+ /* "silx/io/specfile.pyx":735
* try:
* (number, order) = map(int, key.split("."))
* scan_index = self.index(number, order) # <<<<<<<<<<<<<<
* except (ValueError, SfErrScanNotFound, KeyError):
* # int() can raise a value error
*/
- __pyx_t_9 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_index); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 731, __pyx_L5_error)
+ __pyx_t_9 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_index); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 735; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
__Pyx_GOTREF(__pyx_t_9);
__pyx_t_5 = NULL;
- __pyx_t_12 = 0;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_9))) {
+ __pyx_t_4 = 0;
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_9))) {
__pyx_t_5 = PyMethod_GET_SELF(__pyx_t_9);
if (likely(__pyx_t_5)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9);
__Pyx_INCREF(__pyx_t_5);
__Pyx_INCREF(function);
__Pyx_DECREF_SET(__pyx_t_9, function);
- __pyx_t_12 = 1;
+ __pyx_t_4 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_9)) {
- PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_number, __pyx_v_order};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_12, 2+__pyx_t_12); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 731, __pyx_L5_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) {
- PyObject *__pyx_temp[3] = {__pyx_t_5, __pyx_v_number, __pyx_v_order};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_12, 2+__pyx_t_12); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 731, __pyx_L5_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_10 = PyTuple_New(2+__pyx_t_12); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 731, __pyx_L5_error)
- __Pyx_GOTREF(__pyx_t_10);
- if (__pyx_t_5) {
- __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_5); __pyx_t_5 = NULL;
- }
- __Pyx_INCREF(__pyx_v_number);
- __Pyx_GIVEREF(__pyx_v_number);
- PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_12, __pyx_v_number);
- __Pyx_INCREF(__pyx_v_order);
- __Pyx_GIVEREF(__pyx_v_order);
- PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_12, __pyx_v_order);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_10, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 731, __pyx_L5_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+ __pyx_t_10 = PyTuple_New(2+__pyx_t_4); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 735; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
+ __Pyx_GOTREF(__pyx_t_10);
+ if (__pyx_t_5) {
+ PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_5); __Pyx_GIVEREF(__pyx_t_5); __pyx_t_5 = NULL;
}
+ __Pyx_INCREF(__pyx_v_number);
+ PyTuple_SET_ITEM(__pyx_t_10, 0+__pyx_t_4, __pyx_v_number);
+ __Pyx_GIVEREF(__pyx_v_number);
+ __Pyx_INCREF(__pyx_v_order);
+ PyTuple_SET_ITEM(__pyx_t_10, 1+__pyx_t_4, __pyx_v_order);
+ __Pyx_GIVEREF(__pyx_v_order);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_10, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 735; __pyx_clineno = __LINE__; goto __pyx_L5_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
__pyx_v_scan_index = __pyx_t_1;
__pyx_t_1 = 0;
-
- /* "silx/io/specfile.pyx":729
- * scan_index = len(self) + scan_index
- * else:
- * try: # <<<<<<<<<<<<<<
- * (number, order) = map(int, key.split("."))
- * scan_index = self.index(number, order)
- */
}
__Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
__Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
__Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
goto __pyx_L12_try_end;
__pyx_L5_error:;
- __Pyx_PyThreadState_assign
__Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
__Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
__Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":732
+ /* "silx/io/specfile.pyx":736
* (number, order) = map(int, key.split("."))
* scan_index = self.index(number, order)
* except (ValueError, SfErrScanNotFound, KeyError): # <<<<<<<<<<<<<<
* # int() can raise a value error
* raise KeyError(msg + "\nValid keys: '" +
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrScanNotFound); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 732, __pyx_L7_except_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrScanNotFound); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 736; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_12 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_ValueError) || __Pyx_PyErr_ExceptionMatches(__pyx_t_1) || __Pyx_PyErr_ExceptionMatches(__pyx_builtin_KeyError);
+ __pyx_t_12 = PyErr_ExceptionMatches(__pyx_builtin_ValueError) || PyErr_ExceptionMatches(__pyx_t_1) || PyErr_ExceptionMatches(__pyx_builtin_KeyError);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
if (__pyx_t_12) {
__Pyx_AddTraceback("silx.io.specfile.SpecFile.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- if (__Pyx_GetException(&__pyx_t_1, &__pyx_t_9, &__pyx_t_10) < 0) __PYX_ERR(0, 732, __pyx_L7_except_error)
+ if (__Pyx_GetException(&__pyx_t_1, &__pyx_t_9, &__pyx_t_10) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 736; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_GOTREF(__pyx_t_9);
__Pyx_GOTREF(__pyx_t_10);
- /* "silx/io/specfile.pyx":734
+ /* "silx/io/specfile.pyx":738
* except (ValueError, SfErrScanNotFound, KeyError):
* # int() can raise a value error
* raise KeyError(msg + "\nValid keys: '" + # <<<<<<<<<<<<<<
* "', '".join(self.keys()) + "'")
* except AttributeError:
*/
- __pyx_t_5 = PyNumber_Add(__pyx_v_msg, __pyx_kp_s_Valid_keys); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 734, __pyx_L7_except_error)
+ __pyx_t_5 = PyNumber_Add(__pyx_v_msg, __pyx_kp_s_Valid_keys); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 738; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_5);
- /* "silx/io/specfile.pyx":735
+ /* "silx/io/specfile.pyx":739
* # int() can raise a value error
* raise KeyError(msg + "\nValid keys: '" +
* "', '".join(self.keys()) + "'") # <<<<<<<<<<<<<<
* except AttributeError:
* # e.g. "AttrErr: 'float' object has no attribute 'split'"
*/
- __pyx_t_14 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_keys); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 735, __pyx_L7_except_error)
+ __pyx_t_14 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_keys); if (unlikely(!__pyx_t_14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 739; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_14);
__pyx_t_15 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_14))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_14))) {
__pyx_t_15 = PyMethod_GET_SELF(__pyx_t_14);
if (likely(__pyx_t_15)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_14);
@@ -10101,105 +9097,96 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
}
}
if (__pyx_t_15) {
- __pyx_t_13 = __Pyx_PyObject_CallOneArg(__pyx_t_14, __pyx_t_15); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 735, __pyx_L7_except_error)
+ __pyx_t_13 = __Pyx_PyObject_CallOneArg(__pyx_t_14, __pyx_t_15); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 739; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
} else {
- __pyx_t_13 = __Pyx_PyObject_CallNoArg(__pyx_t_14); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 735, __pyx_L7_except_error)
+ __pyx_t_13 = __Pyx_PyObject_CallNoArg(__pyx_t_14); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 739; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
}
__Pyx_GOTREF(__pyx_t_13);
__Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
- __pyx_t_14 = __Pyx_PyString_Join(__pyx_kp_s__27, __pyx_t_13); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 735, __pyx_L7_except_error)
+ __pyx_t_14 = __Pyx_PyString_Join(__pyx_kp_s__30, __pyx_t_13); if (unlikely(!__pyx_t_14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 739; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_14);
__Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
- /* "silx/io/specfile.pyx":734
+ /* "silx/io/specfile.pyx":738
* except (ValueError, SfErrScanNotFound, KeyError):
* # int() can raise a value error
* raise KeyError(msg + "\nValid keys: '" + # <<<<<<<<<<<<<<
* "', '".join(self.keys()) + "'")
* except AttributeError:
*/
- __pyx_t_13 = PyNumber_Add(__pyx_t_5, __pyx_t_14); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 734, __pyx_L7_except_error)
+ __pyx_t_13 = PyNumber_Add(__pyx_t_5, __pyx_t_14); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 738; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_13);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
- /* "silx/io/specfile.pyx":735
+ /* "silx/io/specfile.pyx":739
* # int() can raise a value error
* raise KeyError(msg + "\nValid keys: '" +
* "', '".join(self.keys()) + "'") # <<<<<<<<<<<<<<
* except AttributeError:
* # e.g. "AttrErr: 'float' object has no attribute 'split'"
*/
- __pyx_t_14 = PyNumber_Add(__pyx_t_13, __pyx_kp_s__28); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 735, __pyx_L7_except_error)
+ __pyx_t_14 = PyNumber_Add(__pyx_t_13, __pyx_kp_s__31); if (unlikely(!__pyx_t_14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 739; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_14);
__Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
- /* "silx/io/specfile.pyx":734
+ /* "silx/io/specfile.pyx":738
* except (ValueError, SfErrScanNotFound, KeyError):
* # int() can raise a value error
* raise KeyError(msg + "\nValid keys: '" + # <<<<<<<<<<<<<<
* "', '".join(self.keys()) + "'")
* except AttributeError:
*/
- __pyx_t_13 = PyTuple_New(1); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 734, __pyx_L7_except_error)
+ __pyx_t_13 = PyTuple_New(1); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 738; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_13);
- __Pyx_GIVEREF(__pyx_t_14);
PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_14);
+ __Pyx_GIVEREF(__pyx_t_14);
__pyx_t_14 = 0;
- __pyx_t_14 = __Pyx_PyObject_Call(__pyx_builtin_KeyError, __pyx_t_13, NULL); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 734, __pyx_L7_except_error)
+ __pyx_t_14 = __Pyx_PyObject_Call(__pyx_builtin_KeyError, __pyx_t_13, NULL); if (unlikely(!__pyx_t_14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 738; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_14);
__Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
__Pyx_Raise(__pyx_t_14, 0, 0, 0);
__Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
- __PYX_ERR(0, 734, __pyx_L7_except_error)
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 738; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
}
- /* "silx/io/specfile.pyx":736
+ /* "silx/io/specfile.pyx":740
* raise KeyError(msg + "\nValid keys: '" +
* "', '".join(self.keys()) + "'")
* except AttributeError: # <<<<<<<<<<<<<<
* # e.g. "AttrErr: 'float' object has no attribute 'split'"
* raise TypeError(msg)
*/
- __pyx_t_12 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_AttributeError);
+ __pyx_t_12 = PyErr_ExceptionMatches(__pyx_builtin_AttributeError);
if (__pyx_t_12) {
__Pyx_AddTraceback("silx.io.specfile.SpecFile.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- if (__Pyx_GetException(&__pyx_t_10, &__pyx_t_9, &__pyx_t_1) < 0) __PYX_ERR(0, 736, __pyx_L7_except_error)
+ if (__Pyx_GetException(&__pyx_t_10, &__pyx_t_9, &__pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 740; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_10);
__Pyx_GOTREF(__pyx_t_9);
__Pyx_GOTREF(__pyx_t_1);
- /* "silx/io/specfile.pyx":738
+ /* "silx/io/specfile.pyx":742
* except AttributeError:
* # e.g. "AttrErr: 'float' object has no attribute 'split'"
* raise TypeError(msg) # <<<<<<<<<<<<<<
*
* if not 0 <= scan_index < len(self):
*/
- __pyx_t_14 = PyTuple_New(1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 738, __pyx_L7_except_error)
+ __pyx_t_14 = PyTuple_New(1); if (unlikely(!__pyx_t_14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 742; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_14);
__Pyx_INCREF(__pyx_v_msg);
- __Pyx_GIVEREF(__pyx_v_msg);
PyTuple_SET_ITEM(__pyx_t_14, 0, __pyx_v_msg);
- __pyx_t_13 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_t_14, NULL); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 738, __pyx_L7_except_error)
+ __Pyx_GIVEREF(__pyx_v_msg);
+ __pyx_t_13 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_t_14, NULL); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 742; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
__Pyx_GOTREF(__pyx_t_13);
__Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
__Pyx_Raise(__pyx_t_13, 0, 0, 0);
__Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
- __PYX_ERR(0, 738, __pyx_L7_except_error)
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 742; __pyx_clineno = __LINE__; goto __pyx_L7_except_error;}
}
goto __pyx_L7_except_error;
__pyx_L7_except_error:;
-
- /* "silx/io/specfile.pyx":729
- * scan_index = len(self) + scan_index
- * else:
- * try: # <<<<<<<<<<<<<<
- * (number, order) = map(int, key.split("."))
- * scan_index = self.index(number, order)
- */
- __Pyx_PyThreadState_assign
__Pyx_XGIVEREF(__pyx_t_6);
__Pyx_XGIVEREF(__pyx_t_7);
__Pyx_XGIVEREF(__pyx_t_8);
@@ -10210,72 +9197,64 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
}
__pyx_L3:;
- /* "silx/io/specfile.pyx":740
+ /* "silx/io/specfile.pyx":744
* raise TypeError(msg)
*
* if not 0 <= scan_index < len(self): # <<<<<<<<<<<<<<
* msg = "Scan index must be in range 0-%d" % (len(self) - 1)
* raise IndexError(msg)
*/
- __pyx_t_1 = PyObject_RichCompare(__pyx_int_0, __pyx_v_scan_index, Py_LE); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 740, __pyx_L1_error)
+ __pyx_t_1 = PyObject_RichCompare(__pyx_int_0, __pyx_v_scan_index, Py_LE); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 744; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
if (__Pyx_PyObject_IsTrue(__pyx_t_1)) {
__Pyx_DECREF(__pyx_t_1);
- __pyx_t_4 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_4 == -1)) __PYX_ERR(0, 740, __pyx_L1_error)
- __pyx_t_9 = PyInt_FromSsize_t(__pyx_t_4); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 740, __pyx_L1_error)
+ __pyx_t_4 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 744; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_9 = PyInt_FromSsize_t(__pyx_t_4); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 744; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_9);
- __pyx_t_1 = PyObject_RichCompare(__pyx_v_scan_index, __pyx_t_9, Py_LT); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 740, __pyx_L1_error)
+ __pyx_t_1 = PyObject_RichCompare(__pyx_v_scan_index, __pyx_t_9, Py_LT); __Pyx_XGOTREF(__pyx_t_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 744; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
}
- __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 740, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_3 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 744; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_2 = ((!__pyx_t_3) != 0);
if (__pyx_t_2) {
- /* "silx/io/specfile.pyx":741
+ /* "silx/io/specfile.pyx":745
*
* if not 0 <= scan_index < len(self):
* msg = "Scan index must be in range 0-%d" % (len(self) - 1) # <<<<<<<<<<<<<<
* raise IndexError(msg)
*
*/
- __pyx_t_4 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_4 == -1)) __PYX_ERR(0, 741, __pyx_L1_error)
- __pyx_t_1 = PyInt_FromSsize_t((__pyx_t_4 - 1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 741, __pyx_L1_error)
+ __pyx_t_4 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 745; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_1 = PyInt_FromSsize_t((__pyx_t_4 - 1)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 745; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_9 = __Pyx_PyString_Format(__pyx_kp_s_Scan_index_must_be_in_range_0_d, __pyx_t_1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 741, __pyx_L1_error)
+ __pyx_t_9 = __Pyx_PyString_Format(__pyx_kp_s_Scan_index_must_be_in_range_0_d, __pyx_t_1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 745; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_9);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF_SET(__pyx_v_msg, __pyx_t_9);
__pyx_t_9 = 0;
- /* "silx/io/specfile.pyx":742
+ /* "silx/io/specfile.pyx":746
* if not 0 <= scan_index < len(self):
* msg = "Scan index must be in range 0-%d" % (len(self) - 1)
* raise IndexError(msg) # <<<<<<<<<<<<<<
*
* return Scan(self, scan_index)
*/
- __pyx_t_9 = PyTuple_New(1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 742, __pyx_L1_error)
+ __pyx_t_9 = PyTuple_New(1); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 746; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_9);
__Pyx_INCREF(__pyx_v_msg);
- __Pyx_GIVEREF(__pyx_v_msg);
PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_v_msg);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_IndexError, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 742, __pyx_L1_error)
+ __Pyx_GIVEREF(__pyx_v_msg);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_IndexError, __pyx_t_9, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 746; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
__Pyx_Raise(__pyx_t_1, 0, 0, 0);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __PYX_ERR(0, 742, __pyx_L1_error)
-
- /* "silx/io/specfile.pyx":740
- * raise TypeError(msg)
- *
- * if not 0 <= scan_index < len(self): # <<<<<<<<<<<<<<
- * msg = "Scan index must be in range 0-%d" % (len(self) - 1)
- * raise IndexError(msg)
- */
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 746; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- /* "silx/io/specfile.pyx":744
+ /* "silx/io/specfile.pyx":748
* raise IndexError(msg)
*
* return Scan(self, scan_index) # <<<<<<<<<<<<<<
@@ -10283,58 +9262,40 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
* def keys(self):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_Scan); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 744, __pyx_L1_error)
+ __pyx_t_9 = __Pyx_GetModuleGlobalName(__pyx_n_s_Scan); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 748; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_9);
__pyx_t_10 = NULL;
- __pyx_t_12 = 0;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) {
+ __pyx_t_4 = 0;
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_9))) {
__pyx_t_10 = PyMethod_GET_SELF(__pyx_t_9);
if (likely(__pyx_t_10)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9);
__Pyx_INCREF(__pyx_t_10);
__Pyx_INCREF(function);
__Pyx_DECREF_SET(__pyx_t_9, function);
- __pyx_t_12 = 1;
+ __pyx_t_4 = 1;
}
}
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_9)) {
- PyObject *__pyx_temp[3] = {__pyx_t_10, ((PyObject *)__pyx_v_self), __pyx_v_scan_index};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_12, 2+__pyx_t_12); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 744, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_9)) {
- PyObject *__pyx_temp[3] = {__pyx_t_10, ((PyObject *)__pyx_v_self), __pyx_v_scan_index};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_9, __pyx_temp+1-__pyx_t_12, 2+__pyx_t_12); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 744, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_13 = PyTuple_New(2+__pyx_t_12); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 744, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_13);
- if (__pyx_t_10) {
- __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_10); __pyx_t_10 = NULL;
- }
- __Pyx_INCREF(((PyObject *)__pyx_v_self));
- __Pyx_GIVEREF(((PyObject *)__pyx_v_self));
- PyTuple_SET_ITEM(__pyx_t_13, 0+__pyx_t_12, ((PyObject *)__pyx_v_self));
- __Pyx_INCREF(__pyx_v_scan_index);
- __Pyx_GIVEREF(__pyx_v_scan_index);
- PyTuple_SET_ITEM(__pyx_t_13, 1+__pyx_t_12, __pyx_v_scan_index);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_13, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 744, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
+ __pyx_t_13 = PyTuple_New(2+__pyx_t_4); if (unlikely(!__pyx_t_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 748; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_13);
+ if (__pyx_t_10) {
+ PyTuple_SET_ITEM(__pyx_t_13, 0, __pyx_t_10); __Pyx_GIVEREF(__pyx_t_10); __pyx_t_10 = NULL;
}
+ __Pyx_INCREF(((PyObject *)__pyx_v_self));
+ PyTuple_SET_ITEM(__pyx_t_13, 0+__pyx_t_4, ((PyObject *)__pyx_v_self));
+ __Pyx_GIVEREF(((PyObject *)__pyx_v_self));
+ __Pyx_INCREF(__pyx_v_scan_index);
+ PyTuple_SET_ITEM(__pyx_t_13, 1+__pyx_t_4, __pyx_v_scan_index);
+ __Pyx_GIVEREF(__pyx_v_scan_index);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_t_13, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 748; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":706
+ /* "silx/io/specfile.pyx":710
* yield Scan(self, scan_index)
*
* def __getitem__(self, key): # <<<<<<<<<<<<<<
@@ -10363,7 +9324,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
return __pyx_r;
}
-/* "silx/io/specfile.pyx":746
+/* "silx/io/specfile.pyx":750
* return Scan(self, scan_index)
*
* def keys(self): # <<<<<<<<<<<<<<
@@ -10372,20 +9333,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_11__getitem__(struct __p
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_14keys(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_13keys[] = "SpecFile.keys(self)\nReturns list of scan keys (eg ``['1.1', '2.1',...]``).\n\n :return: list of scan keys\n :rtype: list of strings\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_14keys(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_16keys(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_15keys[] = "SpecFile.keys(self)\nReturns list of scan keys (eg ``['1.1', '2.1',...]``).\n\n :return: list of scan keys\n :rtype: list of strings\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_16keys(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("keys (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_15keys(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_15keys(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
PyObject *__pyx_v_ret_list = NULL;
PyObject *__pyx_v_list_of_numbers = NULL;
PyObject *__pyx_v_count = NULL;
@@ -10401,31 +9362,34 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(struct __pyx_obj_
int __pyx_t_7;
PyObject *__pyx_t_8 = NULL;
int __pyx_t_9;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("keys", 0);
- /* "silx/io/specfile.pyx":752
+ /* "silx/io/specfile.pyx":756
* :rtype: list of strings
* """
* ret_list = [] # <<<<<<<<<<<<<<
* list_of_numbers = self._list()
* count = {}
*/
- __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 752, __pyx_L1_error)
+ __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 756; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_v_ret_list = ((PyObject*)__pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":753
+ /* "silx/io/specfile.pyx":757
* """
* ret_list = []
* list_of_numbers = self._list() # <<<<<<<<<<<<<<
* count = {}
*
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_list); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 753, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_list); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 757; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_3 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -10435,29 +9399,29 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(struct __pyx_obj_
}
}
if (__pyx_t_3) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 753, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 757; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
} else {
- __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 753, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 757; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_v_list_of_numbers = __pyx_t_1;
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":754
+ /* "silx/io/specfile.pyx":758
* ret_list = []
* list_of_numbers = self._list()
* count = {} # <<<<<<<<<<<<<<
*
* for number in list_of_numbers:
*/
- __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 754, __pyx_L1_error)
+ __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 758; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_v_count = ((PyObject*)__pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":756
+ /* "silx/io/specfile.pyx":760
* count = {}
*
* for number in list_of_numbers: # <<<<<<<<<<<<<<
@@ -10468,27 +9432,25 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(struct __pyx_obj_
__pyx_t_1 = __pyx_v_list_of_numbers; __Pyx_INCREF(__pyx_t_1); __pyx_t_4 = 0;
__pyx_t_5 = NULL;
} else {
- __pyx_t_4 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_list_of_numbers); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 756, __pyx_L1_error)
+ __pyx_t_4 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_list_of_numbers); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 760; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 756, __pyx_L1_error)
+ __pyx_t_5 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 760; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
for (;;) {
if (likely(!__pyx_t_5)) {
if (likely(PyList_CheckExact(__pyx_t_1))) {
if (__pyx_t_4 >= PyList_GET_SIZE(__pyx_t_1)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) __PYX_ERR(0, 756, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 760; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 756, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
+ __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 760; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
} else {
if (__pyx_t_4 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) __PYX_ERR(0, 756, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_4); __Pyx_INCREF(__pyx_t_2); __pyx_t_4++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 760; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 756, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
+ __pyx_t_2 = PySequence_ITEM(__pyx_t_1, __pyx_t_4); __pyx_t_4++; if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 760; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
}
} else {
@@ -10497,7 +9459,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(struct __pyx_obj_
PyObject* exc_type = PyErr_Occurred();
if (exc_type) {
if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
- else __PYX_ERR(0, 756, __pyx_L1_error)
+ else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 760; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
break;
}
@@ -10506,81 +9468,73 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(struct __pyx_obj_
__Pyx_XDECREF_SET(__pyx_v_number, __pyx_t_2);
__pyx_t_2 = 0;
- /* "silx/io/specfile.pyx":757
+ /* "silx/io/specfile.pyx":761
*
* for number in list_of_numbers:
* if number not in count: # <<<<<<<<<<<<<<
* count[number] = 1
* else:
*/
- __pyx_t_6 = (__Pyx_PyDict_ContainsTF(__pyx_v_number, __pyx_v_count, Py_NE)); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 757, __pyx_L1_error)
+ __pyx_t_6 = (__Pyx_PyDict_Contains(__pyx_v_number, __pyx_v_count, Py_NE)); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 761; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_t_7 = (__pyx_t_6 != 0);
if (__pyx_t_7) {
- /* "silx/io/specfile.pyx":758
+ /* "silx/io/specfile.pyx":762
* for number in list_of_numbers:
* if number not in count:
* count[number] = 1 # <<<<<<<<<<<<<<
* else:
* count[number] += 1
*/
- if (unlikely(PyDict_SetItem(__pyx_v_count, __pyx_v_number, __pyx_int_1) < 0)) __PYX_ERR(0, 758, __pyx_L1_error)
-
- /* "silx/io/specfile.pyx":757
- *
- * for number in list_of_numbers:
- * if number not in count: # <<<<<<<<<<<<<<
- * count[number] = 1
- * else:
- */
+ if (unlikely(PyDict_SetItem(__pyx_v_count, __pyx_v_number, __pyx_int_1) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 762; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
goto __pyx_L5;
}
+ /*else*/ {
- /* "silx/io/specfile.pyx":760
+ /* "silx/io/specfile.pyx":764
* count[number] = 1
* else:
* count[number] += 1 # <<<<<<<<<<<<<<
* ret_list.append(u'%d.%d' % (number, count[number]))
*
*/
- /*else*/ {
__Pyx_INCREF(__pyx_v_number);
__pyx_t_2 = __pyx_v_number;
- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_count, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 760, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_count, __pyx_t_2); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 764; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_8 = __Pyx_PyInt_AddObjC(__pyx_t_3, __pyx_int_1, 1, 1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 760, __pyx_L1_error)
+ __pyx_t_8 = PyNumber_InPlaceAdd(__pyx_t_3, __pyx_int_1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 764; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_8);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- if (unlikely(PyDict_SetItem(__pyx_v_count, __pyx_t_2, __pyx_t_8) < 0)) __PYX_ERR(0, 760, __pyx_L1_error)
+ if (unlikely(PyDict_SetItem(__pyx_v_count, __pyx_t_2, __pyx_t_8) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 764; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
}
__pyx_L5:;
- /* "silx/io/specfile.pyx":761
+ /* "silx/io/specfile.pyx":765
* else:
* count[number] += 1
* ret_list.append(u'%d.%d' % (number, count[number])) # <<<<<<<<<<<<<<
*
* return ret_list
*/
- __pyx_t_2 = __Pyx_PyDict_GetItem(__pyx_v_count, __pyx_v_number); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 761, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyDict_GetItem(__pyx_v_count, __pyx_v_number); if (unlikely(__pyx_t_2 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 765; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 761, __pyx_L1_error)
+ __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 765; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_8);
__Pyx_INCREF(__pyx_v_number);
- __Pyx_GIVEREF(__pyx_v_number);
PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_v_number);
- __Pyx_GIVEREF(__pyx_t_2);
+ __Pyx_GIVEREF(__pyx_v_number);
PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = PyUnicode_Format(__pyx_kp_u_d_d, __pyx_t_8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 761, __pyx_L1_error)
+ __pyx_t_2 = PyUnicode_Format(__pyx_kp_u_d_d, __pyx_t_8); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 765; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- __pyx_t_9 = __Pyx_PyList_Append(__pyx_v_ret_list, __pyx_t_2); if (unlikely(__pyx_t_9 == -1)) __PYX_ERR(0, 761, __pyx_L1_error)
+ __pyx_t_9 = __Pyx_PyList_Append(__pyx_v_ret_list, __pyx_t_2); if (unlikely(__pyx_t_9 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 765; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- /* "silx/io/specfile.pyx":756
+ /* "silx/io/specfile.pyx":760
* count = {}
*
* for number in list_of_numbers: # <<<<<<<<<<<<<<
@@ -10590,7 +9544,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(struct __pyx_obj_
}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":763
+ /* "silx/io/specfile.pyx":767
* ret_list.append(u'%d.%d' % (number, count[number]))
*
* return ret_list # <<<<<<<<<<<<<<
@@ -10602,7 +9556,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(struct __pyx_obj_
__pyx_r = __pyx_v_ret_list;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":746
+ /* "silx/io/specfile.pyx":750
* return Scan(self, scan_index)
*
* def keys(self): # <<<<<<<<<<<<<<
@@ -10628,7 +9582,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(struct __pyx_obj_
return __pyx_r;
}
-/* "silx/io/specfile.pyx":765
+/* "silx/io/specfile.pyx":769
* return ret_list
*
* def __contains__(self, key): # <<<<<<<<<<<<<<
@@ -10637,23 +9591,23 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_13keys(struct __pyx_obj_
*/
/* Python wrapper */
-static int __pyx_pw_4silx_2io_8specfile_8SpecFile_16__contains__(PyObject *__pyx_v_self, PyObject *__pyx_v_key); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_15__contains__[] = "Return ``True`` if ``key`` is a valid scan key.\n Valid keys can be a string such as ``\"1.1\"`` or a 0-based scan index.\n ";
+static int __pyx_pw_4silx_2io_8specfile_8SpecFile_18__contains__(PyObject *__pyx_v_self, PyObject *__pyx_v_key); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_17__contains__[] = "Return ``True`` if ``key`` is a valid scan key.\n Valid keys can be a string such as ``\"1.1\"`` or a 0-based scan index.\n ";
#if CYTHON_COMPILING_IN_CPYTHON
-struct wrapperbase __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_15__contains__;
+struct wrapperbase __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_17__contains__;
#endif
-static int __pyx_pw_4silx_2io_8specfile_8SpecFile_16__contains__(PyObject *__pyx_v_self, PyObject *__pyx_v_key) {
+static int __pyx_pw_4silx_2io_8specfile_8SpecFile_18__contains__(PyObject *__pyx_v_self, PyObject *__pyx_v_key) {
int __pyx_r;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("__contains__ (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_15__contains__(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_key));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_17__contains__(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_key));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static int __pyx_pf_4silx_2io_8specfile_8SpecFile_15__contains__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_key) {
+static int __pyx_pf_4silx_2io_8specfile_8SpecFile_17__contains__(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_key) {
int __pyx_r;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
@@ -10661,19 +9615,22 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile_15__contains__(struct __pyx_ob
PyObject *__pyx_t_3 = NULL;
Py_ssize_t __pyx_t_4;
int __pyx_t_5;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__contains__", 0);
- /* "silx/io/specfile.pyx":769
+ /* "silx/io/specfile.pyx":773
* Valid keys can be a string such as ``"1.1"`` or a 0-based scan index.
* """
* return key in (self.keys() + list(range(len(self)))) # <<<<<<<<<<<<<<
*
* def _get_error_string(self, error_code):
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_keys); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 769, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_keys); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 773; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_3 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -10683,37 +9640,42 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile_15__contains__(struct __pyx_ob
}
}
if (__pyx_t_3) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 769, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 773; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
} else {
- __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 769, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 773; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_4 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_4 == -1)) __PYX_ERR(0, 769, __pyx_L1_error)
- __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 769, __pyx_L1_error)
+ __pyx_t_4 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 773; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_4); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 773; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 769, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 773; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_range, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 769, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_range, __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 773; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_3 = PySequence_List(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 769, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 773; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = PyNumber_Add(__pyx_t_1, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 769, __pyx_L1_error)
+ PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
+ __pyx_t_2 = 0;
+ __pyx_t_2 = __Pyx_PyObject_Call(((PyObject *)((PyObject*)(&PyList_Type))), __pyx_t_3, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 773; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_5 = (__Pyx_PySequence_ContainsTF(__pyx_v_key, __pyx_t_2, Py_EQ)); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 769, __pyx_L1_error)
+ __pyx_t_3 = PyNumber_Add(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 773; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_3);
+ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+ __pyx_t_5 = (__Pyx_PySequence_Contains(__pyx_v_key, __pyx_t_3, Py_EQ)); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 773; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_r = __pyx_t_5;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":765
+ /* "silx/io/specfile.pyx":769
* return ret_list
*
* def __contains__(self, key): # <<<<<<<<<<<<<<
@@ -10733,7 +9695,7 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile_15__contains__(struct __pyx_ob
return __pyx_r;
}
-/* "silx/io/specfile.pyx":771
+/* "silx/io/specfile.pyx":775
* return key in (self.keys() + list(range(len(self))))
*
* def _get_error_string(self, error_code): # <<<<<<<<<<<<<<
@@ -10742,28 +9704,31 @@ static int __pyx_pf_4silx_2io_8specfile_8SpecFile_15__contains__(struct __pyx_ob
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_18_get_error_string(PyObject *__pyx_v_self, PyObject *__pyx_v_error_code); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_17_get_error_string[] = "SpecFile._get_error_string(self, error_code)\nReturns the error message corresponding to the error code.\n\n :param code: Error code\n :type code: int\n :return: Human readable error message\n :rtype: str\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_18_get_error_string(PyObject *__pyx_v_self, PyObject *__pyx_v_error_code) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_20_get_error_string(PyObject *__pyx_v_self, PyObject *__pyx_v_error_code); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_19_get_error_string[] = "SpecFile._get_error_string(self, error_code)\nReturns the error message corresponding to the error code.\n\n :param code: Error code\n :type code: int\n :return: Human readable error message\n :rtype: str\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_20_get_error_string(PyObject *__pyx_v_self, PyObject *__pyx_v_error_code) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("_get_error_string (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_17_get_error_string(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_error_code));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_19_get_error_string(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_error_code));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_17_get_error_string(CYTHON_UNUSED struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_error_code) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_19_get_error_string(CYTHON_UNUSED struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_error_code) {
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
int __pyx_t_1;
PyObject *__pyx_t_2 = NULL;
PyObject *__pyx_t_3 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("_get_error_string", 0);
- /* "silx/io/specfile.pyx":779
+ /* "silx/io/specfile.pyx":783
* :rtype: str
* """
* return (<bytes> specfile_wrapper.SfError(error_code)).decode() # <<<<<<<<<<<<<<
@@ -10771,21 +9736,21 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_17_get_error_string(CYTH
* def _handle_error(self, error_code):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyInt_As_int(__pyx_v_error_code); if (unlikely((__pyx_t_1 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 779, __pyx_L1_error)
- __pyx_t_2 = __Pyx_PyBytes_FromString(SfError(__pyx_t_1)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 779, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyInt_As_int(__pyx_v_error_code); if (unlikely((__pyx_t_1 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 783; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_2 = __Pyx_PyBytes_FromString(SfError(__pyx_t_1)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 783; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
if (unlikely(__pyx_t_2 == Py_None)) {
PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", "decode");
- __PYX_ERR(0, 779, __pyx_L1_error)
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 783; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- __pyx_t_3 = __Pyx_decode_bytes(((PyObject*)__pyx_t_2), 0, PY_SSIZE_T_MAX, NULL, NULL, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 779, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_decode_bytes(((PyObject*)__pyx_t_2), 0, PY_SSIZE_T_MAX, NULL, NULL, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 783; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_r = __pyx_t_3;
__pyx_t_3 = 0;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":771
+ /* "silx/io/specfile.pyx":775
* return key in (self.keys() + list(range(len(self))))
*
* def _get_error_string(self, error_code): # <<<<<<<<<<<<<<
@@ -10805,7 +9770,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_17_get_error_string(CYTH
return __pyx_r;
}
-/* "silx/io/specfile.pyx":781
+/* "silx/io/specfile.pyx":785
* return (<bytes> specfile_wrapper.SfError(error_code)).decode()
*
* def _handle_error(self, error_code): # <<<<<<<<<<<<<<
@@ -10814,20 +9779,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_17_get_error_string(CYTH
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_20_handle_error(PyObject *__pyx_v_self, PyObject *__pyx_v_error_code); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_19_handle_error[] = "SpecFile._handle_error(self, error_code)\nInspect error code, raise adequate error type if necessary.\n\n :param code: Error code\n :type code: int\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_20_handle_error(PyObject *__pyx_v_self, PyObject *__pyx_v_error_code) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_22_handle_error(PyObject *__pyx_v_self, PyObject *__pyx_v_error_code); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_21_handle_error[] = "SpecFile._handle_error(self, error_code)\nInspect error code, raise adequate error type if necessary.\n\n :param code: Error code\n :type code: int\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_22_handle_error(PyObject *__pyx_v_self, PyObject *__pyx_v_error_code) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("_handle_error (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_19_handle_error(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_error_code));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_21_handle_error(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_error_code));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_19_handle_error(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_error_code) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_21_handle_error(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_error_code) {
PyObject *__pyx_v_error_message = NULL;
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
@@ -10837,19 +9802,22 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_19_handle_error(struct _
PyObject *__pyx_t_4 = NULL;
int __pyx_t_5;
int __pyx_t_6;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("_handle_error", 0);
- /* "silx/io/specfile.pyx":787
+ /* "silx/io/specfile.pyx":791
* :type code: int
* """
* error_message = self._get_error_string(error_code) # <<<<<<<<<<<<<<
* if error_code in ERRORS:
* raise ERRORS[error_code](error_message)
*/
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_get_error_string); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 787, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_get_error_string); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 791; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_3 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -10859,69 +9827,51 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_19_handle_error(struct _
}
}
if (!__pyx_t_3) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_error_code); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 787, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_error_code); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 791; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_error_code};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 787, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
- PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_v_error_code};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 787, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 787, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __pyx_t_3 = NULL;
- __Pyx_INCREF(__pyx_v_error_code);
- __Pyx_GIVEREF(__pyx_v_error_code);
- PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_error_code);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 787, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- }
+ __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 791; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); __Pyx_GIVEREF(__pyx_t_3); __pyx_t_3 = NULL;
+ __Pyx_INCREF(__pyx_v_error_code);
+ PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_v_error_code);
+ __Pyx_GIVEREF(__pyx_v_error_code);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_4, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 791; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_v_error_message = __pyx_t_1;
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":788
+ /* "silx/io/specfile.pyx":792
* """
* error_message = self._get_error_string(error_code)
* if error_code in ERRORS: # <<<<<<<<<<<<<<
* raise ERRORS[error_code](error_message)
*
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 788, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 792; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = (__Pyx_PySequence_ContainsTF(__pyx_v_error_code, __pyx_t_1, Py_EQ)); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 788, __pyx_L1_error)
+ __pyx_t_5 = (__Pyx_PySequence_Contains(__pyx_v_error_code, __pyx_t_1, Py_EQ)); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 792; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_6 = (__pyx_t_5 != 0);
if (__pyx_t_6) {
- /* "silx/io/specfile.pyx":789
+ /* "silx/io/specfile.pyx":793
* error_message = self._get_error_string(error_code)
* if error_code in ERRORS:
* raise ERRORS[error_code](error_message) # <<<<<<<<<<<<<<
*
* def index(self, scan_number, scan_order=1):
*/
- __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_ERRORS); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 789, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_ERRORS); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 793; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_4 = PyObject_GetItem(__pyx_t_2, __pyx_v_error_code); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 789, __pyx_L1_error)
+ __pyx_t_4 = PyObject_GetItem(__pyx_t_2, __pyx_v_error_code); if (unlikely(__pyx_t_4 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 793; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_2 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_2 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_2)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -10931,52 +9881,26 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_19_handle_error(struct _
}
}
if (!__pyx_t_2) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_v_error_message); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 789, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_v_error_message); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 793; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_v_error_message};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 789, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_v_error_message};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 789, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 789, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); __pyx_t_2 = NULL;
- __Pyx_INCREF(__pyx_v_error_message);
- __Pyx_GIVEREF(__pyx_v_error_message);
- PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_v_error_message);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_3, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 789, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- }
+ __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 793; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_3);
+ PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); __pyx_t_2 = NULL;
+ __Pyx_INCREF(__pyx_v_error_message);
+ PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_v_error_message);
+ __Pyx_GIVEREF(__pyx_v_error_message);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_3, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 793; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_Raise(__pyx_t_1, 0, 0, 0);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __PYX_ERR(0, 789, __pyx_L1_error)
-
- /* "silx/io/specfile.pyx":788
- * """
- * error_message = self._get_error_string(error_code)
- * if error_code in ERRORS: # <<<<<<<<<<<<<<
- * raise ERRORS[error_code](error_message)
- *
- */
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 793; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- /* "silx/io/specfile.pyx":781
+ /* "silx/io/specfile.pyx":785
* return (<bytes> specfile_wrapper.SfError(error_code)).decode()
*
* def _handle_error(self, error_code): # <<<<<<<<<<<<<<
@@ -11001,7 +9925,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_19_handle_error(struct _
return __pyx_r;
}
-/* "silx/io/specfile.pyx":791
+/* "silx/io/specfile.pyx":795
* raise ERRORS[error_code](error_message)
*
* def index(self, scan_number, scan_order=1): # <<<<<<<<<<<<<<
@@ -11010,11 +9934,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_19_handle_error(struct _
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_22index(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_21index[] = "SpecFile.index(self, scan_number, scan_order=1)\nReturns scan index from scan number and order.\n\n :param scan_number: Scan number (possibly non-unique).\n :type scan_number: int\n :param scan_order: Scan order.\n :type scan_order: int default 1\n\n :return: Unique scan index\n :rtype: int\n\n\n Scan indices are increasing from ``0`` to ``len(self)-1`` in the\n order in which they appear in the file.\n Scan numbers are defined by users and are not necessarily unique.\n The scan order for a given scan number increments each time the scan\n number appears in a given file.\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_22index(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_24index(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_23index[] = "SpecFile.index(self, scan_number, scan_order=1)\nReturns scan index from scan number and order.\n\n :param scan_number: Scan number (possibly non-unique).\n :type scan_number: int\n :param scan_order: Scan order.\n :type scan_order: int default 1\n\n :return: Unique scan index\n :rtype: int\n\n\n Scan indices are increasing from ``0`` to ``len(self)-1`` in the\n order in which they appear in the file.\n Scan numbers are defined by users and are not necessarily unique.\n The scan order for a given scan number increments each time the scan\n number appears in a given file.\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_24index(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_scan_number = 0;
PyObject *__pyx_v_scan_order = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("index (wrapper)", 0);
@@ -11043,7 +9970,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_22index(PyObject *__pyx_
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "index") < 0)) __PYX_ERR(0, 791, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "index") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 795; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else {
switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -11058,20 +9985,20 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_22index(PyObject *__pyx_
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("index", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 791, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("index", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 795; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.SpecFile.index", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
return NULL;
__pyx_L4_argument_unpacking_done:;
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_21index(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_number, __pyx_v_scan_order);
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_23index(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_number, __pyx_v_scan_order);
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_21index(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_number, PyObject *__pyx_v_scan_order) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_23index(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_number, PyObject *__pyx_v_scan_order) {
PyObject *__pyx_v_idx = NULL;
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
@@ -11083,48 +10010,50 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_21index(struct __pyx_obj
PyObject *__pyx_t_6 = NULL;
PyObject *__pyx_t_7 = NULL;
PyObject *__pyx_t_8 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("index", 0);
- /* "silx/io/specfile.pyx":809
+ /* "silx/io/specfile.pyx":813
* number appears in a given file.
* """
* idx = specfile_wrapper.SfIndex(self.handle, scan_number, scan_order) # <<<<<<<<<<<<<<
* if idx == -1:
* self._handle_error(SF_ERR_SCAN_NOT_FOUND)
*/
- __pyx_t_1 = __Pyx_PyInt_As_long(__pyx_v_scan_number); if (unlikely((__pyx_t_1 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 809, __pyx_L1_error)
- __pyx_t_2 = __Pyx_PyInt_As_long(__pyx_v_scan_order); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 809, __pyx_L1_error)
- __pyx_t_3 = __Pyx_PyInt_From_long(SfIndex(__pyx_v_self->handle, __pyx_t_1, __pyx_t_2)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 809, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyInt_As_long(__pyx_v_scan_number); if (unlikely((__pyx_t_1 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 813; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_2 = __Pyx_PyInt_As_long(__pyx_v_scan_order); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 813; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_3 = __Pyx_PyInt_From_long(SfIndex(__pyx_v_self->handle, __pyx_t_1, __pyx_t_2)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 813; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__pyx_v_idx = __pyx_t_3;
__pyx_t_3 = 0;
- /* "silx/io/specfile.pyx":810
+ /* "silx/io/specfile.pyx":814
* """
* idx = specfile_wrapper.SfIndex(self.handle, scan_number, scan_order)
* if idx == -1: # <<<<<<<<<<<<<<
* self._handle_error(SF_ERR_SCAN_NOT_FOUND)
* return idx - 1
*/
- __pyx_t_3 = __Pyx_PyInt_EqObjC(__pyx_v_idx, __pyx_int_neg_1, -1L, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 810, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 810, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_v_idx, __pyx_int_neg_1, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 814; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 814; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_4) {
- /* "silx/io/specfile.pyx":811
+ /* "silx/io/specfile.pyx":815
* idx = specfile_wrapper.SfIndex(self.handle, scan_number, scan_order)
* if idx == -1:
* self._handle_error(SF_ERR_SCAN_NOT_FOUND) # <<<<<<<<<<<<<<
* return idx - 1
*
*/
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 811, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 815; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_SCAN_NOT_FOUND); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 811, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_SCAN_NOT_FOUND); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 815; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__pyx_t_7 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_5))) {
__pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5);
if (likely(__pyx_t_7)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
@@ -11134,53 +10063,27 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_21index(struct __pyx_obj
}
}
if (!__pyx_t_7) {
- __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 811, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 815; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
__Pyx_GOTREF(__pyx_t_3);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_6};
- __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 811, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_6};
- __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 811, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- } else
- #endif
- {
- __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 811, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL;
- __Pyx_GIVEREF(__pyx_t_6);
- PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_6);
- __pyx_t_6 = 0;
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 811, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- }
+ __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 815; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
+ PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __Pyx_GIVEREF(__pyx_t_7); __pyx_t_7 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_6);
+ __Pyx_GIVEREF(__pyx_t_6);
+ __pyx_t_6 = 0;
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_8, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 815; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_3);
+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-
- /* "silx/io/specfile.pyx":810
- * """
- * idx = specfile_wrapper.SfIndex(self.handle, scan_number, scan_order)
- * if idx == -1: # <<<<<<<<<<<<<<
- * self._handle_error(SF_ERR_SCAN_NOT_FOUND)
- * return idx - 1
- */
+ goto __pyx_L3;
}
+ __pyx_L3:;
- /* "silx/io/specfile.pyx":812
+ /* "silx/io/specfile.pyx":816
* if idx == -1:
* self._handle_error(SF_ERR_SCAN_NOT_FOUND)
* return idx - 1 # <<<<<<<<<<<<<<
@@ -11188,13 +10091,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_21index(struct __pyx_obj
* def number(self, scan_index):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_3 = __Pyx_PyInt_SubtractObjC(__pyx_v_idx, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 812, __pyx_L1_error)
+ __pyx_t_3 = PyNumber_Subtract(__pyx_v_idx, __pyx_int_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 816; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__pyx_r = __pyx_t_3;
__pyx_t_3 = 0;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":791
+ /* "silx/io/specfile.pyx":795
* raise ERRORS[error_code](error_message)
*
* def index(self, scan_number, scan_order=1): # <<<<<<<<<<<<<<
@@ -11218,7 +10121,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_21index(struct __pyx_obj
return __pyx_r;
}
-/* "silx/io/specfile.pyx":814
+/* "silx/io/specfile.pyx":818
* return idx - 1
*
* def number(self, scan_index): # <<<<<<<<<<<<<<
@@ -11227,20 +10130,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_21index(struct __pyx_obj
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_24number(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_23number[] = "SpecFile.number(self, scan_index)\nReturns scan number from scan index.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: User defined scan number.\n :rtype: int\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_24number(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_26number(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_25number[] = "SpecFile.number(self, scan_index)\nReturns scan number from scan index.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: User defined scan number.\n :rtype: int\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_26number(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("number (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_23number(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_25number(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_23number(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_25number(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
long __pyx_v_idx;
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
@@ -11251,44 +10154,47 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_23number(struct __pyx_ob
PyObject *__pyx_t_5 = NULL;
PyObject *__pyx_t_6 = NULL;
PyObject *__pyx_t_7 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("number", 0);
- /* "silx/io/specfile.pyx":824
+ /* "silx/io/specfile.pyx":828
* :rtype: int
* """
* idx = specfile_wrapper.SfNumber(self.handle, scan_index + 1) # <<<<<<<<<<<<<<
* if idx == -1:
* self._handle_error(SF_ERR_SCAN_NOT_FOUND)
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 824, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 828; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 824, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 828; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_idx = SfNumber(__pyx_v_self->handle, __pyx_t_2);
- /* "silx/io/specfile.pyx":825
+ /* "silx/io/specfile.pyx":829
* """
* idx = specfile_wrapper.SfNumber(self.handle, scan_index + 1)
* if idx == -1: # <<<<<<<<<<<<<<
* self._handle_error(SF_ERR_SCAN_NOT_FOUND)
* return idx
*/
- __pyx_t_3 = ((__pyx_v_idx == -1L) != 0);
+ __pyx_t_3 = ((__pyx_v_idx == -1) != 0);
if (__pyx_t_3) {
- /* "silx/io/specfile.pyx":826
+ /* "silx/io/specfile.pyx":830
* idx = specfile_wrapper.SfNumber(self.handle, scan_index + 1)
* if idx == -1:
* self._handle_error(SF_ERR_SCAN_NOT_FOUND) # <<<<<<<<<<<<<<
* return idx
*
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 826, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 830; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_SCAN_NOT_FOUND); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 826, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_SCAN_NOT_FOUND); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 830; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -11298,53 +10204,27 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_23number(struct __pyx_ob
}
}
if (!__pyx_t_6) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 826, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 830; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 826, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 826, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 826, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 826, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- }
+ __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 830; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 830; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-
- /* "silx/io/specfile.pyx":825
- * """
- * idx = specfile_wrapper.SfNumber(self.handle, scan_index + 1)
- * if idx == -1: # <<<<<<<<<<<<<<
- * self._handle_error(SF_ERR_SCAN_NOT_FOUND)
- * return idx
- */
+ goto __pyx_L3;
}
+ __pyx_L3:;
- /* "silx/io/specfile.pyx":827
+ /* "silx/io/specfile.pyx":831
* if idx == -1:
* self._handle_error(SF_ERR_SCAN_NOT_FOUND)
* return idx # <<<<<<<<<<<<<<
@@ -11352,13 +10232,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_23number(struct __pyx_ob
* def order(self, scan_index):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_idx); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 827, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_idx); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 831; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":814
+ /* "silx/io/specfile.pyx":818
* return idx - 1
*
* def number(self, scan_index): # <<<<<<<<<<<<<<
@@ -11381,7 +10261,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_23number(struct __pyx_ob
return __pyx_r;
}
-/* "silx/io/specfile.pyx":829
+/* "silx/io/specfile.pyx":833
* return idx
*
* def order(self, scan_index): # <<<<<<<<<<<<<<
@@ -11390,20 +10270,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_23number(struct __pyx_ob
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_26order(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_25order[] = "SpecFile.order(self, scan_index)\nReturns scan order from scan index.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Scan order (sequential number incrementing each time a\n non-unique occurrence of a scan number is encountered).\n :rtype: int\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_26order(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_28order(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_27order[] = "SpecFile.order(self, scan_index)\nReturns scan order from scan index.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Scan order (sequential number incrementing each time a\n non-unique occurrence of a scan number is encountered).\n :rtype: int\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_28order(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("order (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_25order(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_27order(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_25order(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_27order(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
long __pyx_v_ordr;
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
@@ -11414,44 +10294,47 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_25order(struct __pyx_obj
PyObject *__pyx_t_5 = NULL;
PyObject *__pyx_t_6 = NULL;
PyObject *__pyx_t_7 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("order", 0);
- /* "silx/io/specfile.pyx":840
+ /* "silx/io/specfile.pyx":844
* :rtype: int
* """
* ordr = specfile_wrapper.SfOrder(self.handle, scan_index + 1) # <<<<<<<<<<<<<<
* if ordr == -1:
* self._handle_error(SF_ERR_SCAN_NOT_FOUND)
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 840, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 844; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 840, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 844; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_ordr = SfOrder(__pyx_v_self->handle, __pyx_t_2);
- /* "silx/io/specfile.pyx":841
+ /* "silx/io/specfile.pyx":845
* """
* ordr = specfile_wrapper.SfOrder(self.handle, scan_index + 1)
* if ordr == -1: # <<<<<<<<<<<<<<
* self._handle_error(SF_ERR_SCAN_NOT_FOUND)
* return ordr
*/
- __pyx_t_3 = ((__pyx_v_ordr == -1L) != 0);
+ __pyx_t_3 = ((__pyx_v_ordr == -1) != 0);
if (__pyx_t_3) {
- /* "silx/io/specfile.pyx":842
+ /* "silx/io/specfile.pyx":846
* ordr = specfile_wrapper.SfOrder(self.handle, scan_index + 1)
* if ordr == -1:
* self._handle_error(SF_ERR_SCAN_NOT_FOUND) # <<<<<<<<<<<<<<
* return ordr
*
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 842, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 846; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_SCAN_NOT_FOUND); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 842, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_SCAN_NOT_FOUND); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 846; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -11461,53 +10344,27 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_25order(struct __pyx_obj
}
}
if (!__pyx_t_6) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 842, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 846; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 842, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 842, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 842, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 842, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- }
+ __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 846; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 846; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-
- /* "silx/io/specfile.pyx":841
- * """
- * ordr = specfile_wrapper.SfOrder(self.handle, scan_index + 1)
- * if ordr == -1: # <<<<<<<<<<<<<<
- * self._handle_error(SF_ERR_SCAN_NOT_FOUND)
- * return ordr
- */
+ goto __pyx_L3;
}
+ __pyx_L3:;
- /* "silx/io/specfile.pyx":843
+ /* "silx/io/specfile.pyx":847
* if ordr == -1:
* self._handle_error(SF_ERR_SCAN_NOT_FOUND)
* return ordr # <<<<<<<<<<<<<<
@@ -11515,13 +10372,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_25order(struct __pyx_obj
* def _list(self):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_ordr); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 843, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_ordr); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 847; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":829
+ /* "silx/io/specfile.pyx":833
* return idx
*
* def order(self, scan_index): # <<<<<<<<<<<<<<
@@ -11544,7 +10401,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_25order(struct __pyx_obj
return __pyx_r;
}
-/* "silx/io/specfile.pyx":845
+/* "silx/io/specfile.pyx":849
* return ordr
*
* def _list(self): # <<<<<<<<<<<<<<
@@ -11553,20 +10410,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_25order(struct __pyx_obj
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_28_list(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_27_list[] = "SpecFile._list(self)\nsee documentation of :meth:`list`\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_28_list(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_30_list(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_29_list[] = "SpecFile._list(self)\nsee documentation of :meth:`list`\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_30_list(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("_list (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_27_list(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_29_list(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_27_list(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_29_list(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
long *__pyx_v_scan_numbers;
int __pyx_v_error;
PyObject *__pyx_v_ret_list = NULL;
@@ -11582,22 +10439,25 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_27_list(struct __pyx_obj
Py_ssize_t __pyx_t_7;
Py_ssize_t __pyx_t_8;
int __pyx_t_9;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("_list", 0);
- /* "silx/io/specfile.pyx":850
+ /* "silx/io/specfile.pyx":854
* cdef:
* long *scan_numbers
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* scan_numbers = specfile_wrapper.SfList(self.handle, &error)
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 850, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 854; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 850, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 854; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":852
+ /* "silx/io/specfile.pyx":856
* int error = SF_ERR_NO_ERRORS
*
* scan_numbers = specfile_wrapper.SfList(self.handle, &error) # <<<<<<<<<<<<<<
@@ -11606,19 +10466,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_27_list(struct __pyx_obj
*/
__pyx_v_scan_numbers = SfList(__pyx_v_self->handle, (&__pyx_v_error));
- /* "silx/io/specfile.pyx":853
+ /* "silx/io/specfile.pyx":857
*
* scan_numbers = specfile_wrapper.SfList(self.handle, &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* ret_list = []
*/
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 853, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 857; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 853, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 857; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_5 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_5)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -11628,80 +10488,60 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_27_list(struct __pyx_obj
}
}
if (!__pyx_t_5) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 853, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_4); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 857; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_4};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 853, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_4};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 853, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- } else
- #endif
- {
- __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 853, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __pyx_t_5 = NULL;
- __Pyx_GIVEREF(__pyx_t_4);
- PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_4);
- __pyx_t_4 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 853, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- }
+ __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 857; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_6);
+ PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __Pyx_GIVEREF(__pyx_t_5); __pyx_t_5 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_4);
+ __Pyx_GIVEREF(__pyx_t_4);
+ __pyx_t_4 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 857; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":855
+ /* "silx/io/specfile.pyx":859
* self._handle_error(error)
*
* ret_list = [] # <<<<<<<<<<<<<<
* for i in range(len(self)):
* ret_list.append(scan_numbers[i])
*/
- __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 855, __pyx_L1_error)
+ __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 859; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_v_ret_list = ((PyObject*)__pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":856
+ /* "silx/io/specfile.pyx":860
*
* ret_list = []
* for i in range(len(self)): # <<<<<<<<<<<<<<
* ret_list.append(scan_numbers[i])
*
*/
- __pyx_t_7 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_7 == -1)) __PYX_ERR(0, 856, __pyx_L1_error)
+ __pyx_t_7 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_7 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 860; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_7; __pyx_t_8+=1) {
__pyx_v_i = __pyx_t_8;
- /* "silx/io/specfile.pyx":857
+ /* "silx/io/specfile.pyx":861
* ret_list = []
* for i in range(len(self)):
* ret_list.append(scan_numbers[i]) # <<<<<<<<<<<<<<
*
* free(scan_numbers)
*/
- __pyx_t_1 = __Pyx_PyInt_From_long((__pyx_v_scan_numbers[__pyx_v_i])); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 857, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyInt_From_long((__pyx_v_scan_numbers[__pyx_v_i])); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 861; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_9 = __Pyx_PyList_Append(__pyx_v_ret_list, __pyx_t_1); if (unlikely(__pyx_t_9 == -1)) __PYX_ERR(0, 857, __pyx_L1_error)
+ __pyx_t_9 = __Pyx_PyList_Append(__pyx_v_ret_list, __pyx_t_1); if (unlikely(__pyx_t_9 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 861; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
}
- /* "silx/io/specfile.pyx":859
+ /* "silx/io/specfile.pyx":863
* ret_list.append(scan_numbers[i])
*
* free(scan_numbers) # <<<<<<<<<<<<<<
@@ -11710,7 +10550,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_27_list(struct __pyx_obj
*/
free(__pyx_v_scan_numbers);
- /* "silx/io/specfile.pyx":860
+ /* "silx/io/specfile.pyx":864
*
* free(scan_numbers)
* return ret_list # <<<<<<<<<<<<<<
@@ -11722,7 +10562,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_27_list(struct __pyx_obj
__pyx_r = __pyx_v_ret_list;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":845
+ /* "silx/io/specfile.pyx":849
* return ordr
*
* def _list(self): # <<<<<<<<<<<<<<
@@ -11746,7 +10586,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_27_list(struct __pyx_obj
return __pyx_r;
}
-/* "silx/io/specfile.pyx":862
+/* "silx/io/specfile.pyx":866
* return ret_list
*
* def list(self): # <<<<<<<<<<<<<<
@@ -11755,28 +10595,31 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_27_list(struct __pyx_obj
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_30list(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_29list[] = "SpecFile.list(self)\nReturns list (1D numpy array) of scan numbers in SpecFile.\n\n :return: list of scan numbers (from `` #S`` lines) in the same order\n as in the original SpecFile (e.g ``[1, 1, 2, 3, \342\200\246]``).\n :rtype: numpy array\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_30list(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_32list(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_31list[] = "SpecFile.list(self)\nReturns list (1D numpy array) of scan numbers in SpecFile.\n\n :return: list of scan numbers (from `` #S`` lines) in the same order\n as in the original SpecFile (e.g ``[1, 1, 2, 3, \342\200\246]``).\n :rtype: numpy array\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_32list(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("list (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_29list(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_31list(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_29list(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31list(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self) {
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
PyObject *__pyx_t_2 = NULL;
PyObject *__pyx_t_3 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("list", 0);
- /* "silx/io/specfile.pyx":871
+ /* "silx/io/specfile.pyx":875
* # this method is overloaded in specfilewrapper to output a string
* # representation of the list
* return self._list() # <<<<<<<<<<<<<<
@@ -11784,10 +10627,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_29list(struct __pyx_obj_
* def data(self, scan_index):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_list); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 871, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_list); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 875; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_3 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
@@ -11797,10 +10640,10 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_29list(struct __pyx_obj_
}
}
if (__pyx_t_3) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 871, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 875; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
} else {
- __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 871, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 875; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -11808,7 +10651,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_29list(struct __pyx_obj_
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":862
+ /* "silx/io/specfile.pyx":866
* return ret_list
*
* def list(self): # <<<<<<<<<<<<<<
@@ -11829,7 +10672,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_29list(struct __pyx_obj_
return __pyx_r;
}
-/* "silx/io/specfile.pyx":873
+/* "silx/io/specfile.pyx":877
* return self._list()
*
* def data(self, scan_index): # <<<<<<<<<<<<<<
@@ -11838,20 +10681,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_29list(struct __pyx_obj_
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_32data(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_31data[] = "SpecFile.data(self, scan_index)\nReturns data for the specified scan index.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Complete scan data as a 2D array of doubles\n :rtype: numpy.ndarray\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_32data(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_34data(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_33data[] = "SpecFile.data(self, scan_index)\nReturns data for the specified scan index.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Complete scan data as a 2D array of doubles\n :rtype: numpy.ndarray\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_34data(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("data (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_31data(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_33data(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
double **__pyx_v_mydata;
long *__pyx_v_data_info;
int __pyx_v_i;
@@ -11874,34 +10717,37 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
int __pyx_t_8;
long __pyx_t_9;
int __pyx_t_10;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("data", 0);
- /* "silx/io/specfile.pyx":887
+ /* "silx/io/specfile.pyx":891
* long* data_info
* int i, j
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
* long nlines, ncolumns, regular
*
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 887, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 891; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 887, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 891; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":891
+ /* "silx/io/specfile.pyx":895
*
* sfdata_error = specfile_wrapper.SfData(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* &mydata,
* &data_info,
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 891, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 895; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 891, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 895; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":890
+ /* "silx/io/specfile.pyx":894
* long nlines, ncolumns, regular
*
* sfdata_error = specfile_wrapper.SfData(self.handle, # <<<<<<<<<<<<<<
@@ -11910,19 +10756,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
*/
__pyx_v_sfdata_error = SfData(__pyx_v_self->handle, __pyx_t_3, (&__pyx_v_mydata), (&__pyx_v_data_info), (&__pyx_v_error));
- /* "silx/io/specfile.pyx":895
+ /* "silx/io/specfile.pyx":899
* &data_info,
* &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* if <long>data_info != 0:
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 895, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 899; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 895, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 899; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -11932,44 +10778,24 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
}
}
if (!__pyx_t_6) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 895, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 899; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 895, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 895, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 895, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 895, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- }
+ __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 899; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 899; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":897
+ /* "silx/io/specfile.pyx":901
* self._handle_error(error)
*
* if <long>data_info != 0: # <<<<<<<<<<<<<<
@@ -11979,7 +10805,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
__pyx_t_8 = ((((long)__pyx_v_data_info) != 0) != 0);
if (__pyx_t_8) {
- /* "silx/io/specfile.pyx":898
+ /* "silx/io/specfile.pyx":902
*
* if <long>data_info != 0:
* nlines = data_info[0] # <<<<<<<<<<<<<<
@@ -11988,7 +10814,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
*/
__pyx_v_nlines = (__pyx_v_data_info[0]);
- /* "silx/io/specfile.pyx":899
+ /* "silx/io/specfile.pyx":903
* if <long>data_info != 0:
* nlines = data_info[0]
* ncolumns = data_info[1] # <<<<<<<<<<<<<<
@@ -11997,7 +10823,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
*/
__pyx_v_ncolumns = (__pyx_v_data_info[1]);
- /* "silx/io/specfile.pyx":900
+ /* "silx/io/specfile.pyx":904
* nlines = data_info[0]
* ncolumns = data_info[1]
* regular = data_info[2] # <<<<<<<<<<<<<<
@@ -12005,28 +10831,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
* nlines = 0
*/
__pyx_v_regular = (__pyx_v_data_info[2]);
-
- /* "silx/io/specfile.pyx":897
- * self._handle_error(error)
- *
- * if <long>data_info != 0: # <<<<<<<<<<<<<<
- * nlines = data_info[0]
- * ncolumns = data_info[1]
- */
goto __pyx_L3;
}
+ /*else*/ {
- /* "silx/io/specfile.pyx":902
+ /* "silx/io/specfile.pyx":906
* regular = data_info[2]
* else:
* nlines = 0 # <<<<<<<<<<<<<<
* ncolumns = 0
* regular = 0
*/
- /*else*/ {
__pyx_v_nlines = 0;
- /* "silx/io/specfile.pyx":903
+ /* "silx/io/specfile.pyx":907
* else:
* nlines = 0
* ncolumns = 0 # <<<<<<<<<<<<<<
@@ -12035,7 +10853,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
*/
__pyx_v_ncolumns = 0;
- /* "silx/io/specfile.pyx":904
+ /* "silx/io/specfile.pyx":908
* nlines = 0
* ncolumns = 0
* regular = 0 # <<<<<<<<<<<<<<
@@ -12046,70 +10864,70 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
}
__pyx_L3:;
- /* "silx/io/specfile.pyx":906
+ /* "silx/io/specfile.pyx":910
* regular = 0
*
* cdef numpy.ndarray ret_array = numpy.empty((nlines, ncolumns), # <<<<<<<<<<<<<<
* dtype=numpy.double)
* for i in range(nlines):
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 906, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 910; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_empty); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 906, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_empty); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 910; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_nlines); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 906, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_nlines); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 910; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_7 = __Pyx_PyInt_From_long(__pyx_v_ncolumns); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 906, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyInt_From_long(__pyx_v_ncolumns); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 910; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
- __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 906, __pyx_L1_error)
+ __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 910; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_7);
+ __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_7);
+ __Pyx_GIVEREF(__pyx_t_7);
__pyx_t_1 = 0;
__pyx_t_7 = 0;
- __pyx_t_7 = PyTuple_New(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 906, __pyx_L1_error)
+ __pyx_t_7 = PyTuple_New(1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 910; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_5);
PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
__pyx_t_5 = 0;
+ __pyx_t_5 = PyDict_New(); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 910; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_5);
- /* "silx/io/specfile.pyx":907
+ /* "silx/io/specfile.pyx":911
*
* cdef numpy.ndarray ret_array = numpy.empty((nlines, ncolumns),
* dtype=numpy.double) # <<<<<<<<<<<<<<
* for i in range(nlines):
* for j in range(ncolumns):
*/
- __pyx_t_5 = PyDict_New(); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 907, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 907, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 911; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_double); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 907, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_double); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 911; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, __pyx_t_6) < 0) __PYX_ERR(0, 907, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, __pyx_t_6) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 910; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- /* "silx/io/specfile.pyx":906
+ /* "silx/io/specfile.pyx":910
* regular = 0
*
* cdef numpy.ndarray ret_array = numpy.empty((nlines, ncolumns), # <<<<<<<<<<<<<<
* dtype=numpy.double)
* for i in range(nlines):
*/
- __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 906, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, __pyx_t_5); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 910; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- if (!(likely(((__pyx_t_6) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_6, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 906, __pyx_L1_error)
+ if (!(likely(((__pyx_t_6) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_6, __pyx_ptype_5numpy_ndarray))))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 910; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_v_ret_array = ((PyArrayObject *)__pyx_t_6);
__pyx_t_6 = 0;
- /* "silx/io/specfile.pyx":908
+ /* "silx/io/specfile.pyx":912
* cdef numpy.ndarray ret_array = numpy.empty((nlines, ncolumns),
* dtype=numpy.double)
* for i in range(nlines): # <<<<<<<<<<<<<<
@@ -12120,7 +10938,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_3; __pyx_t_2+=1) {
__pyx_v_i = __pyx_t_2;
- /* "silx/io/specfile.pyx":909
+ /* "silx/io/specfile.pyx":913
* dtype=numpy.double)
* for i in range(nlines):
* for j in range(ncolumns): # <<<<<<<<<<<<<<
@@ -12131,34 +10949,34 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
for (__pyx_t_10 = 0; __pyx_t_10 < __pyx_t_9; __pyx_t_10+=1) {
__pyx_v_j = __pyx_t_10;
- /* "silx/io/specfile.pyx":910
+ /* "silx/io/specfile.pyx":914
* for i in range(nlines):
* for j in range(ncolumns):
* ret_array[i, j] = mydata[i][j] # <<<<<<<<<<<<<<
*
* specfile_wrapper.freeArrNZ(<void ***>&mydata, nlines)
*/
- __pyx_t_6 = PyFloat_FromDouble(((__pyx_v_mydata[__pyx_v_i])[__pyx_v_j])); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 910, __pyx_L1_error)
+ __pyx_t_6 = PyFloat_FromDouble(((__pyx_v_mydata[__pyx_v_i])[__pyx_v_j])); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 914; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_i); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 910, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_i); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 914; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_7 = __Pyx_PyInt_From_int(__pyx_v_j); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 910, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyInt_From_int(__pyx_v_j); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 914; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
- __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 910, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 914; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_5);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_5);
- __Pyx_GIVEREF(__pyx_t_7);
+ __Pyx_GIVEREF(__pyx_t_5);
PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_7);
+ __Pyx_GIVEREF(__pyx_t_7);
__pyx_t_5 = 0;
__pyx_t_7 = 0;
- if (unlikely(PyObject_SetItem(((PyObject *)__pyx_v_ret_array), __pyx_t_4, __pyx_t_6) < 0)) __PYX_ERR(0, 910, __pyx_L1_error)
+ if (unlikely(PyObject_SetItem(((PyObject *)__pyx_v_ret_array), __pyx_t_4, __pyx_t_6) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 914; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
}
}
- /* "silx/io/specfile.pyx":912
+ /* "silx/io/specfile.pyx":916
* ret_array[i, j] = mydata[i][j]
*
* specfile_wrapper.freeArrNZ(<void ***>&mydata, nlines) # <<<<<<<<<<<<<<
@@ -12167,7 +10985,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
*/
freeArrNZ(((void ***)(&__pyx_v_mydata)), __pyx_v_nlines);
- /* "silx/io/specfile.pyx":913
+ /* "silx/io/specfile.pyx":917
*
* specfile_wrapper.freeArrNZ(<void ***>&mydata, nlines)
* free(data_info) # <<<<<<<<<<<<<<
@@ -12176,7 +10994,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
*/
free(__pyx_v_data_info);
- /* "silx/io/specfile.pyx":914
+ /* "silx/io/specfile.pyx":918
* specfile_wrapper.freeArrNZ(<void ***>&mydata, nlines)
* free(data_info)
* return ret_array # <<<<<<<<<<<<<<
@@ -12188,7 +11006,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
__pyx_r = ((PyObject *)__pyx_v_ret_array);
goto __pyx_L0;
- /* "silx/io/specfile.pyx":873
+ /* "silx/io/specfile.pyx":877
* return self._list()
*
* def data(self, scan_index): # <<<<<<<<<<<<<<
@@ -12212,7 +11030,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
return __pyx_r;
}
-/* "silx/io/specfile.pyx":916
+/* "silx/io/specfile.pyx":920
* return ret_array
*
* def data_column_by_name(self, scan_index, label): # <<<<<<<<<<<<<<
@@ -12221,11 +11039,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_31data(struct __pyx_obj_
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_34data_column_by_name(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_33data_column_by_name[] = "SpecFile.data_column_by_name(self, scan_index, label)\nReturns data column for the specified scan index and column label.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n :param label: Label of data column, as defined in the ``#L`` line\n of the scan header.\n :type label: str\n\n :return: Data column as a 1D array of doubles\n :rtype: numpy.ndarray\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_34data_column_by_name(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_36data_column_by_name(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_35data_column_by_name[] = "SpecFile.data_column_by_name(self, scan_index, label)\nReturns data column for the specified scan index and column label.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n :param label: Label of data column, as defined in the ``#L`` line\n of the scan header.\n :type label: str\n\n :return: Data column as a 1D array of doubles\n :rtype: numpy.ndarray\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_36data_column_by_name(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_scan_index = 0;
PyObject *__pyx_v_label = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("data_column_by_name (wrapper)", 0);
@@ -12249,11 +11070,11 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_34data_column_by_name(Py
case 1:
if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_label)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("data_column_by_name", 1, 2, 2, 1); __PYX_ERR(0, 916, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("data_column_by_name", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 920; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "data_column_by_name") < 0)) __PYX_ERR(0, 916, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "data_column_by_name") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 920; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
goto __pyx_L5_argtuple_error;
@@ -12266,20 +11087,20 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_34data_column_by_name(Py
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("data_column_by_name", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 916, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("data_column_by_name", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 920; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.SpecFile.data_column_by_name", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
return NULL;
__pyx_L4_argument_unpacking_done:;
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index, __pyx_v_label);
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_35data_column_by_name(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index, __pyx_v_label);
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_label) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35data_column_by_name(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_label) {
double *__pyx_v_data_column;
long __pyx_v_i;
long __pyx_v_nlines;
@@ -12296,33 +11117,36 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(st
char *__pyx_t_7;
PyObject *__pyx_t_8 = NULL;
long __pyx_t_9;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("data_column_by_name", 0);
__Pyx_INCREF(__pyx_v_label);
- /* "silx/io/specfile.pyx":932
+ /* "silx/io/specfile.pyx":936
* double* data_column
* long i, nlines
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* label = _string_to_char_star(label)
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 932, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 936; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 932, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 936; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":934
+ /* "silx/io/specfile.pyx":938
* int error = SF_ERR_NO_ERRORS
*
* label = _string_to_char_star(label) # <<<<<<<<<<<<<<
*
* nlines = specfile_wrapper.SfDataColByName(self.handle,
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_string_to_char_star); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 934, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_string_to_char_star); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 938; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -12332,63 +11156,45 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(st
}
}
if (!__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_label); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 934, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_label); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 938; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_v_label};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 934, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_v_label};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 934, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 934, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __pyx_t_4 = NULL;
- __Pyx_INCREF(__pyx_v_label);
- __Pyx_GIVEREF(__pyx_v_label);
- PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_v_label);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 934, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- }
+ __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 938; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_5);
+ PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
+ __Pyx_INCREF(__pyx_v_label);
+ PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_v_label);
+ __Pyx_GIVEREF(__pyx_v_label);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 938; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF_SET(__pyx_v_label, __pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":937
+ /* "silx/io/specfile.pyx":941
*
* nlines = specfile_wrapper.SfDataColByName(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* label,
* &data_column,
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 937, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 941; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_6 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_6 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 937, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_6 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 941; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":938
+ /* "silx/io/specfile.pyx":942
* nlines = specfile_wrapper.SfDataColByName(self.handle,
* scan_index + 1,
* label, # <<<<<<<<<<<<<<
* &data_column,
* &error)
*/
- __pyx_t_7 = __Pyx_PyObject_AsString(__pyx_v_label); if (unlikely((!__pyx_t_7) && PyErr_Occurred())) __PYX_ERR(0, 938, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_AsString(__pyx_v_label); if (unlikely((!__pyx_t_7) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 942; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
- /* "silx/io/specfile.pyx":936
+ /* "silx/io/specfile.pyx":940
* label = _string_to_char_star(label)
*
* nlines = specfile_wrapper.SfDataColByName(self.handle, # <<<<<<<<<<<<<<
@@ -12397,19 +11203,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(st
*/
__pyx_v_nlines = SfDataColByName(__pyx_v_self->handle, __pyx_t_6, __pyx_t_7, (&__pyx_v_data_column), (&__pyx_v_error));
- /* "silx/io/specfile.pyx":941
+ /* "silx/io/specfile.pyx":945
* &data_column,
* &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* cdef numpy.ndarray ret_array = numpy.empty((nlines,),
*/
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 941, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 945; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 941, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 945; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -12419,102 +11225,82 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(st
}
}
if (!__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 941, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 945; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 941, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 941, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 941, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_4); __pyx_t_4 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 941, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- }
+ __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 945; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
+ PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 945; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":943
+ /* "silx/io/specfile.pyx":947
* self._handle_error(error)
*
* cdef numpy.ndarray ret_array = numpy.empty((nlines,), # <<<<<<<<<<<<<<
* dtype=numpy.double)
* for i in range(nlines):
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 943, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 947; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 943, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_empty); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 947; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_nlines); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 943, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_nlines); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 947; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_8 = PyTuple_New(1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 943, __pyx_L1_error)
+ __pyx_t_8 = PyTuple_New(1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 947; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_8);
- __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_1);
+ __Pyx_GIVEREF(__pyx_t_1);
__pyx_t_1 = 0;
- __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 943, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 947; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_8);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_8);
+ __Pyx_GIVEREF(__pyx_t_8);
__pyx_t_8 = 0;
+ __pyx_t_8 = PyDict_New(); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 947; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
- /* "silx/io/specfile.pyx":944
+ /* "silx/io/specfile.pyx":948
*
* cdef numpy.ndarray ret_array = numpy.empty((nlines,),
* dtype=numpy.double) # <<<<<<<<<<<<<<
* for i in range(nlines):
* ret_array[i] = data_column[i]
*/
- __pyx_t_8 = PyDict_New(); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 944, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 944, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 948; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_double); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 944, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_double); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 948; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- if (PyDict_SetItem(__pyx_t_8, __pyx_n_s_dtype, __pyx_t_4) < 0) __PYX_ERR(0, 944, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_8, __pyx_n_s_dtype, __pyx_t_4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 947; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- /* "silx/io/specfile.pyx":943
+ /* "silx/io/specfile.pyx":947
* self._handle_error(error)
*
* cdef numpy.ndarray ret_array = numpy.empty((nlines,), # <<<<<<<<<<<<<<
* dtype=numpy.double)
* for i in range(nlines):
*/
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_1, __pyx_t_8); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 943, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_1, __pyx_t_8); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 947; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- if (!(likely(((__pyx_t_4) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_4, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 943, __pyx_L1_error)
+ if (!(likely(((__pyx_t_4) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_4, __pyx_ptype_5numpy_ndarray))))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 947; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_v_ret_array = ((PyArrayObject *)__pyx_t_4);
__pyx_t_4 = 0;
- /* "silx/io/specfile.pyx":945
+ /* "silx/io/specfile.pyx":949
* cdef numpy.ndarray ret_array = numpy.empty((nlines,),
* dtype=numpy.double)
* for i in range(nlines): # <<<<<<<<<<<<<<
@@ -12525,20 +11311,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(st
for (__pyx_t_9 = 0; __pyx_t_9 < __pyx_t_6; __pyx_t_9+=1) {
__pyx_v_i = __pyx_t_9;
- /* "silx/io/specfile.pyx":946
+ /* "silx/io/specfile.pyx":950
* dtype=numpy.double)
* for i in range(nlines):
* ret_array[i] = data_column[i] # <<<<<<<<<<<<<<
*
* free(data_column)
*/
- __pyx_t_4 = PyFloat_FromDouble((__pyx_v_data_column[__pyx_v_i])); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 946, __pyx_L1_error)
+ __pyx_t_4 = PyFloat_FromDouble((__pyx_v_data_column[__pyx_v_i])); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 950; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- if (unlikely(__Pyx_SetItemInt(((PyObject *)__pyx_v_ret_array), __pyx_v_i, __pyx_t_4, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) __PYX_ERR(0, 946, __pyx_L1_error)
+ if (unlikely(__Pyx_SetItemInt(((PyObject *)__pyx_v_ret_array), __pyx_v_i, __pyx_t_4, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 950; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
}
- /* "silx/io/specfile.pyx":948
+ /* "silx/io/specfile.pyx":952
* ret_array[i] = data_column[i]
*
* free(data_column) # <<<<<<<<<<<<<<
@@ -12547,7 +11333,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(st
*/
free(__pyx_v_data_column);
- /* "silx/io/specfile.pyx":949
+ /* "silx/io/specfile.pyx":953
*
* free(data_column)
* return ret_array # <<<<<<<<<<<<<<
@@ -12559,7 +11345,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(st
__pyx_r = ((PyObject *)__pyx_v_ret_array);
goto __pyx_L0;
- /* "silx/io/specfile.pyx":916
+ /* "silx/io/specfile.pyx":920
* return ret_array
*
* def data_column_by_name(self, scan_index, label): # <<<<<<<<<<<<<<
@@ -12584,7 +11370,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(st
return __pyx_r;
}
-/* "silx/io/specfile.pyx":951
+/* "silx/io/specfile.pyx":955
* return ret_array
*
* def scan_header(self, scan_index): # <<<<<<<<<<<<<<
@@ -12593,20 +11379,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_33data_column_by_name(st
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_36scan_header(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_35scan_header[] = "SpecFile.scan_header(self, scan_index)\nReturn list of scan header lines.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: List of raw scan header lines\n :rtype: list of str\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_36scan_header(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_38scan_header(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_37scan_header[] = "SpecFile.scan_header(self, scan_index)\nReturn list of scan header lines.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: List of raw scan header lines\n :rtype: list of str\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_38scan_header(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("scan_header (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_37scan_header(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37scan_header(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
char **__pyx_v_lines;
int __pyx_v_error;
long __pyx_v_nlines;
@@ -12625,55 +11411,58 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(struct __p
long __pyx_t_8;
char *__pyx_t_9;
int __pyx_t_10;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("scan_header", 0);
- /* "silx/io/specfile.pyx":963
+ /* "silx/io/specfile.pyx":967
* cdef:
* char** lines
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* nlines = specfile_wrapper.SfHeader(self.handle,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 963, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 967; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 963, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 967; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":966
+ /* "silx/io/specfile.pyx":970
*
* nlines = specfile_wrapper.SfHeader(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* "", # no pattern matching
* &lines,
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 966, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 970; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 966, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 970; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":965
+ /* "silx/io/specfile.pyx":969
* int error = SF_ERR_NO_ERRORS
*
* nlines = specfile_wrapper.SfHeader(self.handle, # <<<<<<<<<<<<<<
* scan_index + 1,
* "", # no pattern matching
*/
- __pyx_v_nlines = SfHeader(__pyx_v_self->handle, __pyx_t_3, ((char *)""), (&__pyx_v_lines), (&__pyx_v_error));
+ __pyx_v_nlines = SfHeader(__pyx_v_self->handle, __pyx_t_3, __pyx_k__32, (&__pyx_v_lines), (&__pyx_v_error));
- /* "silx/io/specfile.pyx":971
+ /* "silx/io/specfile.pyx":975
* &error)
*
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* lines_list = []
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 971, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 975; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 971, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 975; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -12683,56 +11472,36 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(struct __p
}
}
if (!__pyx_t_6) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 971, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 975; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 971, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 971, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 971, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 971, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- }
+ __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 975; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 975; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":973
+ /* "silx/io/specfile.pyx":977
* self._handle_error(error)
*
* lines_list = [] # <<<<<<<<<<<<<<
* for i in range(nlines):
* line = <bytes>lines[i].decode()
*/
- __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 973, __pyx_L1_error)
+ __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 977; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_v_lines_list = ((PyObject*)__pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":974
+ /* "silx/io/specfile.pyx":978
*
* lines_list = []
* for i in range(nlines): # <<<<<<<<<<<<<<
@@ -12743,7 +11512,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(struct __p
for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_3; __pyx_t_8+=1) {
__pyx_v_i = __pyx_t_8;
- /* "silx/io/specfile.pyx":975
+ /* "silx/io/specfile.pyx":979
* lines_list = []
* for i in range(nlines):
* line = <bytes>lines[i].decode() # <<<<<<<<<<<<<<
@@ -12751,7 +11520,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(struct __p
*
*/
__pyx_t_9 = (__pyx_v_lines[__pyx_v_i]);
- __pyx_t_1 = __Pyx_decode_c_string(__pyx_t_9, 0, strlen(__pyx_t_9), NULL, NULL, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 975, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_decode_c_string(__pyx_t_9, 0, strlen(__pyx_t_9), NULL, NULL, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 979; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_4 = __pyx_t_1;
__Pyx_INCREF(__pyx_t_4);
@@ -12759,17 +11528,17 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(struct __p
__Pyx_XDECREF_SET(__pyx_v_line, ((PyObject*)__pyx_t_4));
__pyx_t_4 = 0;
- /* "silx/io/specfile.pyx":976
+ /* "silx/io/specfile.pyx":980
* for i in range(nlines):
* line = <bytes>lines[i].decode()
* lines_list.append(line) # <<<<<<<<<<<<<<
*
* specfile_wrapper.freeArrNZ(<void***>&lines, nlines)
*/
- __pyx_t_10 = __Pyx_PyList_Append(__pyx_v_lines_list, __pyx_v_line); if (unlikely(__pyx_t_10 == -1)) __PYX_ERR(0, 976, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyList_Append(__pyx_v_lines_list, __pyx_v_line); if (unlikely(__pyx_t_10 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 980; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- /* "silx/io/specfile.pyx":978
+ /* "silx/io/specfile.pyx":982
* lines_list.append(line)
*
* specfile_wrapper.freeArrNZ(<void***>&lines, nlines) # <<<<<<<<<<<<<<
@@ -12778,7 +11547,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(struct __p
*/
freeArrNZ(((void ***)(&__pyx_v_lines)), __pyx_v_nlines);
- /* "silx/io/specfile.pyx":979
+ /* "silx/io/specfile.pyx":983
*
* specfile_wrapper.freeArrNZ(<void***>&lines, nlines)
* return lines_list # <<<<<<<<<<<<<<
@@ -12790,7 +11559,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(struct __p
__pyx_r = __pyx_v_lines_list;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":951
+ /* "silx/io/specfile.pyx":955
* return ret_array
*
* def scan_header(self, scan_index): # <<<<<<<<<<<<<<
@@ -12815,7 +11584,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(struct __p
return __pyx_r;
}
-/* "silx/io/specfile.pyx":981
+/* "silx/io/specfile.pyx":985
* return lines_list
*
* def file_header(self, scan_index=0): # <<<<<<<<<<<<<<
@@ -12824,10 +11593,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_35scan_header(struct __p
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_38file_header(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_37file_header[] = "SpecFile.file_header(self, scan_index=0)\nReturn list of file header lines.\n\n A file header contains all lines between a ``#F`` header line and\n a ``#S`` header line (start of scan). We need to specify a scan\n number because there can be more than one file header in a given file.\n A file header applies to all subsequent scans, until a new file\n header is defined.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: List of raw file header lines\n :rtype: list of str\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_38file_header(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_40file_header(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_39file_header[] = "SpecFile.file_header(self, scan_index=0)\nReturn list of file header lines.\n\n A file header contains all lines between a ``#F`` header line and\n a ``#S`` header line (start of scan). We need to specify a scan\n number because there can be more than one file header in a given file.\n A file header applies to all subsequent scans, until a new file\n header is defined.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: List of raw file header lines\n :rtype: list of str\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_40file_header(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_scan_index = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("file_header (wrapper)", 0);
@@ -12852,7 +11624,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_38file_header(PyObject *
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "file_header") < 0)) __PYX_ERR(0, 981, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "file_header") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 985; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else {
switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -12865,20 +11637,20 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_38file_header(PyObject *
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("file_header", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 981, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("file_header", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 985; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.SpecFile.file_header", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
return NULL;
__pyx_L4_argument_unpacking_done:;
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index);
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_39file_header(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index);
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_39file_header(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
char **__pyx_v_lines;
int __pyx_v_error;
long __pyx_v_nlines;
@@ -12897,55 +11669,58 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(struct __p
long __pyx_t_8;
char *__pyx_t_9;
int __pyx_t_10;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("file_header", 0);
- /* "silx/io/specfile.pyx":999
+ /* "silx/io/specfile.pyx":1003
* cdef:
* char** lines
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* nlines = specfile_wrapper.SfFileHeader(self.handle,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 999, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1003; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 999, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1003; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":1002
+ /* "silx/io/specfile.pyx":1006
*
* nlines = specfile_wrapper.SfFileHeader(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* "", # no pattern matching
* &lines,
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1002, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1006; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1002, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1006; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1001
+ /* "silx/io/specfile.pyx":1005
* int error = SF_ERR_NO_ERRORS
*
* nlines = specfile_wrapper.SfFileHeader(self.handle, # <<<<<<<<<<<<<<
* scan_index + 1,
* "", # no pattern matching
*/
- __pyx_v_nlines = SfFileHeader(__pyx_v_self->handle, __pyx_t_3, ((char *)""), (&__pyx_v_lines), (&__pyx_v_error));
+ __pyx_v_nlines = SfFileHeader(__pyx_v_self->handle, __pyx_t_3, __pyx_k__32, (&__pyx_v_lines), (&__pyx_v_error));
- /* "silx/io/specfile.pyx":1006
+ /* "silx/io/specfile.pyx":1010
* &lines,
* &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* lines_list = []
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1006, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1010; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1006, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1010; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -12955,56 +11730,36 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(struct __p
}
}
if (!__pyx_t_6) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1006, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1010; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1006, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1006, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1006, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1006, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- }
+ __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1010; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1010; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1008
+ /* "silx/io/specfile.pyx":1012
* self._handle_error(error)
*
* lines_list = [] # <<<<<<<<<<<<<<
* for i in range(nlines):
* line = <bytes>lines[i].decode()
*/
- __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1008, __pyx_L1_error)
+ __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1012; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_v_lines_list = ((PyObject*)__pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1009
+ /* "silx/io/specfile.pyx":1013
*
* lines_list = []
* for i in range(nlines): # <<<<<<<<<<<<<<
@@ -13015,7 +11770,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(struct __p
for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_3; __pyx_t_8+=1) {
__pyx_v_i = __pyx_t_8;
- /* "silx/io/specfile.pyx":1010
+ /* "silx/io/specfile.pyx":1014
* lines_list = []
* for i in range(nlines):
* line = <bytes>lines[i].decode() # <<<<<<<<<<<<<<
@@ -13023,7 +11778,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(struct __p
*
*/
__pyx_t_9 = (__pyx_v_lines[__pyx_v_i]);
- __pyx_t_1 = __Pyx_decode_c_string(__pyx_t_9, 0, strlen(__pyx_t_9), NULL, NULL, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1010, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_decode_c_string(__pyx_t_9, 0, strlen(__pyx_t_9), NULL, NULL, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1014; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_4 = __pyx_t_1;
__Pyx_INCREF(__pyx_t_4);
@@ -13031,17 +11786,17 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(struct __p
__Pyx_XDECREF_SET(__pyx_v_line, ((PyObject*)__pyx_t_4));
__pyx_t_4 = 0;
- /* "silx/io/specfile.pyx":1011
+ /* "silx/io/specfile.pyx":1015
* for i in range(nlines):
* line = <bytes>lines[i].decode()
* lines_list.append(line) # <<<<<<<<<<<<<<
*
* specfile_wrapper.freeArrNZ(<void***>&lines, nlines)
*/
- __pyx_t_10 = __Pyx_PyList_Append(__pyx_v_lines_list, __pyx_v_line); if (unlikely(__pyx_t_10 == -1)) __PYX_ERR(0, 1011, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyList_Append(__pyx_v_lines_list, __pyx_v_line); if (unlikely(__pyx_t_10 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1015; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- /* "silx/io/specfile.pyx":1013
+ /* "silx/io/specfile.pyx":1017
* lines_list.append(line)
*
* specfile_wrapper.freeArrNZ(<void***>&lines, nlines) # <<<<<<<<<<<<<<
@@ -13050,7 +11805,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(struct __p
*/
freeArrNZ(((void ***)(&__pyx_v_lines)), __pyx_v_nlines);
- /* "silx/io/specfile.pyx":1014
+ /* "silx/io/specfile.pyx":1018
*
* specfile_wrapper.freeArrNZ(<void***>&lines, nlines)
* return lines_list # <<<<<<<<<<<<<<
@@ -13062,7 +11817,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(struct __p
__pyx_r = __pyx_v_lines_list;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":981
+ /* "silx/io/specfile.pyx":985
* return lines_list
*
* def file_header(self, scan_index=0): # <<<<<<<<<<<<<<
@@ -13087,7 +11842,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(struct __p
return __pyx_r;
}
-/* "silx/io/specfile.pyx":1016
+/* "silx/io/specfile.pyx":1020
* return lines_list
*
* def columns(self, scan_index): # <<<<<<<<<<<<<<
@@ -13096,20 +11851,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_37file_header(struct __p
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_40columns(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_39columns[] = "SpecFile.columns(self, scan_index)\nReturn number of columns in a scan from the ``#N`` header line\n (without ``#N`` and scan number)\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Number of columns in scan from ``#N`` line\n :rtype: int\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_40columns(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_42columns(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_41columns[] = "SpecFile.columns(self, scan_index)\nReturn number of columns in a scan from the ``#N`` header line\n (without ``#N`` and scan number)\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Number of columns in scan from ``#N`` line\n :rtype: int\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_42columns(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("columns (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_39columns(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_41columns(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_39columns(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_41columns(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
int __pyx_v_error;
long __pyx_v_ncolumns;
PyObject *__pyx_r = NULL;
@@ -13121,34 +11876,37 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_39columns(struct __pyx_o
PyObject *__pyx_t_5 = NULL;
PyObject *__pyx_t_6 = NULL;
PyObject *__pyx_t_7 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("columns", 0);
- /* "silx/io/specfile.pyx":1028
+ /* "silx/io/specfile.pyx":1032
* """
* cdef:
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* ncolumns = specfile_wrapper.SfNoColumns(self.handle,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1028, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1032; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 1028, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1032; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":1031
+ /* "silx/io/specfile.pyx":1035
*
* ncolumns = specfile_wrapper.SfNoColumns(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* &error)
* self._handle_error(error)
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1031, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1035; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1031, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1035; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1030
+ /* "silx/io/specfile.pyx":1034
* int error = SF_ERR_NO_ERRORS
*
* ncolumns = specfile_wrapper.SfNoColumns(self.handle, # <<<<<<<<<<<<<<
@@ -13157,19 +11915,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_39columns(struct __pyx_o
*/
__pyx_v_ncolumns = SfNoColumns(__pyx_v_self->handle, __pyx_t_3, (&__pyx_v_error));
- /* "silx/io/specfile.pyx":1033
+ /* "silx/io/specfile.pyx":1037
* scan_index + 1,
* &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* return ncolumns
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1033, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1037; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1033, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1037; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -13179,44 +11937,24 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_39columns(struct __pyx_o
}
}
if (!__pyx_t_6) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1033, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1037; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1033, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1033, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1033, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1033, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- }
+ __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1037; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1037; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1035
+ /* "silx/io/specfile.pyx":1039
* self._handle_error(error)
*
* return ncolumns # <<<<<<<<<<<<<<
@@ -13224,13 +11962,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_39columns(struct __pyx_o
* def command(self, scan_index):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_ncolumns); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1035, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_ncolumns); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1039; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":1016
+ /* "silx/io/specfile.pyx":1020
* return lines_list
*
* def columns(self, scan_index): # <<<<<<<<<<<<<<
@@ -13253,7 +11991,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_39columns(struct __pyx_o
return __pyx_r;
}
-/* "silx/io/specfile.pyx":1037
+/* "silx/io/specfile.pyx":1041
* return ncolumns
*
* def command(self, scan_index): # <<<<<<<<<<<<<<
@@ -13262,20 +12000,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_39columns(struct __pyx_o
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_42command(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_41command[] = "SpecFile.command(self, scan_index)\nReturn ``#S`` line (without ``#S`` and scan number)\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: S line\n :rtype: str\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_42command(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_44command(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_43command[] = "SpecFile.command(self, scan_index)\nReturn ``#S`` line (without ``#S`` and scan number)\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: S line\n :rtype: str\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_44command(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("command (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_41command(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_43command(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_41command(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_43command(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
int __pyx_v_error;
PyObject *__pyx_v_s_record = NULL;
PyObject *__pyx_r = NULL;
@@ -13287,41 +12025,44 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_41command(struct __pyx_o
PyObject *__pyx_t_5 = NULL;
PyObject *__pyx_t_6 = NULL;
PyObject *__pyx_t_7 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("command", 0);
- /* "silx/io/specfile.pyx":1048
+ /* "silx/io/specfile.pyx":1052
* """
* cdef:
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* s_record = <bytes> specfile_wrapper.SfCommand(self.handle,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1048, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1052; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 1048, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1052; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":1051
+ /* "silx/io/specfile.pyx":1055
*
* s_record = <bytes> specfile_wrapper.SfCommand(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* &error)
* self._handle_error(error)
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1051, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1055; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1051, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1055; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1050
+ /* "silx/io/specfile.pyx":1054
* int error = SF_ERR_NO_ERRORS
*
* s_record = <bytes> specfile_wrapper.SfCommand(self.handle, # <<<<<<<<<<<<<<
* scan_index + 1,
* &error)
*/
- __pyx_t_1 = __Pyx_PyBytes_FromString(SfCommand(__pyx_v_self->handle, __pyx_t_3, (&__pyx_v_error))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1050, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyBytes_FromString(SfCommand(__pyx_v_self->handle, __pyx_t_3, (&__pyx_v_error))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1054; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_4 = __pyx_t_1;
__Pyx_INCREF(__pyx_t_4);
@@ -13329,19 +12070,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_41command(struct __pyx_o
__pyx_v_s_record = ((PyObject*)__pyx_t_4);
__pyx_t_4 = 0;
- /* "silx/io/specfile.pyx":1053
+ /* "silx/io/specfile.pyx":1057
* scan_index + 1,
* &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* return s_record.decode()
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1053, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1057; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1053, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1057; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_1))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1);
@@ -13351,44 +12092,24 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_41command(struct __pyx_o
}
}
if (!__pyx_t_6) {
- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1053, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1057; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_4);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_1)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1053, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1053, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1053, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1053, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- }
+ __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1057; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_7, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1057; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- /* "silx/io/specfile.pyx":1055
+ /* "silx/io/specfile.pyx":1059
* self._handle_error(error)
*
* return s_record.decode() # <<<<<<<<<<<<<<
@@ -13398,15 +12119,15 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_41command(struct __pyx_o
__Pyx_XDECREF(__pyx_r);
if (unlikely(__pyx_v_s_record == Py_None)) {
PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", "decode");
- __PYX_ERR(0, 1055, __pyx_L1_error)
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1059; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- __pyx_t_4 = __Pyx_decode_bytes(__pyx_v_s_record, 0, PY_SSIZE_T_MAX, NULL, NULL, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1055, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_decode_bytes(__pyx_v_s_record, 0, PY_SSIZE_T_MAX, NULL, NULL, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1059; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__pyx_r = __pyx_t_4;
__pyx_t_4 = 0;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":1037
+ /* "silx/io/specfile.pyx":1041
* return ncolumns
*
* def command(self, scan_index): # <<<<<<<<<<<<<<
@@ -13430,7 +12151,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_41command(struct __pyx_o
return __pyx_r;
}
-/* "silx/io/specfile.pyx":1057
+/* "silx/io/specfile.pyx":1061
* return s_record.decode()
*
* def date(self, scan_index=0): # <<<<<<<<<<<<<<
@@ -13439,10 +12160,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_41command(struct __pyx_o
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_44date(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_43date[] = "SpecFile.date(self, scan_index=0)\nReturn date from ``#D`` line\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Date from ``#D`` line\n :rtype: str\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_44date(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_46date(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_45date[] = "SpecFile.date(self, scan_index=0)\nReturn date from ``#D`` line\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Date from ``#D`` line\n :rtype: str\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_46date(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_scan_index = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("date (wrapper)", 0);
@@ -13467,7 +12191,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_44date(PyObject *__pyx_v
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "date") < 0)) __PYX_ERR(0, 1057, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "date") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1061; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else {
switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -13480,20 +12204,20 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_44date(PyObject *__pyx_v
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("date", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1057, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("date", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1061; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.SpecFile.date", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
return NULL;
__pyx_L4_argument_unpacking_done:;
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_43date(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index);
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_45date(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index);
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_43date(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45date(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
int __pyx_v_error;
PyObject *__pyx_v_d_line = NULL;
PyObject *__pyx_r = NULL;
@@ -13505,41 +12229,44 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_43date(struct __pyx_obj_
PyObject *__pyx_t_5 = NULL;
PyObject *__pyx_t_6 = NULL;
PyObject *__pyx_t_7 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("date", 0);
- /* "silx/io/specfile.pyx":1068
+ /* "silx/io/specfile.pyx":1072
* """
* cdef:
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* d_line = <bytes> specfile_wrapper.SfDate(self.handle,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1068, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1072; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 1068, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1072; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":1071
+ /* "silx/io/specfile.pyx":1075
*
* d_line = <bytes> specfile_wrapper.SfDate(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* &error)
* self._handle_error(error)
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1071, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1075; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1071, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1075; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1070
+ /* "silx/io/specfile.pyx":1074
* int error = SF_ERR_NO_ERRORS
*
* d_line = <bytes> specfile_wrapper.SfDate(self.handle, # <<<<<<<<<<<<<<
* scan_index + 1,
* &error)
*/
- __pyx_t_1 = __Pyx_PyBytes_FromString(SfDate(__pyx_v_self->handle, __pyx_t_3, (&__pyx_v_error))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1070, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyBytes_FromString(SfDate(__pyx_v_self->handle, __pyx_t_3, (&__pyx_v_error))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1074; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_4 = __pyx_t_1;
__Pyx_INCREF(__pyx_t_4);
@@ -13547,19 +12274,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_43date(struct __pyx_obj_
__pyx_v_d_line = ((PyObject*)__pyx_t_4);
__pyx_t_4 = 0;
- /* "silx/io/specfile.pyx":1073
+ /* "silx/io/specfile.pyx":1077
* scan_index + 1,
* &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* return d_line.decode()
*/
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1073, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1077; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1073, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1077; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_1))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1);
@@ -13569,44 +12296,24 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_43date(struct __pyx_obj_
}
}
if (!__pyx_t_6) {
- __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1073, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1077; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_4);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_1)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1073, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_1)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_1, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1073, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1073, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_7, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1073, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- }
+ __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1077; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_7, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1077; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_4);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- /* "silx/io/specfile.pyx":1075
+ /* "silx/io/specfile.pyx":1079
* self._handle_error(error)
*
* return d_line.decode() # <<<<<<<<<<<<<<
@@ -13616,15 +12323,15 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_43date(struct __pyx_obj_
__Pyx_XDECREF(__pyx_r);
if (unlikely(__pyx_v_d_line == Py_None)) {
PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", "decode");
- __PYX_ERR(0, 1075, __pyx_L1_error)
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1079; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- __pyx_t_4 = __Pyx_decode_bytes(__pyx_v_d_line, 0, PY_SSIZE_T_MAX, NULL, NULL, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1075, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_decode_bytes(__pyx_v_d_line, 0, PY_SSIZE_T_MAX, NULL, NULL, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1079; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__pyx_r = __pyx_t_4;
__pyx_t_4 = 0;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":1057
+ /* "silx/io/specfile.pyx":1061
* return s_record.decode()
*
* def date(self, scan_index=0): # <<<<<<<<<<<<<<
@@ -13648,7 +12355,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_43date(struct __pyx_obj_
return __pyx_r;
}
-/* "silx/io/specfile.pyx":1077
+/* "silx/io/specfile.pyx":1081
* return d_line.decode()
*
* def labels(self, scan_index): # <<<<<<<<<<<<<<
@@ -13657,20 +12364,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_43date(struct __pyx_obj_
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_46labels(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_45labels[] = "SpecFile.labels(self, scan_index)\nReturn all labels from ``#L`` line\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: All labels from ``#L`` line\n :rtype: list of strings\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_46labels(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_48labels(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_47labels[] = "SpecFile.labels(self, scan_index)\nReturn all labels from ``#L`` line\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: All labels from ``#L`` line\n :rtype: list of strings\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_48labels(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("labels (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_47labels(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47labels(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
char **__pyx_v_all_labels;
int __pyx_v_error;
long __pyx_v_nlabels;
@@ -13688,34 +12395,37 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(struct __pyx_ob
long __pyx_t_8;
char *__pyx_t_9;
int __pyx_t_10;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("labels", 0);
- /* "silx/io/specfile.pyx":1089
+ /* "silx/io/specfile.pyx":1093
* cdef:
* char** all_labels
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* nlabels = specfile_wrapper.SfAllLabels(self.handle,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1089, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1093; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 1089, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1093; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":1092
+ /* "silx/io/specfile.pyx":1096
*
* nlabels = specfile_wrapper.SfAllLabels(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* &all_labels,
* &error)
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1092, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1096; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1092, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1096; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1091
+ /* "silx/io/specfile.pyx":1095
* int error = SF_ERR_NO_ERRORS
*
* nlabels = specfile_wrapper.SfAllLabels(self.handle, # <<<<<<<<<<<<<<
@@ -13724,19 +12434,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(struct __pyx_ob
*/
__pyx_v_nlabels = SfAllLabels(__pyx_v_self->handle, __pyx_t_3, (&__pyx_v_all_labels), (&__pyx_v_error));
- /* "silx/io/specfile.pyx":1095
+ /* "silx/io/specfile.pyx":1099
* &all_labels,
* &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* labels_list = []
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1095, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1099; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1095, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1099; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -13746,56 +12456,36 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(struct __pyx_ob
}
}
if (!__pyx_t_6) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1095, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1099; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1095, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1095, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1095, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1095, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- }
+ __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1099; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1099; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1097
+ /* "silx/io/specfile.pyx":1101
* self._handle_error(error)
*
* labels_list = [] # <<<<<<<<<<<<<<
* for i in range(nlabels):
* labels_list.append(<bytes>all_labels[i].decode())
*/
- __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1097, __pyx_L1_error)
+ __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_v_labels_list = ((PyObject*)__pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1098
+ /* "silx/io/specfile.pyx":1102
*
* labels_list = []
* for i in range(nlabels): # <<<<<<<<<<<<<<
@@ -13806,7 +12496,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(struct __pyx_ob
for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_3; __pyx_t_8+=1) {
__pyx_v_i = __pyx_t_8;
- /* "silx/io/specfile.pyx":1099
+ /* "silx/io/specfile.pyx":1103
* labels_list = []
* for i in range(nlabels):
* labels_list.append(<bytes>all_labels[i].decode()) # <<<<<<<<<<<<<<
@@ -13814,13 +12504,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(struct __pyx_ob
* specfile_wrapper.freeArrNZ(<void***>&all_labels, nlabels)
*/
__pyx_t_9 = (__pyx_v_all_labels[__pyx_v_i]);
- __pyx_t_1 = __Pyx_decode_c_string(__pyx_t_9, 0, strlen(__pyx_t_9), NULL, NULL, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1099, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_decode_c_string(__pyx_t_9, 0, strlen(__pyx_t_9), NULL, NULL, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_10 = __Pyx_PyList_Append(__pyx_v_labels_list, __pyx_t_1); if (unlikely(__pyx_t_10 == -1)) __PYX_ERR(0, 1099, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyList_Append(__pyx_v_labels_list, __pyx_t_1); if (unlikely(__pyx_t_10 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
}
- /* "silx/io/specfile.pyx":1101
+ /* "silx/io/specfile.pyx":1105
* labels_list.append(<bytes>all_labels[i].decode())
*
* specfile_wrapper.freeArrNZ(<void***>&all_labels, nlabels) # <<<<<<<<<<<<<<
@@ -13829,7 +12519,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(struct __pyx_ob
*/
freeArrNZ(((void ***)(&__pyx_v_all_labels)), __pyx_v_nlabels);
- /* "silx/io/specfile.pyx":1102
+ /* "silx/io/specfile.pyx":1106
*
* specfile_wrapper.freeArrNZ(<void***>&all_labels, nlabels)
* return labels_list # <<<<<<<<<<<<<<
@@ -13841,7 +12531,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(struct __pyx_ob
__pyx_r = __pyx_v_labels_list;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":1077
+ /* "silx/io/specfile.pyx":1081
* return d_line.decode()
*
* def labels(self, scan_index): # <<<<<<<<<<<<<<
@@ -13865,7 +12555,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(struct __pyx_ob
return __pyx_r;
}
-/* "silx/io/specfile.pyx":1104
+/* "silx/io/specfile.pyx":1108
* return labels_list
*
* def motor_names(self, scan_index=0): # <<<<<<<<<<<<<<
@@ -13874,10 +12564,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_45labels(struct __pyx_ob
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_48motor_names(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_47motor_names[] = "SpecFile.motor_names(self, scan_index=0)\nReturn all motor names from ``#O`` lines\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.If not specified, defaults to 0 (meaning the\n function returns motors names associated with the first scan).\n This parameter makes a difference only if there are more than\n on file header in the file, in which case the file header applies\n to all following scans until a new file header appears.\n :type scan_index: int\n\n :return: All motor names\n :rtype: list of strings\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_48motor_names(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_50motor_names(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_49motor_names[] = "SpecFile.motor_names(self, scan_index=0)\nReturn all motor names from ``#O`` lines\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.If not specified, defaults to 0 (meaning the\n function returns motors names associated with the first scan).\n This parameter makes a difference only if there are more than\n on file header in the file, in which case the file header applies\n to all following scans until a new file header appears.\n :type scan_index: int\n\n :return: All motor names\n :rtype: list of strings\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_50motor_names(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_scan_index = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("motor_names (wrapper)", 0);
@@ -13902,7 +12595,7 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_48motor_names(PyObject *
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "motor_names") < 0)) __PYX_ERR(0, 1104, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "motor_names") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1108; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else {
switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -13915,20 +12608,20 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_48motor_names(PyObject *
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("motor_names", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1104, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("motor_names", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1108; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.SpecFile.motor_names", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
return NULL;
__pyx_L4_argument_unpacking_done:;
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index);
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_names(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index);
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_names(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
char **__pyx_v_all_motors;
int __pyx_v_error;
long __pyx_v_nmotors;
@@ -13946,34 +12639,37 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(struct __p
long __pyx_t_8;
char *__pyx_t_9;
int __pyx_t_10;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("motor_names", 0);
- /* "silx/io/specfile.pyx":1120
+ /* "silx/io/specfile.pyx":1124
* cdef:
* char** all_motors
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* nmotors = specfile_wrapper.SfAllMotors(self.handle,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1120, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1124; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 1120, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1124; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":1123
+ /* "silx/io/specfile.pyx":1127
*
* nmotors = specfile_wrapper.SfAllMotors(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* &all_motors,
* &error)
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1123, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1127; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1123, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1127; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1122
+ /* "silx/io/specfile.pyx":1126
* int error = SF_ERR_NO_ERRORS
*
* nmotors = specfile_wrapper.SfAllMotors(self.handle, # <<<<<<<<<<<<<<
@@ -13982,19 +12678,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(struct __p
*/
__pyx_v_nmotors = SfAllMotors(__pyx_v_self->handle, __pyx_t_3, (&__pyx_v_all_motors), (&__pyx_v_error));
- /* "silx/io/specfile.pyx":1126
+ /* "silx/io/specfile.pyx":1130
* &all_motors,
* &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* motors_list = []
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1126, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1126, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -14004,56 +12700,36 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(struct __p
}
}
if (!__pyx_t_6) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1126, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1126, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1126, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1126, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1126, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- }
+ __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1128
+ /* "silx/io/specfile.pyx":1132
* self._handle_error(error)
*
* motors_list = [] # <<<<<<<<<<<<<<
* for i in range(nmotors):
* motors_list.append(<bytes>all_motors[i].decode())
*/
- __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1128, __pyx_L1_error)
+ __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1132; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_v_motors_list = ((PyObject*)__pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1129
+ /* "silx/io/specfile.pyx":1133
*
* motors_list = []
* for i in range(nmotors): # <<<<<<<<<<<<<<
@@ -14064,7 +12740,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(struct __p
for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_3; __pyx_t_8+=1) {
__pyx_v_i = __pyx_t_8;
- /* "silx/io/specfile.pyx":1130
+ /* "silx/io/specfile.pyx":1134
* motors_list = []
* for i in range(nmotors):
* motors_list.append(<bytes>all_motors[i].decode()) # <<<<<<<<<<<<<<
@@ -14072,13 +12748,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(struct __p
* specfile_wrapper.freeArrNZ(<void***>&all_motors, nmotors)
*/
__pyx_t_9 = (__pyx_v_all_motors[__pyx_v_i]);
- __pyx_t_1 = __Pyx_decode_c_string(__pyx_t_9, 0, strlen(__pyx_t_9), NULL, NULL, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1130, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_decode_c_string(__pyx_t_9, 0, strlen(__pyx_t_9), NULL, NULL, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1134; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_10 = __Pyx_PyList_Append(__pyx_v_motors_list, __pyx_t_1); if (unlikely(__pyx_t_10 == -1)) __PYX_ERR(0, 1130, __pyx_L1_error)
+ __pyx_t_10 = __Pyx_PyList_Append(__pyx_v_motors_list, __pyx_t_1); if (unlikely(__pyx_t_10 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1134; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
}
- /* "silx/io/specfile.pyx":1132
+ /* "silx/io/specfile.pyx":1136
* motors_list.append(<bytes>all_motors[i].decode())
*
* specfile_wrapper.freeArrNZ(<void***>&all_motors, nmotors) # <<<<<<<<<<<<<<
@@ -14087,7 +12763,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(struct __p
*/
freeArrNZ(((void ***)(&__pyx_v_all_motors)), __pyx_v_nmotors);
- /* "silx/io/specfile.pyx":1133
+ /* "silx/io/specfile.pyx":1137
*
* specfile_wrapper.freeArrNZ(<void***>&all_motors, nmotors)
* return motors_list # <<<<<<<<<<<<<<
@@ -14099,7 +12775,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(struct __p
__pyx_r = __pyx_v_motors_list;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":1104
+ /* "silx/io/specfile.pyx":1108
* return labels_list
*
* def motor_names(self, scan_index=0): # <<<<<<<<<<<<<<
@@ -14123,7 +12799,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(struct __p
return __pyx_r;
}
-/* "silx/io/specfile.pyx":1135
+/* "silx/io/specfile.pyx":1139
* return motors_list
*
* def motor_positions(self, scan_index): # <<<<<<<<<<<<<<
@@ -14132,20 +12808,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_47motor_names(struct __p
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_50motor_positions(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_49motor_positions[] = "SpecFile.motor_positions(self, scan_index)\nReturn all motor positions\n\n :param scan_index: Unique scan index between ``0``\n and ``len(self)-1``.\n :type scan_index: int\n\n :return: All motor positions\n :rtype: list of double\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_50motor_positions(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_52motor_positions(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_51motor_positions[] = "SpecFile.motor_positions(self, scan_index)\nReturn all motor positions\n\n :param scan_index: Unique scan index between ``0``\n and ``len(self)-1``.\n :type scan_index: int\n\n :return: All motor positions\n :rtype: list of double\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_52motor_positions(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("motor_positions (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_positions(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_positions(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_positions(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_positions(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
double *__pyx_v_motor_positions;
int __pyx_v_error;
long __pyx_v_nmotors;
@@ -14162,34 +12838,37 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_positions(struct
PyObject *__pyx_t_7 = NULL;
long __pyx_t_8;
int __pyx_t_9;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("motor_positions", 0);
- /* "silx/io/specfile.pyx":1147
+ /* "silx/io/specfile.pyx":1151
* cdef:
* double* motor_positions
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* nmotors = specfile_wrapper.SfAllMotorPos(self.handle,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1147, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1151; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 1147, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1151; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":1150
+ /* "silx/io/specfile.pyx":1154
*
* nmotors = specfile_wrapper.SfAllMotorPos(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* &motor_positions,
* &error)
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1150, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1154; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1150, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1154; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1149
+ /* "silx/io/specfile.pyx":1153
* int error = SF_ERR_NO_ERRORS
*
* nmotors = specfile_wrapper.SfAllMotorPos(self.handle, # <<<<<<<<<<<<<<
@@ -14198,19 +12877,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_positions(struct
*/
__pyx_v_nmotors = SfAllMotorPos(__pyx_v_self->handle, __pyx_t_3, (&__pyx_v_motor_positions), (&__pyx_v_error));
- /* "silx/io/specfile.pyx":1153
+ /* "silx/io/specfile.pyx":1157
* &motor_positions,
* &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* motor_positions_list = []
*/
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1153, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1153, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_4))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_6)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
@@ -14220,56 +12899,36 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_positions(struct
}
}
if (!__pyx_t_6) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1153, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1153, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
- PyObject *__pyx_temp[2] = {__pyx_t_6, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1153, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1153, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __Pyx_GIVEREF(__pyx_t_6); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __pyx_t_6 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1153, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- }
+ __pyx_t_7 = PyTuple_New(1+1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_7);
+ PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); __pyx_t_6 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_7, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_7, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1155
+ /* "silx/io/specfile.pyx":1159
* self._handle_error(error)
*
* motor_positions_list = [] # <<<<<<<<<<<<<<
* for i in range(nmotors):
* motor_positions_list.append(motor_positions[i])
*/
- __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1155, __pyx_L1_error)
+ __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1159; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_v_motor_positions_list = ((PyObject*)__pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1156
+ /* "silx/io/specfile.pyx":1160
*
* motor_positions_list = []
* for i in range(nmotors): # <<<<<<<<<<<<<<
@@ -14280,20 +12939,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_positions(struct
for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_3; __pyx_t_8+=1) {
__pyx_v_i = __pyx_t_8;
- /* "silx/io/specfile.pyx":1157
+ /* "silx/io/specfile.pyx":1161
* motor_positions_list = []
* for i in range(nmotors):
* motor_positions_list.append(motor_positions[i]) # <<<<<<<<<<<<<<
*
* free(motor_positions)
*/
- __pyx_t_1 = PyFloat_FromDouble((__pyx_v_motor_positions[__pyx_v_i])); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1157, __pyx_L1_error)
+ __pyx_t_1 = PyFloat_FromDouble((__pyx_v_motor_positions[__pyx_v_i])); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1161; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_9 = __Pyx_PyList_Append(__pyx_v_motor_positions_list, __pyx_t_1); if (unlikely(__pyx_t_9 == -1)) __PYX_ERR(0, 1157, __pyx_L1_error)
+ __pyx_t_9 = __Pyx_PyList_Append(__pyx_v_motor_positions_list, __pyx_t_1); if (unlikely(__pyx_t_9 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1161; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
}
- /* "silx/io/specfile.pyx":1159
+ /* "silx/io/specfile.pyx":1163
* motor_positions_list.append(motor_positions[i])
*
* free(motor_positions) # <<<<<<<<<<<<<<
@@ -14302,7 +12961,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_positions(struct
*/
free(__pyx_v_motor_positions);
- /* "silx/io/specfile.pyx":1160
+ /* "silx/io/specfile.pyx":1164
*
* free(motor_positions)
* return motor_positions_list # <<<<<<<<<<<<<<
@@ -14314,7 +12973,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_positions(struct
__pyx_r = __pyx_v_motor_positions_list;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":1135
+ /* "silx/io/specfile.pyx":1139
* return motors_list
*
* def motor_positions(self, scan_index): # <<<<<<<<<<<<<<
@@ -14338,7 +12997,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_positions(struct
return __pyx_r;
}
-/* "silx/io/specfile.pyx":1162
+/* "silx/io/specfile.pyx":1166
* return motor_positions_list
*
* def motor_position_by_name(self, scan_index, name): # <<<<<<<<<<<<<<
@@ -14347,11 +13006,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_49motor_positions(struct
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_52motor_position_by_name(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_51motor_position_by_name[] = "SpecFile.motor_position_by_name(self, scan_index, name)\nReturn motor position\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Specified motor position\n :rtype: double\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_52motor_position_by_name(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_54motor_position_by_name(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_53motor_position_by_name[] = "SpecFile.motor_position_by_name(self, scan_index, name)\nReturn motor position\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Specified motor position\n :rtype: double\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_54motor_position_by_name(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_scan_index = 0;
PyObject *__pyx_v_name = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("motor_position_by_name (wrapper)", 0);
@@ -14375,11 +13037,11 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_52motor_position_by_name
case 1:
if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_name)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("motor_position_by_name", 1, 2, 2, 1); __PYX_ERR(0, 1162, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("motor_position_by_name", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1166; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "motor_position_by_name") < 0)) __PYX_ERR(0, 1162, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "motor_position_by_name") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1166; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
goto __pyx_L5_argtuple_error;
@@ -14392,20 +13054,20 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_52motor_position_by_name
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("motor_position_by_name", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1162, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("motor_position_by_name", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1166; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.SpecFile.motor_position_by_name", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
return NULL;
__pyx_L4_argument_unpacking_done:;
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_position_by_name(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index, __pyx_v_name);
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_53motor_position_by_name(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index, __pyx_v_name);
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_position_by_name(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_name) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_53motor_position_by_name(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_name) {
int __pyx_v_error;
double __pyx_v_motor_position;
PyObject *__pyx_r = NULL;
@@ -14418,33 +13080,36 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_position_by_name
long __pyx_t_6;
char *__pyx_t_7;
PyObject *__pyx_t_8 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("motor_position_by_name", 0);
__Pyx_INCREF(__pyx_v_name);
- /* "silx/io/specfile.pyx":1173
+ /* "silx/io/specfile.pyx":1177
* """
* cdef:
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* name = _string_to_char_star(name)
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1173, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1177; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 1173, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1177; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":1175
+ /* "silx/io/specfile.pyx":1179
* int error = SF_ERR_NO_ERRORS
*
* name = _string_to_char_star(name) # <<<<<<<<<<<<<<
*
* motor_position = specfile_wrapper.SfMotorPosByName(self.handle,
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_string_to_char_star); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1175, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_string_to_char_star); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1179; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -14454,63 +13119,45 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_position_by_name
}
}
if (!__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_name); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1175, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_name); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1179; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_v_name};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1175, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_v_name};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1175, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- } else
- #endif
- {
- __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1175, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __pyx_t_4 = NULL;
- __Pyx_INCREF(__pyx_v_name);
- __Pyx_GIVEREF(__pyx_v_name);
- PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_v_name);
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1175, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- }
+ __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1179; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_5);
+ PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
+ __Pyx_INCREF(__pyx_v_name);
+ PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_v_name);
+ __Pyx_GIVEREF(__pyx_v_name);
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1179; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF_SET(__pyx_v_name, __pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1178
+ /* "silx/io/specfile.pyx":1182
*
* motor_position = specfile_wrapper.SfMotorPosByName(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* name,
* &error)
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1178, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1182; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_6 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_6 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1178, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_6 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1182; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1179
+ /* "silx/io/specfile.pyx":1183
* motor_position = specfile_wrapper.SfMotorPosByName(self.handle,
* scan_index + 1,
* name, # <<<<<<<<<<<<<<
* &error)
* self._handle_error(error)
*/
- __pyx_t_7 = __Pyx_PyObject_AsString(__pyx_v_name); if (unlikely((!__pyx_t_7) && PyErr_Occurred())) __PYX_ERR(0, 1179, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_AsString(__pyx_v_name); if (unlikely((!__pyx_t_7) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1183; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
- /* "silx/io/specfile.pyx":1177
+ /* "silx/io/specfile.pyx":1181
* name = _string_to_char_star(name)
*
* motor_position = specfile_wrapper.SfMotorPosByName(self.handle, # <<<<<<<<<<<<<<
@@ -14519,19 +13166,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_position_by_name
*/
__pyx_v_motor_position = SfMotorPosByName(__pyx_v_self->handle, __pyx_t_6, __pyx_t_7, (&__pyx_v_error));
- /* "silx/io/specfile.pyx":1181
+ /* "silx/io/specfile.pyx":1185
* name,
* &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* return motor_position
*/
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1181, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1185; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1181, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1185; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -14541,44 +13188,24 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_position_by_name
}
}
if (!__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1181, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_5); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1185; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1181, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_5};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1181, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- } else
- #endif
- {
- __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1181, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_4); __pyx_t_4 = NULL;
- __Pyx_GIVEREF(__pyx_t_5);
- PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_5);
- __pyx_t_5 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1181, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- }
+ __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1185; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
+ PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_5);
+ __Pyx_GIVEREF(__pyx_t_5);
+ __pyx_t_5 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1185; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1183
+ /* "silx/io/specfile.pyx":1187
* self._handle_error(error)
*
* return motor_position # <<<<<<<<<<<<<<
@@ -14586,13 +13213,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_position_by_name
* def number_of_mca(self, scan_index):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = PyFloat_FromDouble(__pyx_v_motor_position); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1183, __pyx_L1_error)
+ __pyx_t_1 = PyFloat_FromDouble(__pyx_v_motor_position); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1187; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":1162
+ /* "silx/io/specfile.pyx":1166
* return motor_positions_list
*
* def motor_position_by_name(self, scan_index, name): # <<<<<<<<<<<<<<
@@ -14616,7 +13243,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_position_by_name
return __pyx_r;
}
-/* "silx/io/specfile.pyx":1185
+/* "silx/io/specfile.pyx":1189
* return motor_position
*
* def number_of_mca(self, scan_index): # <<<<<<<<<<<<<<
@@ -14625,20 +13252,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_51motor_position_by_name
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_54number_of_mca(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_53number_of_mca[] = "SpecFile.number_of_mca(self, scan_index)\nReturn number of mca spectra in a scan.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Number of mca spectra.\n :rtype: int\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_54number_of_mca(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_56number_of_mca(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_55number_of_mca[] = "SpecFile.number_of_mca(self, scan_index)\nReturn number of mca spectra in a scan.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: Number of mca spectra.\n :rtype: int\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_56number_of_mca(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("number_of_mca (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_53number_of_mca(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_55number_of_mca(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_53number_of_mca(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55number_of_mca(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
int __pyx_v_error;
long __pyx_v_num_mca;
PyObject *__pyx_r = NULL;
@@ -14651,34 +13278,37 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_53number_of_mca(struct _
PyObject *__pyx_t_6 = NULL;
PyObject *__pyx_t_7 = NULL;
PyObject *__pyx_t_8 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("number_of_mca", 0);
- /* "silx/io/specfile.pyx":1196
+ /* "silx/io/specfile.pyx":1200
* """
* cdef:
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
*
* num_mca = specfile_wrapper.SfNoMca(self.handle,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1196, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1200; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 1196, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1200; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":1199
+ /* "silx/io/specfile.pyx":1203
*
* num_mca = specfile_wrapper.SfNoMca(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* &error)
* # error code updating isn't implemented in SfNoMCA
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1199, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1203; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1199, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1203; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1198
+ /* "silx/io/specfile.pyx":1202
* int error = SF_ERR_NO_ERRORS
*
* num_mca = specfile_wrapper.SfNoMca(self.handle, # <<<<<<<<<<<<<<
@@ -14687,29 +13317,29 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_53number_of_mca(struct _
*/
__pyx_v_num_mca = SfNoMca(__pyx_v_self->handle, __pyx_t_3, (&__pyx_v_error));
- /* "silx/io/specfile.pyx":1202
+ /* "silx/io/specfile.pyx":1206
* &error)
* # error code updating isn't implemented in SfNoMCA
* if num_mca == -1: # <<<<<<<<<<<<<<
* raise SfNoMcaError("Failed to retrieve number of MCA " +
* "(SfNoMca returned -1)")
*/
- __pyx_t_4 = ((__pyx_v_num_mca == -1L) != 0);
+ __pyx_t_4 = ((__pyx_v_num_mca == -1) != 0);
if (__pyx_t_4) {
- /* "silx/io/specfile.pyx":1203
+ /* "silx/io/specfile.pyx":1207
* # error code updating isn't implemented in SfNoMCA
* if num_mca == -1:
* raise SfNoMcaError("Failed to retrieve number of MCA " + # <<<<<<<<<<<<<<
* "(SfNoMca returned -1)")
* return num_mca
*/
- __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfNoMcaError); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1203, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfNoMcaError); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1207; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_6 = PyNumber_Add(__pyx_kp_s_Failed_to_retrieve_number_of_MCA, __pyx_kp_s_SfNoMca_returned_1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1203, __pyx_L1_error)
+ __pyx_t_6 = PyNumber_Add(__pyx_kp_s_Failed_to_retrieve_number_of_MCA, __pyx_kp_s_SfNoMca_returned_1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1207; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__pyx_t_7 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_5))) {
__pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5);
if (likely(__pyx_t_7)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
@@ -14719,55 +13349,27 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_53number_of_mca(struct _
}
}
if (!__pyx_t_7) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1203, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1207; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_6};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1203, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_6};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1203, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- } else
- #endif
- {
- __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1203, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL;
- __Pyx_GIVEREF(__pyx_t_6);
- PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_6);
- __pyx_t_6 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1203, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- }
+ __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1207; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
+ PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __Pyx_GIVEREF(__pyx_t_7); __pyx_t_7 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_6);
+ __Pyx_GIVEREF(__pyx_t_6);
+ __pyx_t_6 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1207; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_Raise(__pyx_t_1, 0, 0, 0);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __PYX_ERR(0, 1203, __pyx_L1_error)
-
- /* "silx/io/specfile.pyx":1202
- * &error)
- * # error code updating isn't implemented in SfNoMCA
- * if num_mca == -1: # <<<<<<<<<<<<<<
- * raise SfNoMcaError("Failed to retrieve number of MCA " +
- * "(SfNoMca returned -1)")
- */
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1207; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- /* "silx/io/specfile.pyx":1205
+ /* "silx/io/specfile.pyx":1209
* raise SfNoMcaError("Failed to retrieve number of MCA " +
* "(SfNoMca returned -1)")
* return num_mca # <<<<<<<<<<<<<<
@@ -14775,13 +13377,13 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_53number_of_mca(struct _
* def mca_calibration(self, scan_index):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_num_mca); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1205, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_num_mca); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1209; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":1185
+ /* "silx/io/specfile.pyx":1189
* return motor_position
*
* def number_of_mca(self, scan_index): # <<<<<<<<<<<<<<
@@ -14804,7 +13406,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_53number_of_mca(struct _
return __pyx_r;
}
-/* "silx/io/specfile.pyx":1207
+/* "silx/io/specfile.pyx":1211
* return num_mca
*
* def mca_calibration(self, scan_index): # <<<<<<<<<<<<<<
@@ -14813,20 +13415,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_53number_of_mca(struct _
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_56mca_calibration(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_55mca_calibration[] = "SpecFile.mca_calibration(self, scan_index)\nReturn MCA calibration in the form :math:`a + b x + c x\302\262`\n\n Raise a KeyError if there is no ``@CALIB`` line in the scan header.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: MCA calibration as a list of 3 values :math:`(a, b, c)`\n :rtype: list of floats\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_56mca_calibration(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_58mca_calibration(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_57mca_calibration[] = "SpecFile.mca_calibration(self, scan_index)\nReturn MCA calibration in the form :math:`a + b x + c x\302\262`\n\n Raise a KeyError if there is no ``@CALIB`` line in the scan header.\n\n :param scan_index: Unique scan index between ``0`` and\n ``len(self)-1``.\n :type scan_index: int\n\n :return: MCA calibration as a list of 3 values :math:`(a, b, c)`\n :rtype: list of floats\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_58mca_calibration(PyObject *__pyx_v_self, PyObject *__pyx_v_scan_index) {
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("mca_calibration (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_55mca_calibration(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_57mca_calibration(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), ((PyObject *)__pyx_v_scan_index));
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55mca_calibration(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_57mca_calibration(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index) {
int __pyx_v_error;
double *__pyx_v_mca_calib;
long __pyx_v_mca_calib_error;
@@ -14839,34 +13441,37 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55mca_calibration(struct
long __pyx_t_3;
int __pyx_t_4;
int __pyx_t_5;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("mca_calibration", 0);
- /* "silx/io/specfile.pyx":1220
+ /* "silx/io/specfile.pyx":1224
* """
* cdef:
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
* double* mca_calib
*
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1220, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1224; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 1220, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1224; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":1224
+ /* "silx/io/specfile.pyx":1228
*
* mca_calib_error = specfile_wrapper.SfMcaCalib(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* &mca_calib,
* &error)
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1224, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1228; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1224, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1228; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1223
+ /* "silx/io/specfile.pyx":1227
* double* mca_calib
*
* mca_calib_error = specfile_wrapper.SfMcaCalib(self.handle, # <<<<<<<<<<<<<<
@@ -14875,7 +13480,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55mca_calibration(struct
*/
__pyx_v_mca_calib_error = SfMcaCalib(__pyx_v_self->handle, __pyx_t_3, (&__pyx_v_mca_calib), (&__pyx_v_error));
- /* "silx/io/specfile.pyx":1229
+ /* "silx/io/specfile.pyx":1233
*
* # error code updating isn't implemented in SfMcaCalib
* if mca_calib_error: # <<<<<<<<<<<<<<
@@ -14885,41 +13490,33 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55mca_calibration(struct
__pyx_t_4 = (__pyx_v_mca_calib_error != 0);
if (__pyx_t_4) {
- /* "silx/io/specfile.pyx":1230
+ /* "silx/io/specfile.pyx":1234
* # error code updating isn't implemented in SfMcaCalib
* if mca_calib_error:
* raise KeyError("MCA calibration line (@CALIB) not found") # <<<<<<<<<<<<<<
*
* mca_calib_list = []
*/
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_KeyError, __pyx_tuple__29, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1230, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_KeyError, __pyx_tuple__33, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1234; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_Raise(__pyx_t_1, 0, 0, 0);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __PYX_ERR(0, 1230, __pyx_L1_error)
-
- /* "silx/io/specfile.pyx":1229
- *
- * # error code updating isn't implemented in SfMcaCalib
- * if mca_calib_error: # <<<<<<<<<<<<<<
- * raise KeyError("MCA calibration line (@CALIB) not found")
- *
- */
+ {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1234; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- /* "silx/io/specfile.pyx":1232
+ /* "silx/io/specfile.pyx":1236
* raise KeyError("MCA calibration line (@CALIB) not found")
*
* mca_calib_list = [] # <<<<<<<<<<<<<<
* for i in range(3):
* mca_calib_list.append(mca_calib[i])
*/
- __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1232, __pyx_L1_error)
+ __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1236; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_v_mca_calib_list = ((PyObject*)__pyx_t_1);
__pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1233
+ /* "silx/io/specfile.pyx":1237
*
* mca_calib_list = []
* for i in range(3): # <<<<<<<<<<<<<<
@@ -14929,20 +13526,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55mca_calibration(struct
for (__pyx_t_3 = 0; __pyx_t_3 < 3; __pyx_t_3+=1) {
__pyx_v_i = __pyx_t_3;
- /* "silx/io/specfile.pyx":1234
+ /* "silx/io/specfile.pyx":1238
* mca_calib_list = []
* for i in range(3):
* mca_calib_list.append(mca_calib[i]) # <<<<<<<<<<<<<<
*
* free(mca_calib)
*/
- __pyx_t_1 = PyFloat_FromDouble((__pyx_v_mca_calib[__pyx_v_i])); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1234, __pyx_L1_error)
+ __pyx_t_1 = PyFloat_FromDouble((__pyx_v_mca_calib[__pyx_v_i])); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1238; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_PyList_Append(__pyx_v_mca_calib_list, __pyx_t_1); if (unlikely(__pyx_t_5 == -1)) __PYX_ERR(0, 1234, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyList_Append(__pyx_v_mca_calib_list, __pyx_t_1); if (unlikely(__pyx_t_5 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1238; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
}
- /* "silx/io/specfile.pyx":1236
+ /* "silx/io/specfile.pyx":1240
* mca_calib_list.append(mca_calib[i])
*
* free(mca_calib) # <<<<<<<<<<<<<<
@@ -14951,7 +13548,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55mca_calibration(struct
*/
free(__pyx_v_mca_calib);
- /* "silx/io/specfile.pyx":1237
+ /* "silx/io/specfile.pyx":1241
*
* free(mca_calib)
* return mca_calib_list # <<<<<<<<<<<<<<
@@ -14963,7 +13560,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55mca_calibration(struct
__pyx_r = __pyx_v_mca_calib_list;
goto __pyx_L0;
- /* "silx/io/specfile.pyx":1207
+ /* "silx/io/specfile.pyx":1211
* return num_mca
*
* def mca_calibration(self, scan_index): # <<<<<<<<<<<<<<
@@ -14983,7 +13580,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55mca_calibration(struct
return __pyx_r;
}
-/* "silx/io/specfile.pyx":1239
+/* "silx/io/specfile.pyx":1243
* return mca_calib_list
*
* def get_mca(self, scan_index, mca_index): # <<<<<<<<<<<<<<
@@ -14992,11 +13589,14 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_55mca_calibration(struct
*/
/* Python wrapper */
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_58get_mca(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static char __pyx_doc_4silx_2io_8specfile_8SpecFile_57get_mca[] = "SpecFile.get_mca(self, scan_index, mca_index)\nReturn one MCA spectrum\n\n :param scan_index: Unique scan index between ``0`` and ``len(self)-1``.\n :type scan_index: int\n :param mca_index: Index of MCA in the scan\n :type mca_index: int\n\n :return: MCA spectrum\n :rtype: 1D numpy array\n ";
-static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_58get_mca(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_60get_mca(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static char __pyx_doc_4silx_2io_8specfile_8SpecFile_59get_mca[] = "SpecFile.get_mca(self, scan_index, mca_index)\nReturn one MCA spectrum\n\n :param scan_index: Unique scan index between ``0`` and ``len(self)-1``.\n :type scan_index: int\n :param mca_index: Index of MCA in the scan\n :type mca_index: int\n\n :return: MCA spectrum\n :rtype: 1D numpy array\n ";
+static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_60get_mca(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_v_scan_index = 0;
PyObject *__pyx_v_mca_index = 0;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
PyObject *__pyx_r = 0;
__Pyx_RefNannyDeclarations
__Pyx_RefNannySetupContext("get_mca (wrapper)", 0);
@@ -15020,11 +13620,11 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_58get_mca(PyObject *__py
case 1:
if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_mca_index)) != 0)) kw_args--;
else {
- __Pyx_RaiseArgtupleInvalid("get_mca", 1, 2, 2, 1); __PYX_ERR(0, 1239, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("get_mca", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1243; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
}
if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "get_mca") < 0)) __PYX_ERR(0, 1239, __pyx_L3_error)
+ if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "get_mca") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1243; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
}
} else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
goto __pyx_L5_argtuple_error;
@@ -15037,20 +13637,20 @@ static PyObject *__pyx_pw_4silx_2io_8specfile_8SpecFile_58get_mca(PyObject *__py
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("get_mca", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 1239, __pyx_L3_error)
+ __Pyx_RaiseArgtupleInvalid("get_mca", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1243; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
__pyx_L3_error:;
__Pyx_AddTraceback("silx.io.specfile.SpecFile.get_mca", __pyx_clineno, __pyx_lineno, __pyx_filename);
__Pyx_RefNannyFinishContext();
return NULL;
__pyx_L4_argument_unpacking_done:;
- __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_57get_mca(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index, __pyx_v_mca_index);
+ __pyx_r = __pyx_pf_4silx_2io_8specfile_8SpecFile_59get_mca(((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)__pyx_v_self), __pyx_v_scan_index, __pyx_v_mca_index);
/* function exit code */
__Pyx_RefNannyFinishContext();
return __pyx_r;
}
-static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_57get_mca(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_mca_index) {
+static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_59get_mca(struct __pyx_obj_4silx_2io_8specfile_SpecFile *__pyx_v_self, PyObject *__pyx_v_scan_index, PyObject *__pyx_v_mca_index) {
int __pyx_v_error;
double *__pyx_v_mca_data;
long __pyx_v_len_mca;
@@ -15066,46 +13666,49 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_57get_mca(struct __pyx_o
PyObject *__pyx_t_6 = NULL;
PyObject *__pyx_t_7 = NULL;
PyObject *__pyx_t_8 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("get_mca", 0);
- /* "silx/io/specfile.pyx":1251
+ /* "silx/io/specfile.pyx":1255
* """
* cdef:
* int error = SF_ERR_NO_ERRORS # <<<<<<<<<<<<<<
* double* mca_data
* long len_mca
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1251, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SF_ERR_NO_ERRORS); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1255; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 1251, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyInt_As_int(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1255; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_v_error = __pyx_t_2;
- /* "silx/io/specfile.pyx":1256
+ /* "silx/io/specfile.pyx":1260
*
* len_mca = specfile_wrapper.SfGetMca(self.handle,
* scan_index + 1, # <<<<<<<<<<<<<<
* mca_index + 1,
* &mca_data,
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_scan_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1256, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_scan_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1260; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1256, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_3 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1260; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1257
+ /* "silx/io/specfile.pyx":1261
* len_mca = specfile_wrapper.SfGetMca(self.handle,
* scan_index + 1,
* mca_index + 1, # <<<<<<<<<<<<<<
* &mca_data,
* &error)
*/
- __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_v_mca_index, __pyx_int_1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1257, __pyx_L1_error)
+ __pyx_t_1 = PyNumber_Add(__pyx_v_mca_index, __pyx_int_1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1261; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_4 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_4 == (long)-1) && PyErr_Occurred())) __PYX_ERR(0, 1257, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyInt_As_long(__pyx_t_1); if (unlikely((__pyx_t_4 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1261; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1255
+ /* "silx/io/specfile.pyx":1259
* long len_mca
*
* len_mca = specfile_wrapper.SfGetMca(self.handle, # <<<<<<<<<<<<<<
@@ -15114,19 +13717,19 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_57get_mca(struct __pyx_o
*/
__pyx_v_len_mca = SfGetMca(__pyx_v_self->handle, __pyx_t_3, __pyx_t_4, (&__pyx_v_mca_data), (&__pyx_v_error));
- /* "silx/io/specfile.pyx":1260
+ /* "silx/io/specfile.pyx":1264
* &mca_data,
* &error)
* self._handle_error(error) # <<<<<<<<<<<<<<
*
* cdef numpy.ndarray ret_array = numpy.empty((len_mca,),
*/
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1260, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_handle_error); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_6 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1260, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyInt_From_int(__pyx_v_error); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__pyx_t_7 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_5))) {
__pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5);
if (likely(__pyx_t_7)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
@@ -15136,102 +13739,82 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_57get_mca(struct __pyx_o
}
}
if (!__pyx_t_7) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1260, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_6); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_6};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1260, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) {
- PyObject *__pyx_temp[2] = {__pyx_t_7, __pyx_t_6};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1260, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- } else
- #endif
- {
- __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1260, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_GIVEREF(__pyx_t_7); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __pyx_t_7 = NULL;
- __Pyx_GIVEREF(__pyx_t_6);
- PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_6);
- __pyx_t_6 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1260, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- }
+ __pyx_t_8 = PyTuple_New(1+1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
+ PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __Pyx_GIVEREF(__pyx_t_7); __pyx_t_7 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_8, 0+1, __pyx_t_6);
+ __Pyx_GIVEREF(__pyx_t_6);
+ __pyx_t_6 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_8, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1264; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
}
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "silx/io/specfile.pyx":1262
+ /* "silx/io/specfile.pyx":1266
* self._handle_error(error)
*
* cdef numpy.ndarray ret_array = numpy.empty((len_mca,), # <<<<<<<<<<<<<<
* dtype=numpy.double)
* for i in range(len_mca):
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1262, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_empty); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 1262, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_empty); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_len_mca); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1262, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v_len_mca); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_8 = PyTuple_New(1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1262, __pyx_L1_error)
+ __pyx_t_8 = PyTuple_New(1); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_8);
- __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_1);
+ __Pyx_GIVEREF(__pyx_t_1);
__pyx_t_1 = 0;
- __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1262, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_8);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_8);
+ __Pyx_GIVEREF(__pyx_t_8);
__pyx_t_8 = 0;
+ __pyx_t_8 = PyDict_New(); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_8);
- /* "silx/io/specfile.pyx":1263
+ /* "silx/io/specfile.pyx":1267
*
* cdef numpy.ndarray ret_array = numpy.empty((len_mca,),
* dtype=numpy.double) # <<<<<<<<<<<<<<
* for i in range(len_mca):
* ret_array[i] = mca_data[i]
*/
- __pyx_t_8 = PyDict_New(); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 1263, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 1263, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_numpy); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1267; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
- __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_double); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1263, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_double); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1267; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- if (PyDict_SetItem(__pyx_t_8, __pyx_n_s_dtype, __pyx_t_7) < 0) __PYX_ERR(0, 1263, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_8, __pyx_n_s_dtype, __pyx_t_7) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- /* "silx/io/specfile.pyx":1262
+ /* "silx/io/specfile.pyx":1266
* self._handle_error(error)
*
* cdef numpy.ndarray ret_array = numpy.empty((len_mca,), # <<<<<<<<<<<<<<
* dtype=numpy.double)
* for i in range(len_mca):
*/
- __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_1, __pyx_t_8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1262, __pyx_L1_error)
+ __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_1, __pyx_t_8); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- if (!(likely(((__pyx_t_7) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_7, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 1262, __pyx_L1_error)
+ if (!(likely(((__pyx_t_7) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_7, __pyx_ptype_5numpy_ndarray))))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_v_ret_array = ((PyArrayObject *)__pyx_t_7);
__pyx_t_7 = 0;
- /* "silx/io/specfile.pyx":1264
+ /* "silx/io/specfile.pyx":1268
* cdef numpy.ndarray ret_array = numpy.empty((len_mca,),
* dtype=numpy.double)
* for i in range(len_mca): # <<<<<<<<<<<<<<
@@ -15242,20 +13825,20 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_57get_mca(struct __pyx_o
for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_4; __pyx_t_3+=1) {
__pyx_v_i = __pyx_t_3;
- /* "silx/io/specfile.pyx":1265
+ /* "silx/io/specfile.pyx":1269
* dtype=numpy.double)
* for i in range(len_mca):
* ret_array[i] = mca_data[i] # <<<<<<<<<<<<<<
*
* free(mca_data)
*/
- __pyx_t_7 = PyFloat_FromDouble((__pyx_v_mca_data[__pyx_v_i])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1265, __pyx_L1_error)
+ __pyx_t_7 = PyFloat_FromDouble((__pyx_v_mca_data[__pyx_v_i])); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_7);
- if (unlikely(__Pyx_SetItemInt(((PyObject *)__pyx_v_ret_array), __pyx_v_i, __pyx_t_7, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) __PYX_ERR(0, 1265, __pyx_L1_error)
+ if (unlikely(__Pyx_SetItemInt(((PyObject *)__pyx_v_ret_array), __pyx_v_i, __pyx_t_7, long, 1, __Pyx_PyInt_From_long, 0, 1, 1) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1269; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
}
- /* "silx/io/specfile.pyx":1267
+ /* "silx/io/specfile.pyx":1271
* ret_array[i] = mca_data[i]
*
* free(mca_data) # <<<<<<<<<<<<<<
@@ -15263,7 +13846,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_57get_mca(struct __pyx_o
*/
free(__pyx_v_mca_data);
- /* "silx/io/specfile.pyx":1268
+ /* "silx/io/specfile.pyx":1272
*
* free(mca_data)
* return ret_array # <<<<<<<<<<<<<<
@@ -15273,7 +13856,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_57get_mca(struct __pyx_o
__pyx_r = ((PyObject *)__pyx_v_ret_array);
goto __pyx_L0;
- /* "silx/io/specfile.pyx":1239
+ /* "silx/io/specfile.pyx":1243
* return mca_calib_list
*
* def get_mca(self, scan_index, mca_index): # <<<<<<<<<<<<<<
@@ -15297,7 +13880,7 @@ static PyObject *__pyx_pf_4silx_2io_8specfile_8SpecFile_57get_mca(struct __pyx_o
return __pyx_r;
}
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":197
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":194
* # experimental exception made for __getbuffer__ and __releasebuffer__
* # -- the details of this may change.
* def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<<
@@ -15338,13 +13921,16 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
int __pyx_t_5;
PyObject *__pyx_t_6 = NULL;
char *__pyx_t_7;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("__getbuffer__", 0);
if (__pyx_v_info != NULL) {
__pyx_v_info->obj = Py_None; __Pyx_INCREF(Py_None);
__Pyx_GIVEREF(__pyx_v_info->obj);
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":203
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":200
* # of flags
*
* if info == NULL: return # <<<<<<<<<<<<<<
@@ -15357,7 +13943,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
goto __pyx_L0;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":206
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":203
*
* cdef int copy_shape, i, ndim
* cdef int endian_detector = 1 # <<<<<<<<<<<<<<
@@ -15366,7 +13952,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_endian_detector = 1;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":207
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":204
* cdef int copy_shape, i, ndim
* cdef int endian_detector = 1
* cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<<
@@ -15375,7 +13961,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":209
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":206
* cdef bint little_endian = ((<char*>&endian_detector)[0] != 0)
*
* ndim = PyArray_NDIM(self) # <<<<<<<<<<<<<<
@@ -15384,7 +13970,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_ndim = PyArray_NDIM(__pyx_v_self);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":211
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":208
* ndim = PyArray_NDIM(self)
*
* if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<<
@@ -15394,7 +13980,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
__pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0);
if (__pyx_t_1) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":212
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":209
*
* if sizeof(npy_intp) != sizeof(Py_ssize_t):
* copy_shape = 1 # <<<<<<<<<<<<<<
@@ -15402,30 +13988,22 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* copy_shape = 0
*/
__pyx_v_copy_shape = 1;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":211
- * ndim = PyArray_NDIM(self)
- *
- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<<
- * copy_shape = 1
- * else:
- */
goto __pyx_L4;
}
+ /*else*/ {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":214
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":211
* copy_shape = 1
* else:
* copy_shape = 0 # <<<<<<<<<<<<<<
*
* if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS)
*/
- /*else*/ {
__pyx_v_copy_shape = 0;
}
__pyx_L4:;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":216
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":213
* copy_shape = 0
*
* if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<<
@@ -15439,7 +14017,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
goto __pyx_L6_bool_binop_done;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":217
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":214
*
* if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS)
* and not PyArray_CHKFLAGS(self, NPY_C_CONTIGUOUS)): # <<<<<<<<<<<<<<
@@ -15449,39 +14027,23 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
__pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_C_CONTIGUOUS) != 0)) != 0);
__pyx_t_1 = __pyx_t_2;
__pyx_L6_bool_binop_done:;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":216
- * copy_shape = 0
- *
- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<<
- * and not PyArray_CHKFLAGS(self, NPY_C_CONTIGUOUS)):
- * raise ValueError(u"ndarray is not C contiguous")
- */
if (__pyx_t_1) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":218
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":215
* if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS)
* and not PyArray_CHKFLAGS(self, NPY_C_CONTIGUOUS)):
* raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<<
*
* if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS)
*/
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__30, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 218, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__34, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 215; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_Raise(__pyx_t_3, 0, 0, 0);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __PYX_ERR(1, 218, __pyx_L1_error)
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":216
- * copy_shape = 0
- *
- * if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS) # <<<<<<<<<<<<<<
- * and not PyArray_CHKFLAGS(self, NPY_C_CONTIGUOUS)):
- * raise ValueError(u"ndarray is not C contiguous")
- */
+ {__pyx_filename = __pyx_f[1]; __pyx_lineno = 215; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":220
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":217
* raise ValueError(u"ndarray is not C contiguous")
*
* if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<<
@@ -15495,7 +14057,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
goto __pyx_L9_bool_binop_done;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":221
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":218
*
* if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS)
* and not PyArray_CHKFLAGS(self, NPY_F_CONTIGUOUS)): # <<<<<<<<<<<<<<
@@ -15505,39 +14067,23 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
__pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_F_CONTIGUOUS) != 0)) != 0);
__pyx_t_1 = __pyx_t_2;
__pyx_L9_bool_binop_done:;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":220
- * raise ValueError(u"ndarray is not C contiguous")
- *
- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<<
- * and not PyArray_CHKFLAGS(self, NPY_F_CONTIGUOUS)):
- * raise ValueError(u"ndarray is not Fortran contiguous")
- */
if (__pyx_t_1) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":222
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":219
* if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS)
* and not PyArray_CHKFLAGS(self, NPY_F_CONTIGUOUS)):
* raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<<
*
* info.buf = PyArray_DATA(self)
*/
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__31, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 222, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__35, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_Raise(__pyx_t_3, 0, 0, 0);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __PYX_ERR(1, 222, __pyx_L1_error)
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":220
- * raise ValueError(u"ndarray is not C contiguous")
- *
- * if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS) # <<<<<<<<<<<<<<
- * and not PyArray_CHKFLAGS(self, NPY_F_CONTIGUOUS)):
- * raise ValueError(u"ndarray is not Fortran contiguous")
- */
+ {__pyx_filename = __pyx_f[1]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":224
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":221
* raise ValueError(u"ndarray is not Fortran contiguous")
*
* info.buf = PyArray_DATA(self) # <<<<<<<<<<<<<<
@@ -15546,7 +14092,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_info->buf = PyArray_DATA(__pyx_v_self);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":225
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":222
*
* info.buf = PyArray_DATA(self)
* info.ndim = ndim # <<<<<<<<<<<<<<
@@ -15555,7 +14101,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_info->ndim = __pyx_v_ndim;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":226
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":223
* info.buf = PyArray_DATA(self)
* info.ndim = ndim
* if copy_shape: # <<<<<<<<<<<<<<
@@ -15565,7 +14111,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
__pyx_t_1 = (__pyx_v_copy_shape != 0);
if (__pyx_t_1) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":229
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":226
* # Allocate new buffer for strides and shape info.
* # This is allocated as one block, strides first.
* info.strides = <Py_ssize_t*>stdlib.malloc(sizeof(Py_ssize_t) * <size_t>ndim * 2) # <<<<<<<<<<<<<<
@@ -15574,7 +14120,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_info->strides = ((Py_ssize_t *)malloc((((sizeof(Py_ssize_t)) * ((size_t)__pyx_v_ndim)) * 2)));
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":230
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":227
* # This is allocated as one block, strides first.
* info.strides = <Py_ssize_t*>stdlib.malloc(sizeof(Py_ssize_t) * <size_t>ndim * 2)
* info.shape = info.strides + ndim # <<<<<<<<<<<<<<
@@ -15583,7 +14129,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_info->shape = (__pyx_v_info->strides + __pyx_v_ndim);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":231
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":228
* info.strides = <Py_ssize_t*>stdlib.malloc(sizeof(Py_ssize_t) * <size_t>ndim * 2)
* info.shape = info.strides + ndim
* for i in range(ndim): # <<<<<<<<<<<<<<
@@ -15594,7 +14140,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_4; __pyx_t_5+=1) {
__pyx_v_i = __pyx_t_5;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":232
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":229
* info.shape = info.strides + ndim
* for i in range(ndim):
* info.strides[i] = PyArray_STRIDES(self)[i] # <<<<<<<<<<<<<<
@@ -15603,7 +14149,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
(__pyx_v_info->strides[__pyx_v_i]) = (PyArray_STRIDES(__pyx_v_self)[__pyx_v_i]);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":233
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":230
* for i in range(ndim):
* info.strides[i] = PyArray_STRIDES(self)[i]
* info.shape[i] = PyArray_DIMS(self)[i] # <<<<<<<<<<<<<<
@@ -15612,28 +14158,20 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
(__pyx_v_info->shape[__pyx_v_i]) = (PyArray_DIMS(__pyx_v_self)[__pyx_v_i]);
}
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":226
- * info.buf = PyArray_DATA(self)
- * info.ndim = ndim
- * if copy_shape: # <<<<<<<<<<<<<<
- * # Allocate new buffer for strides and shape info.
- * # This is allocated as one block, strides first.
- */
goto __pyx_L11;
}
+ /*else*/ {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":235
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":232
* info.shape[i] = PyArray_DIMS(self)[i]
* else:
* info.strides = <Py_ssize_t*>PyArray_STRIDES(self) # <<<<<<<<<<<<<<
* info.shape = <Py_ssize_t*>PyArray_DIMS(self)
* info.suboffsets = NULL
*/
- /*else*/ {
__pyx_v_info->strides = ((Py_ssize_t *)PyArray_STRIDES(__pyx_v_self));
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":236
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":233
* else:
* info.strides = <Py_ssize_t*>PyArray_STRIDES(self)
* info.shape = <Py_ssize_t*>PyArray_DIMS(self) # <<<<<<<<<<<<<<
@@ -15644,7 +14182,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
}
__pyx_L11:;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":237
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":234
* info.strides = <Py_ssize_t*>PyArray_STRIDES(self)
* info.shape = <Py_ssize_t*>PyArray_DIMS(self)
* info.suboffsets = NULL # <<<<<<<<<<<<<<
@@ -15653,7 +14191,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_info->suboffsets = NULL;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":238
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":235
* info.shape = <Py_ssize_t*>PyArray_DIMS(self)
* info.suboffsets = NULL
* info.itemsize = PyArray_ITEMSIZE(self) # <<<<<<<<<<<<<<
@@ -15662,7 +14200,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_info->itemsize = PyArray_ITEMSIZE(__pyx_v_self);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":239
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":236
* info.suboffsets = NULL
* info.itemsize = PyArray_ITEMSIZE(self)
* info.readonly = not PyArray_ISWRITEABLE(self) # <<<<<<<<<<<<<<
@@ -15671,28 +14209,28 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_info->readonly = (!(PyArray_ISWRITEABLE(__pyx_v_self) != 0));
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":242
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":239
*
* cdef int t
* cdef char* f = NULL # <<<<<<<<<<<<<<
* cdef dtype descr = self.descr
- * cdef int offset
+ * cdef list stack
*/
__pyx_v_f = NULL;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":243
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":240
* cdef int t
* cdef char* f = NULL
* cdef dtype descr = self.descr # <<<<<<<<<<<<<<
+ * cdef list stack
* cdef int offset
- *
*/
__pyx_t_3 = ((PyObject *)__pyx_v_self->descr);
__Pyx_INCREF(__pyx_t_3);
__pyx_v_descr = ((PyArray_Descr *)__pyx_t_3);
__pyx_t_3 = 0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":246
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":244
* cdef int offset
*
* cdef bint hasfields = PyDataType_HASFIELDS(descr) # <<<<<<<<<<<<<<
@@ -15701,7 +14239,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_hasfields = PyDataType_HASFIELDS(__pyx_v_descr);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":248
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":246
* cdef bint hasfields = PyDataType_HASFIELDS(descr)
*
* if not hasfields and not copy_shape: # <<<<<<<<<<<<<<
@@ -15719,7 +14257,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
__pyx_L15_bool_binop_done:;
if (__pyx_t_1) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":250
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":248
* if not hasfields and not copy_shape:
* # do not call releasebuffer
* info.obj = None # <<<<<<<<<<<<<<
@@ -15731,25 +14269,17 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
__Pyx_GOTREF(__pyx_v_info->obj);
__Pyx_DECREF(__pyx_v_info->obj);
__pyx_v_info->obj = Py_None;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":248
- * cdef bint hasfields = PyDataType_HASFIELDS(descr)
- *
- * if not hasfields and not copy_shape: # <<<<<<<<<<<<<<
- * # do not call releasebuffer
- * info.obj = None
- */
goto __pyx_L14;
}
+ /*else*/ {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":253
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":251
* else:
* # need to call releasebuffer
* info.obj = self # <<<<<<<<<<<<<<
*
* if not hasfields:
*/
- /*else*/ {
__Pyx_INCREF(((PyObject *)__pyx_v_self));
__Pyx_GIVEREF(((PyObject *)__pyx_v_self));
__Pyx_GOTREF(__pyx_v_info->obj);
@@ -15758,7 +14288,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
}
__pyx_L14:;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":255
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":253
* info.obj = self
*
* if not hasfields: # <<<<<<<<<<<<<<
@@ -15768,7 +14298,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
__pyx_t_1 = ((!(__pyx_v_hasfields != 0)) != 0);
if (__pyx_t_1) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":256
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":254
*
* if not hasfields:
* t = descr.type_num # <<<<<<<<<<<<<<
@@ -15778,7 +14308,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
__pyx_t_4 = __pyx_v_descr->type_num;
__pyx_v_t = __pyx_t_4;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":257
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":255
* if not hasfields:
* t = descr.type_num
* if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<<
@@ -15798,7 +14328,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
}
__pyx_L20_next_or:;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":258
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":256
* t = descr.type_num
* if ((descr.byteorder == c'>' and little_endian) or
* (descr.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<<
@@ -15814,51 +14344,43 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
__pyx_t_2 = ((!(__pyx_v_little_endian != 0)) != 0);
__pyx_t_1 = __pyx_t_2;
__pyx_L19_bool_binop_done:;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":257
- * if not hasfields:
- * t = descr.type_num
- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<<
- * (descr.byteorder == c'<' and not little_endian)):
- * raise ValueError(u"Non-native byte order not supported")
- */
if (__pyx_t_1) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":259
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":257
* if ((descr.byteorder == c'>' and little_endian) or
* (descr.byteorder == c'<' and not little_endian)):
* raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<<
* if t == NPY_BYTE: f = "b"
* elif t == NPY_UBYTE: f = "B"
*/
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__32, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 259, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__36, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 257; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_Raise(__pyx_t_3, 0, 0, 0);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __PYX_ERR(1, 259, __pyx_L1_error)
+ {__pyx_filename = __pyx_f[1]; __pyx_lineno = 257; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ }
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":257
- * if not hasfields:
- * t = descr.type_num
- * if ((descr.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<<
- * (descr.byteorder == c'<' and not little_endian)):
- * raise ValueError(u"Non-native byte order not supported")
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":274
+ * elif t == NPY_CDOUBLE: f = "Zd"
+ * elif t == NPY_CLONGDOUBLE: f = "Zg"
+ * elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<<
+ * else:
+ * raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t)
*/
- }
+ switch (__pyx_v_t) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":260
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":258
* (descr.byteorder == c'<' and not little_endian)):
* raise ValueError(u"Non-native byte order not supported")
* if t == NPY_BYTE: f = "b" # <<<<<<<<<<<<<<
* elif t == NPY_UBYTE: f = "B"
* elif t == NPY_SHORT: f = "h"
*/
- switch (__pyx_v_t) {
case NPY_BYTE:
- __pyx_v_f = ((char *)"b");
+ __pyx_v_f = __pyx_k_b;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":261
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":259
* raise ValueError(u"Non-native byte order not supported")
* if t == NPY_BYTE: f = "b"
* elif t == NPY_UBYTE: f = "B" # <<<<<<<<<<<<<<
@@ -15866,10 +14388,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_USHORT: f = "H"
*/
case NPY_UBYTE:
- __pyx_v_f = ((char *)"B");
+ __pyx_v_f = __pyx_k_B;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":262
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":260
* if t == NPY_BYTE: f = "b"
* elif t == NPY_UBYTE: f = "B"
* elif t == NPY_SHORT: f = "h" # <<<<<<<<<<<<<<
@@ -15877,10 +14399,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_INT: f = "i"
*/
case NPY_SHORT:
- __pyx_v_f = ((char *)"h");
+ __pyx_v_f = __pyx_k_h;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":263
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":261
* elif t == NPY_UBYTE: f = "B"
* elif t == NPY_SHORT: f = "h"
* elif t == NPY_USHORT: f = "H" # <<<<<<<<<<<<<<
@@ -15888,10 +14410,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_UINT: f = "I"
*/
case NPY_USHORT:
- __pyx_v_f = ((char *)"H");
+ __pyx_v_f = __pyx_k_H;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":264
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":262
* elif t == NPY_SHORT: f = "h"
* elif t == NPY_USHORT: f = "H"
* elif t == NPY_INT: f = "i" # <<<<<<<<<<<<<<
@@ -15899,10 +14421,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_LONG: f = "l"
*/
case NPY_INT:
- __pyx_v_f = ((char *)"i");
+ __pyx_v_f = __pyx_k_i;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":265
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":263
* elif t == NPY_USHORT: f = "H"
* elif t == NPY_INT: f = "i"
* elif t == NPY_UINT: f = "I" # <<<<<<<<<<<<<<
@@ -15910,10 +14432,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_ULONG: f = "L"
*/
case NPY_UINT:
- __pyx_v_f = ((char *)"I");
+ __pyx_v_f = __pyx_k_I;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":266
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":264
* elif t == NPY_INT: f = "i"
* elif t == NPY_UINT: f = "I"
* elif t == NPY_LONG: f = "l" # <<<<<<<<<<<<<<
@@ -15921,10 +14443,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_LONGLONG: f = "q"
*/
case NPY_LONG:
- __pyx_v_f = ((char *)"l");
+ __pyx_v_f = __pyx_k_l;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":267
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":265
* elif t == NPY_UINT: f = "I"
* elif t == NPY_LONG: f = "l"
* elif t == NPY_ULONG: f = "L" # <<<<<<<<<<<<<<
@@ -15932,10 +14454,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_ULONGLONG: f = "Q"
*/
case NPY_ULONG:
- __pyx_v_f = ((char *)"L");
+ __pyx_v_f = __pyx_k_L;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":268
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":266
* elif t == NPY_LONG: f = "l"
* elif t == NPY_ULONG: f = "L"
* elif t == NPY_LONGLONG: f = "q" # <<<<<<<<<<<<<<
@@ -15943,10 +14465,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_FLOAT: f = "f"
*/
case NPY_LONGLONG:
- __pyx_v_f = ((char *)"q");
+ __pyx_v_f = __pyx_k_q;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":269
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":267
* elif t == NPY_ULONG: f = "L"
* elif t == NPY_LONGLONG: f = "q"
* elif t == NPY_ULONGLONG: f = "Q" # <<<<<<<<<<<<<<
@@ -15954,10 +14476,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_DOUBLE: f = "d"
*/
case NPY_ULONGLONG:
- __pyx_v_f = ((char *)"Q");
+ __pyx_v_f = __pyx_k_Q;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":270
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":268
* elif t == NPY_LONGLONG: f = "q"
* elif t == NPY_ULONGLONG: f = "Q"
* elif t == NPY_FLOAT: f = "f" # <<<<<<<<<<<<<<
@@ -15965,10 +14487,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_LONGDOUBLE: f = "g"
*/
case NPY_FLOAT:
- __pyx_v_f = ((char *)"f");
+ __pyx_v_f = __pyx_k_f;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":271
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":269
* elif t == NPY_ULONGLONG: f = "Q"
* elif t == NPY_FLOAT: f = "f"
* elif t == NPY_DOUBLE: f = "d" # <<<<<<<<<<<<<<
@@ -15976,10 +14498,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_CFLOAT: f = "Zf"
*/
case NPY_DOUBLE:
- __pyx_v_f = ((char *)"d");
+ __pyx_v_f = __pyx_k_d;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":272
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":270
* elif t == NPY_FLOAT: f = "f"
* elif t == NPY_DOUBLE: f = "d"
* elif t == NPY_LONGDOUBLE: f = "g" # <<<<<<<<<<<<<<
@@ -15987,10 +14509,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_CDOUBLE: f = "Zd"
*/
case NPY_LONGDOUBLE:
- __pyx_v_f = ((char *)"g");
+ __pyx_v_f = __pyx_k_g;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":273
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":271
* elif t == NPY_DOUBLE: f = "d"
* elif t == NPY_LONGDOUBLE: f = "g"
* elif t == NPY_CFLOAT: f = "Zf" # <<<<<<<<<<<<<<
@@ -15998,10 +14520,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_CLONGDOUBLE: f = "Zg"
*/
case NPY_CFLOAT:
- __pyx_v_f = ((char *)"Zf");
+ __pyx_v_f = __pyx_k_Zf;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":274
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":272
* elif t == NPY_LONGDOUBLE: f = "g"
* elif t == NPY_CFLOAT: f = "Zf"
* elif t == NPY_CDOUBLE: f = "Zd" # <<<<<<<<<<<<<<
@@ -16009,10 +14531,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* elif t == NPY_OBJECT: f = "O"
*/
case NPY_CDOUBLE:
- __pyx_v_f = ((char *)"Zd");
+ __pyx_v_f = __pyx_k_Zd;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":275
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":273
* elif t == NPY_CFLOAT: f = "Zf"
* elif t == NPY_CDOUBLE: f = "Zd"
* elif t == NPY_CLONGDOUBLE: f = "Zg" # <<<<<<<<<<<<<<
@@ -16020,10 +14542,10 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* else:
*/
case NPY_CLONGDOUBLE:
- __pyx_v_f = ((char *)"Zg");
+ __pyx_v_f = __pyx_k_Zg;
break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":276
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":274
* elif t == NPY_CDOUBLE: f = "Zd"
* elif t == NPY_CLONGDOUBLE: f = "Zg"
* elif t == NPY_OBJECT: f = "O" # <<<<<<<<<<<<<<
@@ -16031,37 +14553,37 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
* raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t)
*/
case NPY_OBJECT:
- __pyx_v_f = ((char *)"O");
+ __pyx_v_f = __pyx_k_O;
break;
default:
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":278
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":276
* elif t == NPY_OBJECT: f = "O"
* else:
* raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<<
* info.format = f
* return
*/
- __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 278, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_t); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_6 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 278, __pyx_L1_error)
+ __pyx_t_6 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_t_3); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 278, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_6);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_6);
+ __Pyx_GIVEREF(__pyx_t_6);
__pyx_t_6 = 0;
- __pyx_t_6 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_t_3, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 278, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_t_3, NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_6);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_Raise(__pyx_t_6, 0, 0, 0);
__Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __PYX_ERR(1, 278, __pyx_L1_error)
+ {__pyx_filename = __pyx_f[1]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
break;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":279
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":277
* else:
* raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t)
* info.format = f # <<<<<<<<<<<<<<
@@ -16070,7 +14592,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_info->format = __pyx_v_f;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":280
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":278
* raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t)
* info.format = f
* return # <<<<<<<<<<<<<<
@@ -16079,27 +14601,19 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_r = 0;
goto __pyx_L0;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":255
- * info.obj = self
- *
- * if not hasfields: # <<<<<<<<<<<<<<
- * t = descr.type_num
- * if ((descr.byteorder == c'>' and little_endian) or
- */
}
+ /*else*/ {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":282
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":280
* return
* else:
* info.format = <char*>stdlib.malloc(_buffer_format_string_len) # <<<<<<<<<<<<<<
* info.format[0] = c'^' # Native data types, manual alignment
* offset = 0
*/
- /*else*/ {
- __pyx_v_info->format = ((char *)malloc(0xFF));
+ __pyx_v_info->format = ((char *)malloc(255));
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":283
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":281
* else:
* info.format = <char*>stdlib.malloc(_buffer_format_string_len)
* info.format[0] = c'^' # Native data types, manual alignment # <<<<<<<<<<<<<<
@@ -16108,7 +14622,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
(__pyx_v_info->format[0]) = '^';
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":284
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":282
* info.format = <char*>stdlib.malloc(_buffer_format_string_len)
* info.format[0] = c'^' # Native data types, manual alignment
* offset = 0 # <<<<<<<<<<<<<<
@@ -16117,17 +14631,17 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
*/
__pyx_v_offset = 0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":285
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":283
* info.format[0] = c'^' # Native data types, manual alignment
* offset = 0
* f = _util_dtypestring(descr, info.format + 1, # <<<<<<<<<<<<<<
* info.format + _buffer_format_string_len,
* &offset)
*/
- __pyx_t_7 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 0xFF), (&__pyx_v_offset)); if (unlikely(__pyx_t_7 == NULL)) __PYX_ERR(1, 285, __pyx_L1_error)
+ __pyx_t_7 = __pyx_f_5numpy__util_dtypestring(__pyx_v_descr, (__pyx_v_info->format + 1), (__pyx_v_info->format + 255), (&__pyx_v_offset)); if (unlikely(__pyx_t_7 == NULL)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 283; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_v_f = __pyx_t_7;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":288
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":286
* info.format + _buffer_format_string_len,
* &offset)
* f[0] = c'\0' # Terminate format string # <<<<<<<<<<<<<<
@@ -16137,7 +14651,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
(__pyx_v_f[0]) = '\x00';
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":197
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":194
* # experimental exception made for __getbuffer__ and __releasebuffer__
* # -- the details of this may change.
* def __getbuffer__(ndarray self, Py_buffer* info, int flags): # <<<<<<<<<<<<<<
@@ -16169,7 +14683,7 @@ static int __pyx_pf_5numpy_7ndarray___getbuffer__(PyArrayObject *__pyx_v_self, P
return __pyx_r;
}
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":290
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":288
* f[0] = c'\0' # Terminate format string
*
* def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<<
@@ -16193,7 +14707,7 @@ static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_s
int __pyx_t_1;
__Pyx_RefNannySetupContext("__releasebuffer__", 0);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":291
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":289
*
* def __releasebuffer__(ndarray self, Py_buffer* info):
* if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<<
@@ -16203,7 +14717,7 @@ static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_s
__pyx_t_1 = (PyArray_HASFIELDS(__pyx_v_self) != 0);
if (__pyx_t_1) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":292
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":290
* def __releasebuffer__(ndarray self, Py_buffer* info):
* if PyArray_HASFIELDS(self):
* stdlib.free(info.format) # <<<<<<<<<<<<<<
@@ -16211,17 +14725,11 @@ static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_s
* stdlib.free(info.strides)
*/
free(__pyx_v_info->format);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":291
- *
- * def __releasebuffer__(ndarray self, Py_buffer* info):
- * if PyArray_HASFIELDS(self): # <<<<<<<<<<<<<<
- * stdlib.free(info.format)
- * if sizeof(npy_intp) != sizeof(Py_ssize_t):
- */
+ goto __pyx_L3;
}
+ __pyx_L3:;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":293
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":291
* if PyArray_HASFIELDS(self):
* stdlib.free(info.format)
* if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<<
@@ -16231,7 +14739,7 @@ static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_s
__pyx_t_1 = (((sizeof(npy_intp)) != (sizeof(Py_ssize_t))) != 0);
if (__pyx_t_1) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":294
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":292
* stdlib.free(info.format)
* if sizeof(npy_intp) != sizeof(Py_ssize_t):
* stdlib.free(info.strides) # <<<<<<<<<<<<<<
@@ -16239,17 +14747,11 @@ static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_s
*
*/
free(__pyx_v_info->strides);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":293
- * if PyArray_HASFIELDS(self):
- * stdlib.free(info.format)
- * if sizeof(npy_intp) != sizeof(Py_ssize_t): # <<<<<<<<<<<<<<
- * stdlib.free(info.strides)
- * # info.shape was stored after info.strides in the same block
- */
+ goto __pyx_L4;
}
+ __pyx_L4:;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":290
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":288
* f[0] = c'\0' # Terminate format string
*
* def __releasebuffer__(ndarray self, Py_buffer* info): # <<<<<<<<<<<<<<
@@ -16261,7 +14763,7 @@ static void __pyx_pf_5numpy_7ndarray_2__releasebuffer__(PyArrayObject *__pyx_v_s
__Pyx_RefNannyFinishContext();
}
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":770
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":768
* ctypedef npy_cdouble complex_t
*
* cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<<
@@ -16273,9 +14775,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("PyArray_MultiIterNew1", 0);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":771
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":769
*
* cdef inline object PyArray_MultiIterNew1(a):
* return PyArray_MultiIterNew(1, <void*>a) # <<<<<<<<<<<<<<
@@ -16283,13 +14788,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__
* cdef inline object PyArray_MultiIterNew2(a, b):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 771, __pyx_L1_error)
+ __pyx_t_1 = PyArray_MultiIterNew(1, ((void *)__pyx_v_a)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 769; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":770
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":768
* ctypedef npy_cdouble complex_t
*
* cdef inline object PyArray_MultiIterNew1(a): # <<<<<<<<<<<<<<
@@ -16308,7 +14813,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew1(PyObject *__
return __pyx_r;
}
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":773
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":771
* return PyArray_MultiIterNew(1, <void*>a)
*
* cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<<
@@ -16320,9 +14825,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("PyArray_MultiIterNew2", 0);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":774
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":772
*
* cdef inline object PyArray_MultiIterNew2(a, b):
* return PyArray_MultiIterNew(2, <void*>a, <void*>b) # <<<<<<<<<<<<<<
@@ -16330,13 +14838,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__
* cdef inline object PyArray_MultiIterNew3(a, b, c):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 774, __pyx_L1_error)
+ __pyx_t_1 = PyArray_MultiIterNew(2, ((void *)__pyx_v_a), ((void *)__pyx_v_b)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 772; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":773
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":771
* return PyArray_MultiIterNew(1, <void*>a)
*
* cdef inline object PyArray_MultiIterNew2(a, b): # <<<<<<<<<<<<<<
@@ -16355,7 +14863,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew2(PyObject *__
return __pyx_r;
}
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":776
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":774
* return PyArray_MultiIterNew(2, <void*>a, <void*>b)
*
* cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<<
@@ -16367,9 +14875,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("PyArray_MultiIterNew3", 0);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":777
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":775
*
* cdef inline object PyArray_MultiIterNew3(a, b, c):
* return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c) # <<<<<<<<<<<<<<
@@ -16377,13 +14888,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__
* cdef inline object PyArray_MultiIterNew4(a, b, c, d):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 777, __pyx_L1_error)
+ __pyx_t_1 = PyArray_MultiIterNew(3, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 775; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":776
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":774
* return PyArray_MultiIterNew(2, <void*>a, <void*>b)
*
* cdef inline object PyArray_MultiIterNew3(a, b, c): # <<<<<<<<<<<<<<
@@ -16402,7 +14913,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew3(PyObject *__
return __pyx_r;
}
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":779
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":777
* return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c)
*
* cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<<
@@ -16414,9 +14925,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("PyArray_MultiIterNew4", 0);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":780
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":778
*
* cdef inline object PyArray_MultiIterNew4(a, b, c, d):
* return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d) # <<<<<<<<<<<<<<
@@ -16424,13 +14938,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__
* cdef inline object PyArray_MultiIterNew5(a, b, c, d, e):
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 780, __pyx_L1_error)
+ __pyx_t_1 = PyArray_MultiIterNew(4, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 778; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":779
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":777
* return PyArray_MultiIterNew(3, <void*>a, <void*>b, <void*> c)
*
* cdef inline object PyArray_MultiIterNew4(a, b, c, d): # <<<<<<<<<<<<<<
@@ -16449,7 +14963,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew4(PyObject *__
return __pyx_r;
}
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":782
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":780
* return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d)
*
* cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<<
@@ -16461,9 +14975,12 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__
PyObject *__pyx_r = NULL;
__Pyx_RefNannyDeclarations
PyObject *__pyx_t_1 = NULL;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("PyArray_MultiIterNew5", 0);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":783
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":781
*
* cdef inline object PyArray_MultiIterNew5(a, b, c, d, e):
* return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e) # <<<<<<<<<<<<<<
@@ -16471,13 +14988,13 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__
* cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL:
*/
__Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 783, __pyx_L1_error)
+ __pyx_t_1 = PyArray_MultiIterNew(5, ((void *)__pyx_v_a), ((void *)__pyx_v_b), ((void *)__pyx_v_c), ((void *)__pyx_v_d), ((void *)__pyx_v_e)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 781; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_r = __pyx_t_1;
__pyx_t_1 = 0;
goto __pyx_L0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":782
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":780
* return PyArray_MultiIterNew(4, <void*>a, <void*>b, <void*>c, <void*> d)
*
* cdef inline object PyArray_MultiIterNew5(a, b, c, d, e): # <<<<<<<<<<<<<<
@@ -16496,7 +15013,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_PyArray_MultiIterNew5(PyObject *__
return __pyx_r;
}
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":785
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":783
* return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e)
*
* cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<<
@@ -16523,19 +15040,22 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
int __pyx_t_7;
long __pyx_t_8;
char *__pyx_t_9;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannySetupContext("_util_dtypestring", 0);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":790
- *
- * cdef dtype child
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":790
+ * cdef int delta_offset
+ * cdef tuple i
* cdef int endian_detector = 1 # <<<<<<<<<<<<<<
* cdef bint little_endian = ((<char*>&endian_detector)[0] != 0)
* cdef tuple fields
*/
__pyx_v_endian_detector = 1;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":791
- * cdef dtype child
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":791
+ * cdef tuple i
* cdef int endian_detector = 1
* cdef bint little_endian = ((<char*>&endian_detector)[0] != 0) # <<<<<<<<<<<<<<
* cdef tuple fields
@@ -16543,7 +15063,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
*/
__pyx_v_little_endian = ((((char *)(&__pyx_v_endian_detector))[0]) != 0);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":794
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":794
* cdef tuple fields
*
* for childname in descr.names: # <<<<<<<<<<<<<<
@@ -16552,38 +15072,33 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
*/
if (unlikely(__pyx_v_descr->names == Py_None)) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
- __PYX_ERR(1, 794, __pyx_L1_error)
+ {__pyx_filename = __pyx_f[1]; __pyx_lineno = 794; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__pyx_t_1 = __pyx_v_descr->names; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0;
for (;;) {
if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) __PYX_ERR(1, 794, __pyx_L1_error)
+ #if CYTHON_COMPILING_IN_CPYTHON
+ __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_3); __pyx_t_2++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 794; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#else
- __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 794, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
+ __pyx_t_3 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 794; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
__Pyx_XDECREF_SET(__pyx_v_childname, __pyx_t_3);
__pyx_t_3 = 0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":795
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":795
*
* for childname in descr.names:
* fields = descr.fields[childname] # <<<<<<<<<<<<<<
* child, new_offset = fields
*
*/
- if (unlikely(__pyx_v_descr->fields == Py_None)) {
- PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
- __PYX_ERR(1, 795, __pyx_L1_error)
- }
- __pyx_t_3 = __Pyx_PyDict_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 795, __pyx_L1_error)
+ __pyx_t_3 = PyObject_GetItem(__pyx_v_descr->fields, __pyx_v_childname); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 795; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
__Pyx_GOTREF(__pyx_t_3);
- if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) __PYX_ERR(1, 795, __pyx_L1_error)
+ if (!(likely(PyTuple_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_t_3)->tp_name), 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 795; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_XDECREF_SET(__pyx_v_fields, ((PyObject*)__pyx_t_3));
__pyx_t_3 = 0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":796
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":796
* for childname in descr.names:
* fields = descr.fields[childname]
* child, new_offset = fields # <<<<<<<<<<<<<<
@@ -16592,7 +15107,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
*/
if (likely(__pyx_v_fields != Py_None)) {
PyObject* sequence = __pyx_v_fields;
- #if !CYTHON_COMPILING_IN_PYPY
+ #if CYTHON_COMPILING_IN_CPYTHON
Py_ssize_t size = Py_SIZE(sequence);
#else
Py_ssize_t size = PySequence_Size(sequence);
@@ -16600,68 +15115,60 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
if (unlikely(size != 2)) {
if (size > 2) __Pyx_RaiseTooManyValuesError(2);
else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
- __PYX_ERR(1, 796, __pyx_L1_error)
+ {__pyx_filename = __pyx_f[1]; __pyx_lineno = 796; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+ #if CYTHON_COMPILING_IN_CPYTHON
__pyx_t_3 = PyTuple_GET_ITEM(sequence, 0);
__pyx_t_4 = PyTuple_GET_ITEM(sequence, 1);
__Pyx_INCREF(__pyx_t_3);
__Pyx_INCREF(__pyx_t_4);
#else
- __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 796, __pyx_L1_error)
+ __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 796; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 796, __pyx_L1_error)
+ __pyx_t_4 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 796; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
#endif
} else {
- __Pyx_RaiseNoneNotIterableError(); __PYX_ERR(1, 796, __pyx_L1_error)
+ __Pyx_RaiseNoneNotIterableError(); {__pyx_filename = __pyx_f[1]; __pyx_lineno = 796; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) __PYX_ERR(1, 796, __pyx_L1_error)
+ if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_dtype))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 796; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_XDECREF_SET(__pyx_v_child, ((PyArray_Descr *)__pyx_t_3));
__pyx_t_3 = 0;
__Pyx_XDECREF_SET(__pyx_v_new_offset, __pyx_t_4);
__pyx_t_4 = 0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":798
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":798
* child, new_offset = fields
*
* if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<<
* raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd")
*
*/
- __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 798, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 798; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 798, __pyx_L1_error)
+ __pyx_t_3 = PyNumber_Subtract(__pyx_v_new_offset, __pyx_t_4); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 798; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 798, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_PyInt_As_int(__pyx_t_3); if (unlikely((__pyx_t_5 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 798; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_6 = ((((__pyx_v_end - __pyx_v_f) - ((int)__pyx_t_5)) < 15) != 0);
if (__pyx_t_6) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":799
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":799
*
* if (end - f) - <int>(new_offset - offset[0]) < 15:
* raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<<
*
* if ((child.byteorder == c'>' and little_endian) or
*/
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__33, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 799, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__37, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 799; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_Raise(__pyx_t_3, 0, 0, 0);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __PYX_ERR(1, 799, __pyx_L1_error)
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":798
- * child, new_offset = fields
- *
- * if (end - f) - <int>(new_offset - offset[0]) < 15: # <<<<<<<<<<<<<<
- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd")
- *
- */
+ {__pyx_filename = __pyx_f[1]; __pyx_lineno = 799; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":801
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":801
* raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd")
*
* if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<<
@@ -16681,7 +15188,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
}
__pyx_L8_next_or:;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":802
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":802
*
* if ((child.byteorder == c'>' and little_endian) or
* (child.byteorder == c'<' and not little_endian)): # <<<<<<<<<<<<<<
@@ -16697,39 +15204,23 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
__pyx_t_7 = ((!(__pyx_v_little_endian != 0)) != 0);
__pyx_t_6 = __pyx_t_7;
__pyx_L7_bool_binop_done:;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":801
- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd")
- *
- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<<
- * (child.byteorder == c'<' and not little_endian)):
- * raise ValueError(u"Non-native byte order not supported")
- */
if (__pyx_t_6) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":803
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":803
* if ((child.byteorder == c'>' and little_endian) or
* (child.byteorder == c'<' and not little_endian)):
* raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<<
* # One could encode it in the format string and have Cython
* # complain instead, BUT: < and > in format strings also imply
*/
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__34, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 803, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__38, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 803; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_Raise(__pyx_t_3, 0, 0, 0);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __PYX_ERR(1, 803, __pyx_L1_error)
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":801
- * raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd")
- *
- * if ((child.byteorder == c'>' and little_endian) or # <<<<<<<<<<<<<<
- * (child.byteorder == c'<' and not little_endian)):
- * raise ValueError(u"Non-native byte order not supported")
- */
+ {__pyx_filename = __pyx_f[1]; __pyx_lineno = 803; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":813
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":813
*
* # Output padding bytes
* while offset[0] < new_offset: # <<<<<<<<<<<<<<
@@ -16737,24 +15228,24 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
* f += 1
*/
while (1) {
- __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 813, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyInt_From_int((__pyx_v_offset[0])); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 813; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 813, __pyx_L1_error)
+ __pyx_t_4 = PyObject_RichCompare(__pyx_t_3, __pyx_v_new_offset, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 813; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 813, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 813; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (!__pyx_t_6) break;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":814
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":814
* # Output padding bytes
* while offset[0] < new_offset:
* f[0] = 120 # "x"; pad byte # <<<<<<<<<<<<<<
* f += 1
* offset[0] += 1
*/
- (__pyx_v_f[0]) = 0x78;
+ (__pyx_v_f[0]) = 120;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":815
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":815
* while offset[0] < new_offset:
* f[0] = 120 # "x"; pad byte
* f += 1 # <<<<<<<<<<<<<<
@@ -16763,7 +15254,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
*/
__pyx_v_f = (__pyx_v_f + 1);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":816
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":816
* f[0] = 120 # "x"; pad byte
* f += 1
* offset[0] += 1 # <<<<<<<<<<<<<<
@@ -16774,7 +15265,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
(__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + 1);
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":818
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":818
* offset[0] += 1
*
* offset[0] += child.itemsize # <<<<<<<<<<<<<<
@@ -16784,7 +15275,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
__pyx_t_8 = 0;
(__pyx_v_offset[__pyx_t_8]) = ((__pyx_v_offset[__pyx_t_8]) + __pyx_v_child->elsize);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":820
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":820
* offset[0] += child.itemsize
*
* if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<<
@@ -16794,19 +15285,19 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
__pyx_t_6 = ((!(PyDataType_HASFIELDS(__pyx_v_child) != 0)) != 0);
if (__pyx_t_6) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":821
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":821
*
* if not PyDataType_HASFIELDS(child):
* t = child.type_num # <<<<<<<<<<<<<<
* if end - f < 5:
* raise RuntimeError(u"Format string allocated too short.")
*/
- __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 821, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_child->type_num); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 821; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_4);
__pyx_t_4 = 0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":822
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":822
* if not PyDataType_HASFIELDS(child):
* t = child.type_num
* if end - f < 5: # <<<<<<<<<<<<<<
@@ -16816,365 +15307,357 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
__pyx_t_6 = (((__pyx_v_end - __pyx_v_f) < 5) != 0);
if (__pyx_t_6) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":823
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":823
* t = child.type_num
* if end - f < 5:
* raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<<
*
* # Until ticket #99 is fixed, use integers to avoid warnings
*/
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__35, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 823, __pyx_L1_error)
+ __pyx_t_4 = __Pyx_PyObject_Call(__pyx_builtin_RuntimeError, __pyx_tuple__39, NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 823; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
__Pyx_Raise(__pyx_t_4, 0, 0, 0);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __PYX_ERR(1, 823, __pyx_L1_error)
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":822
- * if not PyDataType_HASFIELDS(child):
- * t = child.type_num
- * if end - f < 5: # <<<<<<<<<<<<<<
- * raise RuntimeError(u"Format string allocated too short.")
- *
- */
+ {__pyx_filename = __pyx_f[1]; __pyx_lineno = 823; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":826
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":826
*
* # Until ticket #99 is fixed, use integers to avoid warnings
* if t == NPY_BYTE: f[0] = 98 #"b" # <<<<<<<<<<<<<<
* elif t == NPY_UBYTE: f[0] = 66 #"B"
* elif t == NPY_SHORT: f[0] = 104 #"h"
*/
- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_BYTE); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 826, __pyx_L1_error)
+ __pyx_t_4 = PyInt_FromLong(NPY_BYTE); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 826; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 826, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 826; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 826, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 826; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_6) {
(__pyx_v_f[0]) = 98;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":827
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":827
* # Until ticket #99 is fixed, use integers to avoid warnings
* if t == NPY_BYTE: f[0] = 98 #"b"
* elif t == NPY_UBYTE: f[0] = 66 #"B" # <<<<<<<<<<<<<<
* elif t == NPY_SHORT: f[0] = 104 #"h"
* elif t == NPY_USHORT: f[0] = 72 #"H"
*/
- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UBYTE); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 827, __pyx_L1_error)
+ __pyx_t_3 = PyInt_FromLong(NPY_UBYTE); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 827; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 827, __pyx_L1_error)
+ __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 827; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 827, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 827; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (__pyx_t_6) {
(__pyx_v_f[0]) = 66;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":828
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":828
* if t == NPY_BYTE: f[0] = 98 #"b"
* elif t == NPY_UBYTE: f[0] = 66 #"B"
* elif t == NPY_SHORT: f[0] = 104 #"h" # <<<<<<<<<<<<<<
* elif t == NPY_USHORT: f[0] = 72 #"H"
* elif t == NPY_INT: f[0] = 105 #"i"
*/
- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_SHORT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 828, __pyx_L1_error)
+ __pyx_t_4 = PyInt_FromLong(NPY_SHORT); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 828; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 828, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 828; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 828, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 828; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_6) {
- (__pyx_v_f[0]) = 0x68;
+ (__pyx_v_f[0]) = 104;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":829
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":829
* elif t == NPY_UBYTE: f[0] = 66 #"B"
* elif t == NPY_SHORT: f[0] = 104 #"h"
* elif t == NPY_USHORT: f[0] = 72 #"H" # <<<<<<<<<<<<<<
* elif t == NPY_INT: f[0] = 105 #"i"
* elif t == NPY_UINT: f[0] = 73 #"I"
*/
- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_USHORT); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 829, __pyx_L1_error)
+ __pyx_t_3 = PyInt_FromLong(NPY_USHORT); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 829; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 829, __pyx_L1_error)
+ __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 829; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 829, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 829; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (__pyx_t_6) {
(__pyx_v_f[0]) = 72;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":830
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":830
* elif t == NPY_SHORT: f[0] = 104 #"h"
* elif t == NPY_USHORT: f[0] = 72 #"H"
* elif t == NPY_INT: f[0] = 105 #"i" # <<<<<<<<<<<<<<
* elif t == NPY_UINT: f[0] = 73 #"I"
* elif t == NPY_LONG: f[0] = 108 #"l"
*/
- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_INT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 830, __pyx_L1_error)
+ __pyx_t_4 = PyInt_FromLong(NPY_INT); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 830; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 830, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 830; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 830, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 830; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_6) {
- (__pyx_v_f[0]) = 0x69;
+ (__pyx_v_f[0]) = 105;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":831
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":831
* elif t == NPY_USHORT: f[0] = 72 #"H"
* elif t == NPY_INT: f[0] = 105 #"i"
* elif t == NPY_UINT: f[0] = 73 #"I" # <<<<<<<<<<<<<<
* elif t == NPY_LONG: f[0] = 108 #"l"
* elif t == NPY_ULONG: f[0] = 76 #"L"
*/
- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_UINT); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 831, __pyx_L1_error)
+ __pyx_t_3 = PyInt_FromLong(NPY_UINT); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 831; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 831, __pyx_L1_error)
+ __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 831; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 831, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 831; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (__pyx_t_6) {
(__pyx_v_f[0]) = 73;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":832
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":832
* elif t == NPY_INT: f[0] = 105 #"i"
* elif t == NPY_UINT: f[0] = 73 #"I"
* elif t == NPY_LONG: f[0] = 108 #"l" # <<<<<<<<<<<<<<
* elif t == NPY_ULONG: f[0] = 76 #"L"
* elif t == NPY_LONGLONG: f[0] = 113 #"q"
*/
- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 832, __pyx_L1_error)
+ __pyx_t_4 = PyInt_FromLong(NPY_LONG); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 832; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 832, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 832; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 832, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 832; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_6) {
- (__pyx_v_f[0]) = 0x6C;
+ (__pyx_v_f[0]) = 108;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":833
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":833
* elif t == NPY_UINT: f[0] = 73 #"I"
* elif t == NPY_LONG: f[0] = 108 #"l"
* elif t == NPY_ULONG: f[0] = 76 #"L" # <<<<<<<<<<<<<<
* elif t == NPY_LONGLONG: f[0] = 113 #"q"
* elif t == NPY_ULONGLONG: f[0] = 81 #"Q"
*/
- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 833, __pyx_L1_error)
+ __pyx_t_3 = PyInt_FromLong(NPY_ULONG); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 833; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 833, __pyx_L1_error)
+ __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 833; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 833, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 833; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (__pyx_t_6) {
(__pyx_v_f[0]) = 76;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":834
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":834
* elif t == NPY_LONG: f[0] = 108 #"l"
* elif t == NPY_ULONG: f[0] = 76 #"L"
* elif t == NPY_LONGLONG: f[0] = 113 #"q" # <<<<<<<<<<<<<<
* elif t == NPY_ULONGLONG: f[0] = 81 #"Q"
* elif t == NPY_FLOAT: f[0] = 102 #"f"
*/
- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 834, __pyx_L1_error)
+ __pyx_t_4 = PyInt_FromLong(NPY_LONGLONG); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 834; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 834, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 834; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 834, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 834; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_6) {
- (__pyx_v_f[0]) = 0x71;
+ (__pyx_v_f[0]) = 113;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":835
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":835
* elif t == NPY_ULONG: f[0] = 76 #"L"
* elif t == NPY_LONGLONG: f[0] = 113 #"q"
* elif t == NPY_ULONGLONG: f[0] = 81 #"Q" # <<<<<<<<<<<<<<
* elif t == NPY_FLOAT: f[0] = 102 #"f"
* elif t == NPY_DOUBLE: f[0] = 100 #"d"
*/
- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 835, __pyx_L1_error)
+ __pyx_t_3 = PyInt_FromLong(NPY_ULONGLONG); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 835; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 835, __pyx_L1_error)
+ __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 835; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 835, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 835; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (__pyx_t_6) {
(__pyx_v_f[0]) = 81;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":836
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":836
* elif t == NPY_LONGLONG: f[0] = 113 #"q"
* elif t == NPY_ULONGLONG: f[0] = 81 #"Q"
* elif t == NPY_FLOAT: f[0] = 102 #"f" # <<<<<<<<<<<<<<
* elif t == NPY_DOUBLE: f[0] = 100 #"d"
* elif t == NPY_LONGDOUBLE: f[0] = 103 #"g"
*/
- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_FLOAT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 836, __pyx_L1_error)
+ __pyx_t_4 = PyInt_FromLong(NPY_FLOAT); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 836; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 836, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 836; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 836, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 836; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_6) {
- (__pyx_v_f[0]) = 0x66;
+ (__pyx_v_f[0]) = 102;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":837
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":837
* elif t == NPY_ULONGLONG: f[0] = 81 #"Q"
* elif t == NPY_FLOAT: f[0] = 102 #"f"
* elif t == NPY_DOUBLE: f[0] = 100 #"d" # <<<<<<<<<<<<<<
* elif t == NPY_LONGDOUBLE: f[0] = 103 #"g"
* elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf
*/
- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 837, __pyx_L1_error)
+ __pyx_t_3 = PyInt_FromLong(NPY_DOUBLE); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 837; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 837, __pyx_L1_error)
+ __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 837; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 837, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 837; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (__pyx_t_6) {
- (__pyx_v_f[0]) = 0x64;
+ (__pyx_v_f[0]) = 100;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":838
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":838
* elif t == NPY_FLOAT: f[0] = 102 #"f"
* elif t == NPY_DOUBLE: f[0] = 100 #"d"
* elif t == NPY_LONGDOUBLE: f[0] = 103 #"g" # <<<<<<<<<<<<<<
* elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf
* elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd
*/
- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 838, __pyx_L1_error)
+ __pyx_t_4 = PyInt_FromLong(NPY_LONGDOUBLE); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 838; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 838, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 838; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 838, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 838; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_6) {
- (__pyx_v_f[0]) = 0x67;
+ (__pyx_v_f[0]) = 103;
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":839
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":839
* elif t == NPY_DOUBLE: f[0] = 100 #"d"
* elif t == NPY_LONGDOUBLE: f[0] = 103 #"g"
* elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf # <<<<<<<<<<<<<<
* elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd
* elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg
*/
- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 839, __pyx_L1_error)
+ __pyx_t_3 = PyInt_FromLong(NPY_CFLOAT); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 839; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 839, __pyx_L1_error)
+ __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 839; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 839, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 839; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (__pyx_t_6) {
(__pyx_v_f[0]) = 90;
- (__pyx_v_f[1]) = 0x66;
+ (__pyx_v_f[1]) = 102;
__pyx_v_f = (__pyx_v_f + 1);
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":840
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":840
* elif t == NPY_LONGDOUBLE: f[0] = 103 #"g"
* elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf
* elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd # <<<<<<<<<<<<<<
* elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg
* elif t == NPY_OBJECT: f[0] = 79 #"O"
*/
- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 840, __pyx_L1_error)
+ __pyx_t_4 = PyInt_FromLong(NPY_CDOUBLE); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 840; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 840, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 840; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 840, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 840; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_6) {
(__pyx_v_f[0]) = 90;
- (__pyx_v_f[1]) = 0x64;
+ (__pyx_v_f[1]) = 100;
__pyx_v_f = (__pyx_v_f + 1);
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":841
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":841
* elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1 # Zf
* elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd
* elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg # <<<<<<<<<<<<<<
* elif t == NPY_OBJECT: f[0] = 79 #"O"
* else:
*/
- __pyx_t_3 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 841, __pyx_L1_error)
+ __pyx_t_3 = PyInt_FromLong(NPY_CLONGDOUBLE); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 841; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 841, __pyx_L1_error)
+ __pyx_t_4 = PyObject_RichCompare(__pyx_v_t, __pyx_t_3, Py_EQ); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 841; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 841, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 841; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
if (__pyx_t_6) {
(__pyx_v_f[0]) = 90;
- (__pyx_v_f[1]) = 0x67;
+ (__pyx_v_f[1]) = 103;
__pyx_v_f = (__pyx_v_f + 1);
goto __pyx_L15;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":842
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":842
* elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1 # Zd
* elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1 # Zg
* elif t == NPY_OBJECT: f[0] = 79 #"O" # <<<<<<<<<<<<<<
* else:
* raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t)
*/
- __pyx_t_4 = __Pyx_PyInt_From_enum__NPY_TYPES(NPY_OBJECT); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 842, __pyx_L1_error)
+ __pyx_t_4 = PyInt_FromLong(NPY_OBJECT); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 842; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 842, __pyx_L1_error)
+ __pyx_t_3 = PyObject_RichCompare(__pyx_v_t, __pyx_t_4, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 842; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(1, 842, __pyx_L1_error)
+ __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_6 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 842; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
if (__pyx_t_6) {
(__pyx_v_f[0]) = 79;
goto __pyx_L15;
}
+ /*else*/ {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":844
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":844
* elif t == NPY_OBJECT: f[0] = 79 #"O"
* else:
* raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t) # <<<<<<<<<<<<<<
* f += 1
* else:
*/
- /*else*/ {
- __pyx_t_3 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 844, __pyx_L1_error)
+ __pyx_t_3 = PyUnicode_Format(__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_v_t); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 844; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 844, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 844; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_3);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3);
+ __Pyx_GIVEREF(__pyx_t_3);
__pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_t_4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 844, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_t_4, NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 844; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_Raise(__pyx_t_3, 0, 0, 0);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __PYX_ERR(1, 844, __pyx_L1_error)
+ {__pyx_filename = __pyx_f[1]; __pyx_lineno = 844; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
__pyx_L15:;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":845
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":845
* else:
* raise ValueError(u"unknown dtype code in numpy.pxd (%d)" % t)
* f += 1 # <<<<<<<<<<<<<<
@@ -17182,31 +15665,23 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
* # Cython ignores struct boundary information ("T{...}"),
*/
__pyx_v_f = (__pyx_v_f + 1);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":820
- * offset[0] += child.itemsize
- *
- * if not PyDataType_HASFIELDS(child): # <<<<<<<<<<<<<<
- * t = child.type_num
- * if end - f < 5:
- */
goto __pyx_L13;
}
+ /*else*/ {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":849
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":849
* # Cython ignores struct boundary information ("T{...}"),
* # so don't output it
* f = _util_dtypestring(child, f, end, offset) # <<<<<<<<<<<<<<
* return f
*
*/
- /*else*/ {
- __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == NULL)) __PYX_ERR(1, 849, __pyx_L1_error)
+ __pyx_t_9 = __pyx_f_5numpy__util_dtypestring(__pyx_v_child, __pyx_v_f, __pyx_v_end, __pyx_v_offset); if (unlikely(__pyx_t_9 == NULL)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 849; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_v_f = __pyx_t_9;
}
__pyx_L13:;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":794
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":794
* cdef tuple fields
*
* for childname in descr.names: # <<<<<<<<<<<<<<
@@ -17216,7 +15691,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":850
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":850
* # so don't output it
* f = _util_dtypestring(child, f, end, offset)
* return f # <<<<<<<<<<<<<<
@@ -17226,7 +15701,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
__pyx_r = __pyx_v_f;
goto __pyx_L0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":785
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":783
* return PyArray_MultiIterNew(5, <void*>a, <void*>b, <void*>c, <void*> d, <void*> e)
*
* cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset) except NULL: # <<<<<<<<<<<<<<
@@ -17251,7 +15726,7 @@ static CYTHON_INLINE char *__pyx_f_5numpy__util_dtypestring(PyArray_Descr *__pyx
return __pyx_r;
}
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":966
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":966
*
*
* cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<<
@@ -17266,7 +15741,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
int __pyx_t_2;
__Pyx_RefNannySetupContext("set_array_base", 0);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":968
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":968
* cdef inline void set_array_base(ndarray arr, object base):
* cdef PyObject* baseptr
* if base is None: # <<<<<<<<<<<<<<
@@ -17277,7 +15752,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
__pyx_t_2 = (__pyx_t_1 != 0);
if (__pyx_t_2) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":969
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":969
* cdef PyObject* baseptr
* if base is None:
* baseptr = NULL # <<<<<<<<<<<<<<
@@ -17285,28 +15760,20 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
* Py_INCREF(base) # important to do this before decref below!
*/
__pyx_v_baseptr = NULL;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":968
- * cdef inline void set_array_base(ndarray arr, object base):
- * cdef PyObject* baseptr
- * if base is None: # <<<<<<<<<<<<<<
- * baseptr = NULL
- * else:
- */
goto __pyx_L3;
}
+ /*else*/ {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":971
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":971
* baseptr = NULL
* else:
* Py_INCREF(base) # important to do this before decref below! # <<<<<<<<<<<<<<
* baseptr = <PyObject*>base
* Py_XDECREF(arr.base)
*/
- /*else*/ {
Py_INCREF(__pyx_v_base);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":972
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":972
* else:
* Py_INCREF(base) # important to do this before decref below!
* baseptr = <PyObject*>base # <<<<<<<<<<<<<<
@@ -17317,7 +15784,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
}
__pyx_L3:;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":973
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":973
* Py_INCREF(base) # important to do this before decref below!
* baseptr = <PyObject*>base
* Py_XDECREF(arr.base) # <<<<<<<<<<<<<<
@@ -17326,7 +15793,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
*/
Py_XDECREF(__pyx_v_arr->base);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":974
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":974
* baseptr = <PyObject*>base
* Py_XDECREF(arr.base)
* arr.base = baseptr # <<<<<<<<<<<<<<
@@ -17335,7 +15802,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
*/
__pyx_v_arr->base = __pyx_v_baseptr;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":966
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":966
*
*
* cdef inline void set_array_base(ndarray arr, object base): # <<<<<<<<<<<<<<
@@ -17347,7 +15814,7 @@ static CYTHON_INLINE void __pyx_f_5numpy_set_array_base(PyArrayObject *__pyx_v_a
__Pyx_RefNannyFinishContext();
}
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":976
+/* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":976
* arr.base = baseptr
*
* cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<<
@@ -17361,7 +15828,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
int __pyx_t_1;
__Pyx_RefNannySetupContext("get_array_base", 0);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":977
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":977
*
* cdef inline object get_array_base(ndarray arr):
* if arr.base is NULL: # <<<<<<<<<<<<<<
@@ -17371,7 +15838,7 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
__pyx_t_1 = ((__pyx_v_arr->base == NULL) != 0);
if (__pyx_t_1) {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":978
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":978
* cdef inline object get_array_base(ndarray arr):
* if arr.base is NULL:
* return None # <<<<<<<<<<<<<<
@@ -17382,31 +15849,21 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
__Pyx_INCREF(Py_None);
__pyx_r = Py_None;
goto __pyx_L0;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":977
- *
- * cdef inline object get_array_base(ndarray arr):
- * if arr.base is NULL: # <<<<<<<<<<<<<<
- * return None
- * else:
- */
}
+ /*else*/ {
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":980
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":980
* return None
* else:
* return <object>arr.base # <<<<<<<<<<<<<<
- *
- *
*/
- /*else*/ {
__Pyx_XDECREF(__pyx_r);
__Pyx_INCREF(((PyObject *)__pyx_v_arr->base));
__pyx_r = ((PyObject *)__pyx_v_arr->base);
goto __pyx_L0;
}
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":976
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":976
* arr.base = baseptr
*
* cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<<
@@ -17421,396 +15878,6 @@ static CYTHON_INLINE PyObject *__pyx_f_5numpy_get_array_base(PyArrayObject *__py
return __pyx_r;
}
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":985
- * # Versions of the import_* functions which are more suitable for
- * # Cython code.
- * cdef inline int import_array() except -1: # <<<<<<<<<<<<<<
- * try:
- * _import_array()
- */
-
-static CYTHON_INLINE int __pyx_f_5numpy_import_array(void) {
- int __pyx_r;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- PyObject *__pyx_t_2 = NULL;
- PyObject *__pyx_t_3 = NULL;
- int __pyx_t_4;
- PyObject *__pyx_t_5 = NULL;
- PyObject *__pyx_t_6 = NULL;
- PyObject *__pyx_t_7 = NULL;
- PyObject *__pyx_t_8 = NULL;
- __Pyx_RefNannySetupContext("import_array", 0);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":986
- * # Cython code.
- * cdef inline int import_array() except -1:
- * try: # <<<<<<<<<<<<<<
- * _import_array()
- * except Exception:
- */
- {
- __Pyx_PyThreadState_declare
- __Pyx_PyThreadState_assign
- __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3);
- __Pyx_XGOTREF(__pyx_t_1);
- __Pyx_XGOTREF(__pyx_t_2);
- __Pyx_XGOTREF(__pyx_t_3);
- /*try:*/ {
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":987
- * cdef inline int import_array() except -1:
- * try:
- * _import_array() # <<<<<<<<<<<<<<
- * except Exception:
- * raise ImportError("numpy.core.multiarray failed to import")
- */
- __pyx_t_4 = _import_array(); if (unlikely(__pyx_t_4 == -1)) __PYX_ERR(1, 987, __pyx_L3_error)
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":986
- * # Cython code.
- * cdef inline int import_array() except -1:
- * try: # <<<<<<<<<<<<<<
- * _import_array()
- * except Exception:
- */
- }
- __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- goto __pyx_L10_try_end;
- __pyx_L3_error:;
- __Pyx_PyThreadState_assign
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":988
- * try:
- * _import_array()
- * except Exception: # <<<<<<<<<<<<<<
- * raise ImportError("numpy.core.multiarray failed to import")
- *
- */
- __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0])));
- if (__pyx_t_4) {
- __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename);
- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 988, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_GOTREF(__pyx_t_7);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":989
- * _import_array()
- * except Exception:
- * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<<
- *
- * cdef inline int import_umath() except -1:
- */
- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__36, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 989, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_Raise(__pyx_t_8, 0, 0, 0);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- __PYX_ERR(1, 989, __pyx_L5_except_error)
- }
- goto __pyx_L5_except_error;
- __pyx_L5_except_error:;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":986
- * # Cython code.
- * cdef inline int import_array() except -1:
- * try: # <<<<<<<<<<<<<<
- * _import_array()
- * except Exception:
- */
- __Pyx_PyThreadState_assign
- __Pyx_XGIVEREF(__pyx_t_1);
- __Pyx_XGIVEREF(__pyx_t_2);
- __Pyx_XGIVEREF(__pyx_t_3);
- __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3);
- goto __pyx_L1_error;
- __pyx_L10_try_end:;
- }
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":985
- * # Versions of the import_* functions which are more suitable for
- * # Cython code.
- * cdef inline int import_array() except -1: # <<<<<<<<<<<<<<
- * try:
- * _import_array()
- */
-
- /* function exit code */
- __pyx_r = 0;
- goto __pyx_L0;
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_5);
- __Pyx_XDECREF(__pyx_t_6);
- __Pyx_XDECREF(__pyx_t_7);
- __Pyx_XDECREF(__pyx_t_8);
- __Pyx_AddTraceback("numpy.import_array", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = -1;
- __pyx_L0:;
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":991
- * raise ImportError("numpy.core.multiarray failed to import")
- *
- * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<<
- * try:
- * _import_umath()
- */
-
-static CYTHON_INLINE int __pyx_f_5numpy_import_umath(void) {
- int __pyx_r;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- PyObject *__pyx_t_2 = NULL;
- PyObject *__pyx_t_3 = NULL;
- int __pyx_t_4;
- PyObject *__pyx_t_5 = NULL;
- PyObject *__pyx_t_6 = NULL;
- PyObject *__pyx_t_7 = NULL;
- PyObject *__pyx_t_8 = NULL;
- __Pyx_RefNannySetupContext("import_umath", 0);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":992
- *
- * cdef inline int import_umath() except -1:
- * try: # <<<<<<<<<<<<<<
- * _import_umath()
- * except Exception:
- */
- {
- __Pyx_PyThreadState_declare
- __Pyx_PyThreadState_assign
- __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3);
- __Pyx_XGOTREF(__pyx_t_1);
- __Pyx_XGOTREF(__pyx_t_2);
- __Pyx_XGOTREF(__pyx_t_3);
- /*try:*/ {
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":993
- * cdef inline int import_umath() except -1:
- * try:
- * _import_umath() # <<<<<<<<<<<<<<
- * except Exception:
- * raise ImportError("numpy.core.umath failed to import")
- */
- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == -1)) __PYX_ERR(1, 993, __pyx_L3_error)
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":992
- *
- * cdef inline int import_umath() except -1:
- * try: # <<<<<<<<<<<<<<
- * _import_umath()
- * except Exception:
- */
- }
- __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- goto __pyx_L10_try_end;
- __pyx_L3_error:;
- __Pyx_PyThreadState_assign
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":994
- * try:
- * _import_umath()
- * except Exception: # <<<<<<<<<<<<<<
- * raise ImportError("numpy.core.umath failed to import")
- *
- */
- __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0])));
- if (__pyx_t_4) {
- __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename);
- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 994, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_GOTREF(__pyx_t_7);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":995
- * _import_umath()
- * except Exception:
- * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<<
- *
- * cdef inline int import_ufunc() except -1:
- */
- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__37, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 995, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_Raise(__pyx_t_8, 0, 0, 0);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- __PYX_ERR(1, 995, __pyx_L5_except_error)
- }
- goto __pyx_L5_except_error;
- __pyx_L5_except_error:;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":992
- *
- * cdef inline int import_umath() except -1:
- * try: # <<<<<<<<<<<<<<
- * _import_umath()
- * except Exception:
- */
- __Pyx_PyThreadState_assign
- __Pyx_XGIVEREF(__pyx_t_1);
- __Pyx_XGIVEREF(__pyx_t_2);
- __Pyx_XGIVEREF(__pyx_t_3);
- __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3);
- goto __pyx_L1_error;
- __pyx_L10_try_end:;
- }
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":991
- * raise ImportError("numpy.core.multiarray failed to import")
- *
- * cdef inline int import_umath() except -1: # <<<<<<<<<<<<<<
- * try:
- * _import_umath()
- */
-
- /* function exit code */
- __pyx_r = 0;
- goto __pyx_L0;
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_5);
- __Pyx_XDECREF(__pyx_t_6);
- __Pyx_XDECREF(__pyx_t_7);
- __Pyx_XDECREF(__pyx_t_8);
- __Pyx_AddTraceback("numpy.import_umath", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = -1;
- __pyx_L0:;
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":997
- * raise ImportError("numpy.core.umath failed to import")
- *
- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<<
- * try:
- * _import_umath()
- */
-
-static CYTHON_INLINE int __pyx_f_5numpy_import_ufunc(void) {
- int __pyx_r;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- PyObject *__pyx_t_2 = NULL;
- PyObject *__pyx_t_3 = NULL;
- int __pyx_t_4;
- PyObject *__pyx_t_5 = NULL;
- PyObject *__pyx_t_6 = NULL;
- PyObject *__pyx_t_7 = NULL;
- PyObject *__pyx_t_8 = NULL;
- __Pyx_RefNannySetupContext("import_ufunc", 0);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":998
- *
- * cdef inline int import_ufunc() except -1:
- * try: # <<<<<<<<<<<<<<
- * _import_umath()
- * except Exception:
- */
- {
- __Pyx_PyThreadState_declare
- __Pyx_PyThreadState_assign
- __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3);
- __Pyx_XGOTREF(__pyx_t_1);
- __Pyx_XGOTREF(__pyx_t_2);
- __Pyx_XGOTREF(__pyx_t_3);
- /*try:*/ {
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":999
- * cdef inline int import_ufunc() except -1:
- * try:
- * _import_umath() # <<<<<<<<<<<<<<
- * except Exception:
- * raise ImportError("numpy.core.umath failed to import")
- */
- __pyx_t_4 = _import_umath(); if (unlikely(__pyx_t_4 == -1)) __PYX_ERR(1, 999, __pyx_L3_error)
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":998
- *
- * cdef inline int import_ufunc() except -1:
- * try: # <<<<<<<<<<<<<<
- * _import_umath()
- * except Exception:
- */
- }
- __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- goto __pyx_L10_try_end;
- __pyx_L3_error:;
- __Pyx_PyThreadState_assign
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":1000
- * try:
- * _import_umath()
- * except Exception: # <<<<<<<<<<<<<<
- * raise ImportError("numpy.core.umath failed to import")
- */
- __pyx_t_4 = __Pyx_PyErr_ExceptionMatches(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0])));
- if (__pyx_t_4) {
- __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename);
- if (__Pyx_GetException(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7) < 0) __PYX_ERR(1, 1000, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_GOTREF(__pyx_t_7);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":1001
- * _import_umath()
- * except Exception:
- * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<<
- */
- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__38, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 1001, __pyx_L5_except_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_Raise(__pyx_t_8, 0, 0, 0);
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- __PYX_ERR(1, 1001, __pyx_L5_except_error)
- }
- goto __pyx_L5_except_error;
- __pyx_L5_except_error:;
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":998
- *
- * cdef inline int import_ufunc() except -1:
- * try: # <<<<<<<<<<<<<<
- * _import_umath()
- * except Exception:
- */
- __Pyx_PyThreadState_assign
- __Pyx_XGIVEREF(__pyx_t_1);
- __Pyx_XGIVEREF(__pyx_t_2);
- __Pyx_XGIVEREF(__pyx_t_3);
- __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3);
- goto __pyx_L1_error;
- __pyx_L10_try_end:;
- }
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":997
- * raise ImportError("numpy.core.umath failed to import")
- *
- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<<
- * try:
- * _import_umath()
- */
-
- /* function exit code */
- __pyx_r = 0;
- goto __pyx_L0;
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_5);
- __Pyx_XDECREF(__pyx_t_6);
- __Pyx_XDECREF(__pyx_t_7);
- __Pyx_XDECREF(__pyx_t_8);
- __Pyx_AddTraceback("numpy.import_ufunc", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = -1;
- __pyx_L0:;
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
static PyObject *__pyx_tp_new_4silx_2io_8specfile_SpecFile(PyTypeObject *t, PyObject *a, PyObject *k) {
struct __pyx_obj_4silx_2io_8specfile_SpecFile *p;
PyObject *o;
@@ -17822,11 +15889,10 @@ static PyObject *__pyx_tp_new_4silx_2io_8specfile_SpecFile(PyTypeObject *t, PyOb
if (unlikely(!o)) return 0;
p = ((struct __pyx_obj_4silx_2io_8specfile_SpecFile *)o);
p->filename = ((PyObject*)Py_None); Py_INCREF(Py_None);
- if (unlikely(__pyx_pw_4silx_2io_8specfile_8SpecFile_1__cinit__(o, a, k) < 0)) goto bad;
+ if (unlikely(__pyx_pw_4silx_2io_8specfile_8SpecFile_1__cinit__(o, a, k) < 0)) {
+ Py_DECREF(o); o = 0;
+ }
return o;
- bad:
- Py_DECREF(o); o = 0;
- return NULL;
}
static void __pyx_tp_dealloc_4silx_2io_8specfile_SpecFile(PyObject *o) {
@@ -17856,47 +15922,48 @@ static PyObject *__pyx_sq_item_4silx_2io_8specfile_SpecFile(PyObject *o, Py_ssiz
}
static PyMethodDef __pyx_methods_4silx_2io_8specfile_SpecFile[] = {
- {"keys", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_14keys, METH_NOARGS, __pyx_doc_4silx_2io_8specfile_8SpecFile_13keys},
- {"_get_error_string", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_18_get_error_string, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_17_get_error_string},
- {"_handle_error", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_20_handle_error, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_19_handle_error},
- {"index", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_22index, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_21index},
- {"number", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_24number, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_23number},
- {"order", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_26order, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_25order},
- {"_list", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_28_list, METH_NOARGS, __pyx_doc_4silx_2io_8specfile_8SpecFile_27_list},
- {"list", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_30list, METH_NOARGS, __pyx_doc_4silx_2io_8specfile_8SpecFile_29list},
- {"data", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_32data, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_31data},
- {"data_column_by_name", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_34data_column_by_name, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_33data_column_by_name},
- {"scan_header", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_36scan_header, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_35scan_header},
- {"file_header", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_38file_header, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_37file_header},
- {"columns", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_40columns, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_39columns},
- {"command", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_42command, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_41command},
- {"date", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_44date, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_43date},
- {"labels", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_46labels, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_45labels},
- {"motor_names", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_48motor_names, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_47motor_names},
- {"motor_positions", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_50motor_positions, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_49motor_positions},
- {"motor_position_by_name", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_52motor_position_by_name, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_51motor_position_by_name},
- {"number_of_mca", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_54number_of_mca, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_53number_of_mca},
- {"mca_calibration", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_56mca_calibration, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_55mca_calibration},
- {"get_mca", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_58get_mca, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_57get_mca},
+ {"close", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_7close, METH_NOARGS, __pyx_doc_4silx_2io_8specfile_8SpecFile_6close},
+ {"keys", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_16keys, METH_NOARGS, __pyx_doc_4silx_2io_8specfile_8SpecFile_15keys},
+ {"_get_error_string", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_20_get_error_string, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_19_get_error_string},
+ {"_handle_error", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_22_handle_error, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_21_handle_error},
+ {"index", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_24index, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_23index},
+ {"number", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_26number, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_25number},
+ {"order", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_28order, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_27order},
+ {"_list", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_30_list, METH_NOARGS, __pyx_doc_4silx_2io_8specfile_8SpecFile_29_list},
+ {"list", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_32list, METH_NOARGS, __pyx_doc_4silx_2io_8specfile_8SpecFile_31list},
+ {"data", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_34data, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_33data},
+ {"data_column_by_name", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_36data_column_by_name, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_35data_column_by_name},
+ {"scan_header", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_38scan_header, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_37scan_header},
+ {"file_header", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_40file_header, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_39file_header},
+ {"columns", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_42columns, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_41columns},
+ {"command", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_44command, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_43command},
+ {"date", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_46date, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_45date},
+ {"labels", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_48labels, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_47labels},
+ {"motor_names", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_50motor_names, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_49motor_names},
+ {"motor_positions", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_52motor_positions, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_51motor_positions},
+ {"motor_position_by_name", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_54motor_position_by_name, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_53motor_position_by_name},
+ {"number_of_mca", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_56number_of_mca, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_55number_of_mca},
+ {"mca_calibration", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_58mca_calibration, METH_O, __pyx_doc_4silx_2io_8specfile_8SpecFile_57mca_calibration},
+ {"get_mca", (PyCFunction)__pyx_pw_4silx_2io_8specfile_8SpecFile_60get_mca, METH_VARARGS|METH_KEYWORDS, __pyx_doc_4silx_2io_8specfile_8SpecFile_59get_mca},
{0, 0, 0, 0}
};
static PySequenceMethods __pyx_tp_as_sequence_SpecFile = {
- __pyx_pw_4silx_2io_8specfile_8SpecFile_7__len__, /*sq_length*/
+ __pyx_pw_4silx_2io_8specfile_8SpecFile_9__len__, /*sq_length*/
0, /*sq_concat*/
0, /*sq_repeat*/
__pyx_sq_item_4silx_2io_8specfile_SpecFile, /*sq_item*/
0, /*sq_slice*/
0, /*sq_ass_item*/
0, /*sq_ass_slice*/
- __pyx_pw_4silx_2io_8specfile_8SpecFile_16__contains__, /*sq_contains*/
+ __pyx_pw_4silx_2io_8specfile_8SpecFile_18__contains__, /*sq_contains*/
0, /*sq_inplace_concat*/
0, /*sq_inplace_repeat*/
};
static PyMappingMethods __pyx_tp_as_mapping_SpecFile = {
- __pyx_pw_4silx_2io_8specfile_8SpecFile_7__len__, /*mp_length*/
- __pyx_pw_4silx_2io_8specfile_8SpecFile_12__getitem__, /*mp_subscript*/
+ __pyx_pw_4silx_2io_8specfile_8SpecFile_9__len__, /*mp_length*/
+ __pyx_pw_4silx_2io_8specfile_8SpecFile_14__getitem__, /*mp_subscript*/
0, /*mp_ass_subscript*/
};
@@ -17911,9 +15978,8 @@ static PyTypeObject __pyx_type_4silx_2io_8specfile_SpecFile = {
0, /*tp_setattr*/
#if PY_MAJOR_VERSION < 3
0, /*tp_compare*/
- #endif
- #if PY_MAJOR_VERSION >= 3
- 0, /*tp_as_async*/
+ #else
+ 0, /*reserved*/
#endif
0, /*tp_repr*/
0, /*tp_as_number*/
@@ -17931,7 +15997,7 @@ static PyTypeObject __pyx_type_4silx_2io_8specfile_SpecFile = {
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
- __pyx_pw_4silx_2io_8specfile_8SpecFile_9__iter__, /*tp_iter*/
+ __pyx_pw_4silx_2io_8specfile_8SpecFile_11__iter__, /*tp_iter*/
0, /*tp_iternext*/
__pyx_methods_4silx_2io_8specfile_SpecFile, /*tp_methods*/
0, /*tp_members*/
@@ -18015,9 +16081,8 @@ static PyTypeObject __pyx_type_4silx_2io_8specfile___pyx_scope_struct____iter__
0, /*tp_setattr*/
#if PY_MAJOR_VERSION < 3
0, /*tp_compare*/
- #endif
- #if PY_MAJOR_VERSION >= 3
- 0, /*tp_as_async*/
+ #else
+ 0, /*reserved*/
#endif
0, /*tp_repr*/
0, /*tp_as_number*/
@@ -18119,9 +16184,8 @@ static PyTypeObject __pyx_type_4silx_2io_8specfile___pyx_scope_struct_1___iter__
0, /*tp_setattr*/
#if PY_MAJOR_VERSION < 3
0, /*tp_compare*/
- #endif
- #if PY_MAJOR_VERSION >= 3
- 0, /*tp_as_async*/
+ #else
+ 0, /*reserved*/
#endif
0, /*tp_repr*/
0, /*tp_as_number*/
@@ -18189,6 +16253,7 @@ static struct PyModuleDef __pyx_moduledef = {
#endif
static __Pyx_StringTabEntry __pyx_string_tab[] = {
+ {&__pyx_kp_b_, __pyx_k_, sizeof(__pyx_k_), 0, 0, 0, 0},
{&__pyx_kp_s_, __pyx_k_, sizeof(__pyx_k_), 0, 0, 1, 0},
{&__pyx_kp_s_11_08_2017, __pyx_k_11_08_2017, sizeof(__pyx_k_11_08_2017), 0, 0, 1, 0},
{&__pyx_kp_s_2, __pyx_k_2, sizeof(__pyx_k_2), 0, 0, 1, 0},
@@ -18201,12 +16266,12 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{&__pyx_kp_s_Custom_exception_raised_when_SfN, __pyx_k_Custom_exception_raised_when_SfN, sizeof(__pyx_k_Custom_exception_raised_when_SfN), 0, 0, 1, 0},
{&__pyx_n_s_ERRORS, __pyx_k_ERRORS, sizeof(__pyx_k_ERRORS), 0, 0, 1, 1},
{&__pyx_kp_s_Error_while_closing_SpecFile, __pyx_k_Error_while_closing_SpecFile, sizeof(__pyx_k_Error_while_closing_SpecFile), 0, 0, 1, 0},
- {&__pyx_kp_s_F, __pyx_k_F, sizeof(__pyx_k_F), 0, 0, 1, 0},
+ {&__pyx_n_s_Exception, __pyx_k_Exception, sizeof(__pyx_k_Exception), 0, 0, 1, 1},
+ {&__pyx_kp_b_F, __pyx_k_F, sizeof(__pyx_k_F), 0, 0, 0, 0},
{&__pyx_kp_s_Failed_to_retrieve_number_of_MCA, __pyx_k_Failed_to_retrieve_number_of_MCA, sizeof(__pyx_k_Failed_to_retrieve_number_of_MCA), 0, 0, 1, 0},
{&__pyx_kp_u_Format_string_allocated_too_shor, __pyx_k_Format_string_allocated_too_shor, sizeof(__pyx_k_Format_string_allocated_too_shor), 0, 1, 0, 0},
{&__pyx_kp_u_Format_string_allocated_too_shor_2, __pyx_k_Format_string_allocated_too_shor_2, sizeof(__pyx_k_Format_string_allocated_too_shor_2), 0, 1, 0, 0},
{&__pyx_n_s_IOError, __pyx_k_IOError, sizeof(__pyx_k_IOError), 0, 0, 1, 1},
- {&__pyx_n_s_ImportError, __pyx_k_ImportError, sizeof(__pyx_k_ImportError), 0, 0, 1, 1},
{&__pyx_n_s_IndexError, __pyx_k_IndexError, sizeof(__pyx_k_IndexError), 0, 0, 1, 1},
{&__pyx_n_s_KeyError, __pyx_k_KeyError, sizeof(__pyx_k_KeyError), 0, 0, 1, 1},
{&__pyx_n_s_L, __pyx_k_L, sizeof(__pyx_k_L), 0, 0, 1, 1},
@@ -18228,7 +16293,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{&__pyx_kp_s_P_Knobel, __pyx_k_P_Knobel, sizeof(__pyx_k_P_Knobel), 0, 0, 1, 0},
{&__pyx_kp_s_Parameter_value_must_be_a_string, __pyx_k_Parameter_value_must_be_a_string, sizeof(__pyx_k_Parameter_value_must_be_a_string), 0, 0, 1, 0},
{&__pyx_n_s_RuntimeError, __pyx_k_RuntimeError, sizeof(__pyx_k_RuntimeError), 0, 0, 1, 1},
- {&__pyx_kp_s_S, __pyx_k_S, sizeof(__pyx_k_S), 0, 0, 1, 0},
+ {&__pyx_kp_b_S, __pyx_k_S, sizeof(__pyx_k_S), 0, 0, 0, 0},
{&__pyx_n_s_SF_ERR_FILE_OPEN, __pyx_k_SF_ERR_FILE_OPEN, sizeof(__pyx_k_SF_ERR_FILE_OPEN), 0, 0, 1, 1},
{&__pyx_n_s_SF_ERR_NO_ERRORS, __pyx_k_SF_ERR_NO_ERRORS, sizeof(__pyx_k_SF_ERR_NO_ERRORS), 0, 0, 1, 1},
{&__pyx_n_s_SF_ERR_SCAN_NOT_FOUND, __pyx_k_SF_ERR_SCAN_NOT_FOUND, sizeof(__pyx_k_SF_ERR_SCAN_NOT_FOUND), 0, 0, 1, 1},
@@ -18279,9 +16344,9 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{&__pyx_kp_s_Valid_keys, __pyx_k_Valid_keys, sizeof(__pyx_k_Valid_keys), 0, 0, 1, 0},
{&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1},
{&__pyx_kp_s__14, __pyx_k__14, sizeof(__pyx_k__14), 0, 0, 1, 0},
- {&__pyx_kp_s__25, __pyx_k__25, sizeof(__pyx_k__25), 0, 0, 1, 0},
- {&__pyx_kp_s__27, __pyx_k__27, sizeof(__pyx_k__27), 0, 0, 1, 0},
{&__pyx_kp_s__28, __pyx_k__28, sizeof(__pyx_k__28), 0, 0, 1, 0},
+ {&__pyx_kp_s__30, __pyx_k__30, sizeof(__pyx_k__30), 0, 0, 1, 0},
+ {&__pyx_kp_s__31, __pyx_k__31, sizeof(__pyx_k__31), 0, 0, 1, 0},
{&__pyx_kp_s__7, __pyx_k__7, sizeof(__pyx_k__7), 0, 0, 1, 0},
{&__pyx_n_s_add_or_concatenate, __pyx_k_add_or_concatenate, sizeof(__pyx_k_add_or_concatenate), 0, 0, 1, 1},
{&__pyx_n_s_all_calib_values, __pyx_k_all_calib_values, sizeof(__pyx_k_all_calib_values), 0, 0, 1, 1},
@@ -18296,6 +16361,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{&__pyx_n_s_chann_line, __pyx_k_chann_line, sizeof(__pyx_k_chann_line), 0, 0, 1, 1},
{&__pyx_n_s_chann_lines, __pyx_k_chann_lines, sizeof(__pyx_k_chann_lines), 0, 0, 1, 1},
{&__pyx_n_s_channels, __pyx_k_channels, sizeof(__pyx_k_channels), 0, 0, 1, 1},
+ {&__pyx_n_s_chunk, __pyx_k_chunk, sizeof(__pyx_k_chunk), 0, 0, 1, 1},
{&__pyx_n_s_close, __pyx_k_close, sizeof(__pyx_k_close), 0, 0, 1, 1},
{&__pyx_kp_u_d_d, __pyx_k_d_d, sizeof(__pyx_k_d_d), 0, 1, 0, 0},
{&__pyx_n_s_data, __pyx_k_data, sizeof(__pyx_k_data), 0, 0, 1, 1},
@@ -18310,7 +16376,9 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{&__pyx_n_s_dtype, __pyx_k_dtype, sizeof(__pyx_k_dtype), 0, 0, 1, 1},
{&__pyx_n_s_empty, __pyx_k_empty, sizeof(__pyx_k_empty), 0, 0, 1, 1},
{&__pyx_n_s_encode, __pyx_k_encode, sizeof(__pyx_k_encode), 0, 0, 1, 1},
+ {&__pyx_n_s_enter, __pyx_k_enter, sizeof(__pyx_k_enter), 0, 0, 1, 1},
{&__pyx_n_s_enumerate, __pyx_k_enumerate, sizeof(__pyx_k_enumerate), 0, 0, 1, 1},
+ {&__pyx_n_s_exit, __pyx_k_exit, sizeof(__pyx_k_exit), 0, 0, 1, 1},
{&__pyx_n_s_f, __pyx_k_f, sizeof(__pyx_k_f), 0, 0, 1, 1},
{&__pyx_n_s_file_header, __pyx_k_file_header, sizeof(__pyx_k_file_header), 0, 0, 1, 1},
{&__pyx_n_s_file_header_dict, __pyx_k_file_header_dict, sizeof(__pyx_k_file_header_dict), 0, 0, 1, 1},
@@ -18377,8 +16445,6 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{&__pyx_kp_s_number_and_M_the_order_eg_2_3, __pyx_k_number_and_M_the_order_eg_2_3, sizeof(__pyx_k_number_and_M_the_order_eg_2_3), 0, 0, 1, 0},
{&__pyx_n_s_number_of_mca, __pyx_k_number_of_mca, sizeof(__pyx_k_number_of_mca), 0, 0, 1, 1},
{&__pyx_n_s_numpy, __pyx_k_numpy, sizeof(__pyx_k_numpy), 0, 0, 1, 1},
- {&__pyx_kp_s_numpy_core_multiarray_failed_to, __pyx_k_numpy_core_multiarray_failed_to, sizeof(__pyx_k_numpy_core_multiarray_failed_to), 0, 0, 1, 0},
- {&__pyx_kp_s_numpy_core_umath_failed_to_impor, __pyx_k_numpy_core_umath_failed_to_impor, sizeof(__pyx_k_numpy_core_umath_failed_to_impor), 0, 0, 1, 0},
{&__pyx_n_s_object, __pyx_k_object, sizeof(__pyx_k_object), 0, 0, 1, 1},
{&__pyx_n_s_one_line_calib_values, __pyx_k_one_line_calib_values, sizeof(__pyx_k_one_line_calib_values), 0, 0, 1, 1},
{&__pyx_n_s_one_line_chann_values, __pyx_k_one_line_chann_values, sizeof(__pyx_k_one_line_chann_values), 0, 0, 1, 1},
@@ -18396,7 +16462,9 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{&__pyx_n_s_property, __pyx_k_property, sizeof(__pyx_k_property), 0, 0, 1, 1},
{&__pyx_n_s_qualname, __pyx_k_qualname, sizeof(__pyx_k_qualname), 0, 0, 1, 1},
{&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1},
+ {&__pyx_n_s_rb, __pyx_k_rb, sizeof(__pyx_k_rb), 0, 0, 1, 1},
{&__pyx_n_s_re, __pyx_k_re, sizeof(__pyx_k_re), 0, 0, 1, 1},
+ {&__pyx_n_s_read, __pyx_k_read, sizeof(__pyx_k_read), 0, 0, 1, 1},
{&__pyx_n_s_record, __pyx_k_record, sizeof(__pyx_k_record), 0, 0, 1, 1},
{&__pyx_n_s_record_exists_in_hdr, __pyx_k_record_exists_in_hdr, sizeof(__pyx_k_record_exists_in_hdr), 0, 0, 1, 1},
{&__pyx_n_s_ret, __pyx_k_ret, sizeof(__pyx_k_ret), 0, 0, 1, 1},
@@ -18430,7 +16498,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{&__pyx_n_s_throw, __pyx_k_throw, sizeof(__pyx_k_throw), 0, 0, 1, 1},
{&__pyx_n_s_transpose, __pyx_k_transpose, sizeof(__pyx_k_transpose), 0, 0, 1, 1},
{&__pyx_kp_u_unknown_dtype_code_in_numpy_pxd, __pyx_k_unknown_dtype_code_in_numpy_pxd, sizeof(__pyx_k_unknown_dtype_code_in_numpy_pxd), 0, 1, 0, 0},
- {&__pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_k_users_kieffer_workspace_400_rel, sizeof(__pyx_k_users_kieffer_workspace_400_rel), 0, 0, 1, 0},
+ {&__pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_k_users_knobel_git_silx_silx_io_s, sizeof(__pyx_k_users_knobel_git_silx_silx_io_s), 0, 0, 1, 0},
{&__pyx_n_s_value, __pyx_k_value, sizeof(__pyx_k_value), 0, 0, 1, 1},
{&__pyx_n_s_version, __pyx_k_version, sizeof(__pyx_k_version), 0, 0, 1, 1},
{&__pyx_n_s_version_info, __pyx_k_version_info, sizeof(__pyx_k_version_info), 0, 0, 1, 1},
@@ -18440,21 +16508,21 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{0, 0, 0, 0, 0, 0, 0}
};
static int __Pyx_InitCachedBuiltins(void) {
- __pyx_builtin_MemoryError = __Pyx_GetBuiltinName(__pyx_n_s_MemoryError); if (!__pyx_builtin_MemoryError) __PYX_ERR(0, 151, __pyx_L1_error)
- __pyx_builtin_IOError = __Pyx_GetBuiltinName(__pyx_n_s_IOError); if (!__pyx_builtin_IOError) __PYX_ERR(0, 152, __pyx_L1_error)
- __pyx_builtin_KeyError = __Pyx_GetBuiltinName(__pyx_n_s_KeyError); if (!__pyx_builtin_KeyError) __PYX_ERR(0, 156, __pyx_L1_error)
- __pyx_builtin_IndexError = __Pyx_GetBuiltinName(__pyx_n_s_IndexError); if (!__pyx_builtin_IndexError) __PYX_ERR(0, 157, __pyx_L1_error)
- __pyx_builtin_object = __Pyx_GetBuiltinName(__pyx_n_s_object); if (!__pyx_builtin_object) __PYX_ERR(0, 193, __pyx_L1_error)
- __pyx_builtin_property = __Pyx_GetBuiltinName(__pyx_n_s_property); if (!__pyx_builtin_property) __PYX_ERR(0, 422, __pyx_L1_error)
- __pyx_builtin_map = __Pyx_GetBuiltinName(__pyx_n_s_map); if (!__pyx_builtin_map) __PYX_ERR(0, 258, __pyx_L1_error)
- __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 259, __pyx_L1_error)
- __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 304, __pyx_L1_error)
- __pyx_builtin_open = __Pyx_GetBuiltinName(__pyx_n_s_open); if (!__pyx_builtin_open) __PYX_ERR(0, 633, __pyx_L1_error)
- __pyx_builtin_enumerate = __Pyx_GetBuiltinName(__pyx_n_s_enumerate); if (!__pyx_builtin_enumerate) __PYX_ERR(0, 634, __pyx_L1_error)
- __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 732, __pyx_L1_error)
- __pyx_builtin_AttributeError = __Pyx_GetBuiltinName(__pyx_n_s_AttributeError); if (!__pyx_builtin_AttributeError) __PYX_ERR(0, 736, __pyx_L1_error)
- __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) __PYX_ERR(1, 799, __pyx_L1_error)
- __pyx_builtin_ImportError = __Pyx_GetBuiltinName(__pyx_n_s_ImportError); if (!__pyx_builtin_ImportError) __PYX_ERR(1, 989, __pyx_L1_error)
+ __pyx_builtin_Exception = __Pyx_GetBuiltinName(__pyx_n_s_Exception); if (!__pyx_builtin_Exception) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_MemoryError = __Pyx_GetBuiltinName(__pyx_n_s_MemoryError); if (!__pyx_builtin_MemoryError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_IOError = __Pyx_GetBuiltinName(__pyx_n_s_IOError); if (!__pyx_builtin_IOError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_KeyError = __Pyx_GetBuiltinName(__pyx_n_s_KeyError); if (!__pyx_builtin_KeyError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_IndexError = __Pyx_GetBuiltinName(__pyx_n_s_IndexError); if (!__pyx_builtin_IndexError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_object = __Pyx_GetBuiltinName(__pyx_n_s_object); if (!__pyx_builtin_object) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 193; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_property = __Pyx_GetBuiltinName(__pyx_n_s_property); if (!__pyx_builtin_property) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 422; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_map = __Pyx_GetBuiltinName(__pyx_n_s_map); if (!__pyx_builtin_map) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 258; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 259; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 304; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_open = __Pyx_GetBuiltinName(__pyx_n_s_open); if (!__pyx_builtin_open) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_enumerate = __Pyx_GetBuiltinName(__pyx_n_s_enumerate); if (!__pyx_builtin_enumerate) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 736; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_AttributeError = __Pyx_GetBuiltinName(__pyx_n_s_AttributeError); if (!__pyx_builtin_AttributeError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 740; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_builtin_RuntimeError = __Pyx_GetBuiltinName(__pyx_n_s_RuntimeError); if (!__pyx_builtin_RuntimeError) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 799; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
return 0;
__pyx_L1_error:;
return -1;
@@ -18471,7 +16539,7 @@ static int __Pyx_InitCachedConstants(void) {
* all_chann_values = [chann_line.split() for chann_line in chann_lines]
* for one_line_chann_values in all_chann_values:
*/
- __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_s_); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 255, __pyx_L1_error)
+ __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_s_); if (unlikely(!__pyx_tuple__2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 255; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__2);
__Pyx_GIVEREF(__pyx_tuple__2);
@@ -18482,7 +16550,7 @@ static int __Pyx_InitCachedConstants(void) {
* all_calib_values = [calib_line.split() for calib_line in calib_lines]
* for one_line_calib_values in all_calib_values:
*/
- __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 270, __pyx_L1_error)
+ __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_); if (unlikely(!__pyx_tuple__3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__3);
__Pyx_GIVEREF(__pyx_tuple__3);
@@ -18493,7 +16561,7 @@ static int __Pyx_InitCachedConstants(void) {
*
* if isinstance(key, (int, long)):
*/
- __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_No_MCA_spectrum_found_in_this_sc); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(0, 296, __pyx_L1_error)
+ __pyx_tuple__4 = PyTuple_Pack(1, __pyx_kp_s_No_MCA_spectrum_found_in_this_sc); if (unlikely(!__pyx_tuple__4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 296; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__4);
__Pyx_GIVEREF(__pyx_tuple__4);
@@ -18504,7 +16572,7 @@ static int __Pyx_InitCachedConstants(void) {
*
*
*/
- __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_s_Parameter_value_must_be_a_string); if (unlikely(!__pyx_tuple__5)) __PYX_ERR(0, 334, __pyx_L1_error)
+ __pyx_tuple__5 = PyTuple_Pack(1, __pyx_kp_s_Parameter_value_must_be_a_string); if (unlikely(!__pyx_tuple__5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 334; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__5);
__Pyx_GIVEREF(__pyx_tuple__5);
@@ -18515,10 +16583,10 @@ static int __Pyx_InitCachedConstants(void) {
* hvalue = match.group(2).strip()
* _add_or_concatenate(self._scan_header_dict, hkey, hvalue)
*/
- __pyx_tuple__6 = PyTuple_Pack(1, __pyx_int_1); if (unlikely(!__pyx_tuple__6)) __PYX_ERR(0, 382, __pyx_L1_error)
+ __pyx_tuple__6 = PyTuple_Pack(1, __pyx_int_1); if (unlikely(!__pyx_tuple__6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 382; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__6);
__Pyx_GIVEREF(__pyx_tuple__6);
- __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s__7); if (unlikely(!__pyx_tuple__8)) __PYX_ERR(0, 382, __pyx_L1_error)
+ __pyx_tuple__8 = PyTuple_Pack(1, __pyx_kp_s__7); if (unlikely(!__pyx_tuple__8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 382; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__8);
__Pyx_GIVEREF(__pyx_tuple__8);
@@ -18529,7 +16597,7 @@ static int __Pyx_InitCachedConstants(void) {
* _add_or_concatenate(self._scan_header_dict, hkey, hvalue)
* elif match_mca:
*/
- __pyx_tuple__9 = PyTuple_Pack(1, __pyx_int_2); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(0, 383, __pyx_L1_error)
+ __pyx_tuple__9 = PyTuple_Pack(1, __pyx_int_2); if (unlikely(!__pyx_tuple__9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 383; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__9);
__Pyx_GIVEREF(__pyx_tuple__9);
@@ -18540,10 +16608,10 @@ static int __Pyx_InitCachedConstants(void) {
* hvalue = match_mca.group(2).strip()
* _add_or_concatenate(self._mca_header_dict, hkey, hvalue)
*/
- __pyx_tuple__10 = PyTuple_Pack(1, __pyx_int_1); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(0, 386, __pyx_L1_error)
+ __pyx_tuple__10 = PyTuple_Pack(1, __pyx_int_1); if (unlikely(!__pyx_tuple__10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 386; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__10);
__Pyx_GIVEREF(__pyx_tuple__10);
- __pyx_tuple__11 = PyTuple_Pack(1, __pyx_kp_s__7); if (unlikely(!__pyx_tuple__11)) __PYX_ERR(0, 386, __pyx_L1_error)
+ __pyx_tuple__11 = PyTuple_Pack(1, __pyx_kp_s__7); if (unlikely(!__pyx_tuple__11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 386; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__11);
__Pyx_GIVEREF(__pyx_tuple__11);
@@ -18554,7 +16622,7 @@ static int __Pyx_InitCachedConstants(void) {
* _add_or_concatenate(self._mca_header_dict, hkey, hvalue)
* else:
*/
- __pyx_tuple__12 = PyTuple_Pack(1, __pyx_int_2); if (unlikely(!__pyx_tuple__12)) __PYX_ERR(0, 387, __pyx_L1_error)
+ __pyx_tuple__12 = PyTuple_Pack(1, __pyx_int_2); if (unlikely(!__pyx_tuple__12)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 387; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__12);
__Pyx_GIVEREF(__pyx_tuple__12);
@@ -18565,7 +16633,7 @@ static int __Pyx_InitCachedConstants(void) {
* try:
* self._labels = self._specfile.labels(self._index)
*/
- __pyx_tuple__13 = PyTuple_Pack(1, __pyx_n_s_L); if (unlikely(!__pyx_tuple__13)) __PYX_ERR(0, 394, __pyx_L1_error)
+ __pyx_tuple__13 = PyTuple_Pack(1, __pyx_n_s_L); if (unlikely(!__pyx_tuple__13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 394; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__13);
__Pyx_GIVEREF(__pyx_tuple__13);
@@ -18576,7 +16644,7 @@ static int __Pyx_InitCachedConstants(void) {
*
* self._file_header_dict = {}
*/
- __pyx_tuple__15 = PyTuple_Pack(1, __pyx_kp_s__14); if (unlikely(!__pyx_tuple__15)) __PYX_ERR(0, 402, __pyx_L1_error)
+ __pyx_tuple__15 = PyTuple_Pack(1, __pyx_kp_s__14); if (unlikely(!__pyx_tuple__15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 402; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__15);
__Pyx_GIVEREF(__pyx_tuple__15);
@@ -18587,10 +16655,10 @@ static int __Pyx_InitCachedConstants(void) {
* hvalue = match.group(2).strip()
* _add_or_concatenate(self._file_header_dict, hkey, hvalue)
*/
- __pyx_tuple__16 = PyTuple_Pack(1, __pyx_int_1); if (unlikely(!__pyx_tuple__16)) __PYX_ERR(0, 409, __pyx_L1_error)
+ __pyx_tuple__16 = PyTuple_Pack(1, __pyx_int_1); if (unlikely(!__pyx_tuple__16)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__16);
__Pyx_GIVEREF(__pyx_tuple__16);
- __pyx_tuple__17 = PyTuple_Pack(1, __pyx_kp_s__7); if (unlikely(!__pyx_tuple__17)) __PYX_ERR(0, 409, __pyx_L1_error)
+ __pyx_tuple__17 = PyTuple_Pack(1, __pyx_kp_s__7); if (unlikely(!__pyx_tuple__17)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 409; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__17);
__Pyx_GIVEREF(__pyx_tuple__17);
@@ -18601,7 +16669,7 @@ static int __Pyx_InitCachedConstants(void) {
* _add_or_concatenate(self._file_header_dict, hkey, hvalue)
* else:
*/
- __pyx_tuple__18 = PyTuple_Pack(1, __pyx_int_2); if (unlikely(!__pyx_tuple__18)) __PYX_ERR(0, 410, __pyx_L1_error)
+ __pyx_tuple__18 = PyTuple_Pack(1, __pyx_int_2); if (unlikely(!__pyx_tuple__18)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 410; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__18);
__Pyx_GIVEREF(__pyx_tuple__18);
@@ -18612,7 +16680,7 @@ static int __Pyx_InitCachedConstants(void) {
*
* def data_column_by_name(self, label):
*/
- __pyx_slice__19 = PySlice_New(Py_None, Py_None, Py_None); if (unlikely(!__pyx_slice__19)) __PYX_ERR(0, 581, __pyx_L1_error)
+ __pyx_slice__19 = PySlice_New(Py_None, Py_None, Py_None); if (unlikely(!__pyx_slice__19)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 581; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_slice__19);
__Pyx_GIVEREF(__pyx_slice__19);
@@ -18623,7 +16691,7 @@ static int __Pyx_InitCachedConstants(void) {
* return ret
*
*/
- __pyx_tuple__20 = PyTuple_Pack(1, __pyx_int_0); if (unlikely(!__pyx_tuple__20)) __PYX_ERR(0, 599, __pyx_L1_error)
+ __pyx_tuple__20 = PyTuple_Pack(1, __pyx_int_0); if (unlikely(!__pyx_tuple__20)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 599; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__20);
__Pyx_GIVEREF(__pyx_tuple__20);
@@ -18634,153 +16702,155 @@ static int __Pyx_InitCachedConstants(void) {
* return bytes(string_, "ascii")
* return string_
*/
- __pyx_tuple__21 = PyTuple_Pack(1, __pyx_kp_s_3); if (unlikely(!__pyx_tuple__21)) __PYX_ERR(0, 617, __pyx_L1_error)
+ __pyx_tuple__21 = PyTuple_Pack(1, __pyx_kp_s_3); if (unlikely(!__pyx_tuple__21)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 617; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__21);
__Pyx_GIVEREF(__pyx_tuple__21);
- /* "silx/io/specfile.pyx":635
- * f = open(filename)
- * for i, line in enumerate(f):
- * if line.startswith("#S ") or line.startswith("#F "): # <<<<<<<<<<<<<<
- * f.close()
- * return True
+ /* "silx/io/specfile.pyx":634
+ * # test for presence of #S or #F in first 10 lines
+ * with open(filename, "rb") as f:
+ * chunk = f.read(2500) # <<<<<<<<<<<<<<
+ * for i, line in enumerate(chunk.split(b"\n")):
+ * if line.startswith(b"#S ") or line.startswith(b"#F "):
*/
- __pyx_tuple__22 = PyTuple_Pack(1, __pyx_kp_s_S); if (unlikely(!__pyx_tuple__22)) __PYX_ERR(0, 635, __pyx_L1_error)
+ __pyx_tuple__22 = PyTuple_Pack(1, __pyx_int_2500); if (unlikely(!__pyx_tuple__22)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 634; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__22);
__Pyx_GIVEREF(__pyx_tuple__22);
- __pyx_tuple__23 = PyTuple_Pack(1, __pyx_kp_s_F); if (unlikely(!__pyx_tuple__23)) __PYX_ERR(0, 635, __pyx_L1_error)
+
+ /* "silx/io/specfile.pyx":633
+ * return False
+ * # test for presence of #S or #F in first 10 lines
+ * with open(filename, "rb") as f: # <<<<<<<<<<<<<<
+ * chunk = f.read(2500)
+ * for i, line in enumerate(chunk.split(b"\n")):
+ */
+ __pyx_tuple__23 = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_tuple__23)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 633; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_tuple__23);
__Pyx_GIVEREF(__pyx_tuple__23);
- /* "silx/io/specfile.pyx":687
+ /* "silx/io/specfile.pyx":635
+ * with open(filename, "rb") as f:
+ * chunk = f.read(2500)
+ * for i, line in enumerate(chunk.split(b"\n")): # <<<<<<<<<<<<<<
+ * if line.startswith(b"#S ") or line.startswith(b"#F "):
+ * return True
+ */
+ __pyx_tuple__24 = PyTuple_Pack(1, __pyx_kp_b_); if (unlikely(!__pyx_tuple__24)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 635; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__24);
+ __Pyx_GIVEREF(__pyx_tuple__24);
+
+ /* "silx/io/specfile.pyx":636
+ * chunk = f.read(2500)
+ * for i, line in enumerate(chunk.split(b"\n")):
+ * if line.startswith(b"#S ") or line.startswith(b"#F "): # <<<<<<<<<<<<<<
+ * return True
+ * if i >= 10:
+ */
+ __pyx_tuple__25 = PyTuple_Pack(1, __pyx_kp_b_S); if (unlikely(!__pyx_tuple__25)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 636; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__25);
+ __Pyx_GIVEREF(__pyx_tuple__25);
+ __pyx_tuple__26 = PyTuple_Pack(1, __pyx_kp_b_F); if (unlikely(!__pyx_tuple__26)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 636; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__26);
+ __Pyx_GIVEREF(__pyx_tuple__26);
+
+ /* "silx/io/specfile.pyx":690
* if self.handle:
* if specfile_wrapper.SfClose(self.handle):
* _logger.warning("Error while closing SpecFile") # <<<<<<<<<<<<<<
+ * self.handle = NULL
*
- * def __len__(self):
*/
- __pyx_tuple__24 = PyTuple_Pack(1, __pyx_kp_s_Error_while_closing_SpecFile); if (unlikely(!__pyx_tuple__24)) __PYX_ERR(0, 687, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__24);
- __Pyx_GIVEREF(__pyx_tuple__24);
+ __pyx_tuple__27 = PyTuple_Pack(1, __pyx_kp_s_Error_while_closing_SpecFile); if (unlikely(!__pyx_tuple__27)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 690; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__27);
+ __Pyx_GIVEREF(__pyx_tuple__27);
- /* "silx/io/specfile.pyx":730
+ /* "silx/io/specfile.pyx":734
* else:
* try:
* (number, order) = map(int, key.split(".")) # <<<<<<<<<<<<<<
* scan_index = self.index(number, order)
* except (ValueError, SfErrScanNotFound, KeyError):
*/
- __pyx_tuple__26 = PyTuple_Pack(1, __pyx_kp_s__25); if (unlikely(!__pyx_tuple__26)) __PYX_ERR(0, 730, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__26);
- __Pyx_GIVEREF(__pyx_tuple__26);
+ __pyx_tuple__29 = PyTuple_Pack(1, __pyx_kp_s__28); if (unlikely(!__pyx_tuple__29)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 734; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__29);
+ __Pyx_GIVEREF(__pyx_tuple__29);
- /* "silx/io/specfile.pyx":1230
+ /* "silx/io/specfile.pyx":1234
* # error code updating isn't implemented in SfMcaCalib
* if mca_calib_error:
* raise KeyError("MCA calibration line (@CALIB) not found") # <<<<<<<<<<<<<<
*
* mca_calib_list = []
*/
- __pyx_tuple__29 = PyTuple_Pack(1, __pyx_kp_s_MCA_calibration_line_CALIB_not_f); if (unlikely(!__pyx_tuple__29)) __PYX_ERR(0, 1230, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__29);
- __Pyx_GIVEREF(__pyx_tuple__29);
+ __pyx_tuple__33 = PyTuple_Pack(1, __pyx_kp_s_MCA_calibration_line_CALIB_not_f); if (unlikely(!__pyx_tuple__33)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1234; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__33);
+ __Pyx_GIVEREF(__pyx_tuple__33);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":218
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":215
* if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS)
* and not PyArray_CHKFLAGS(self, NPY_C_CONTIGUOUS)):
* raise ValueError(u"ndarray is not C contiguous") # <<<<<<<<<<<<<<
*
* if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS)
*/
- __pyx_tuple__30 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__30)) __PYX_ERR(1, 218, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__30);
- __Pyx_GIVEREF(__pyx_tuple__30);
+ __pyx_tuple__34 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_C_contiguous); if (unlikely(!__pyx_tuple__34)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 215; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__34);
+ __Pyx_GIVEREF(__pyx_tuple__34);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":222
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":219
* if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS)
* and not PyArray_CHKFLAGS(self, NPY_F_CONTIGUOUS)):
* raise ValueError(u"ndarray is not Fortran contiguous") # <<<<<<<<<<<<<<
*
* info.buf = PyArray_DATA(self)
*/
- __pyx_tuple__31 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__31)) __PYX_ERR(1, 222, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__31);
- __Pyx_GIVEREF(__pyx_tuple__31);
+ __pyx_tuple__35 = PyTuple_Pack(1, __pyx_kp_u_ndarray_is_not_Fortran_contiguou); if (unlikely(!__pyx_tuple__35)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__35);
+ __Pyx_GIVEREF(__pyx_tuple__35);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":259
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":257
* if ((descr.byteorder == c'>' and little_endian) or
* (descr.byteorder == c'<' and not little_endian)):
* raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<<
* if t == NPY_BYTE: f = "b"
* elif t == NPY_UBYTE: f = "B"
*/
- __pyx_tuple__32 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__32)) __PYX_ERR(1, 259, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__32);
- __Pyx_GIVEREF(__pyx_tuple__32);
+ __pyx_tuple__36 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__36)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 257; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__36);
+ __Pyx_GIVEREF(__pyx_tuple__36);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":799
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":799
*
* if (end - f) - <int>(new_offset - offset[0]) < 15:
* raise RuntimeError(u"Format string allocated too short, see comment in numpy.pxd") # <<<<<<<<<<<<<<
*
* if ((child.byteorder == c'>' and little_endian) or
*/
- __pyx_tuple__33 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__33)) __PYX_ERR(1, 799, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__33);
- __Pyx_GIVEREF(__pyx_tuple__33);
+ __pyx_tuple__37 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor); if (unlikely(!__pyx_tuple__37)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 799; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__37);
+ __Pyx_GIVEREF(__pyx_tuple__37);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":803
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":803
* if ((child.byteorder == c'>' and little_endian) or
* (child.byteorder == c'<' and not little_endian)):
* raise ValueError(u"Non-native byte order not supported") # <<<<<<<<<<<<<<
* # One could encode it in the format string and have Cython
* # complain instead, BUT: < and > in format strings also imply
*/
- __pyx_tuple__34 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__34)) __PYX_ERR(1, 803, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__34);
- __Pyx_GIVEREF(__pyx_tuple__34);
+ __pyx_tuple__38 = PyTuple_Pack(1, __pyx_kp_u_Non_native_byte_order_not_suppor); if (unlikely(!__pyx_tuple__38)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 803; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__38);
+ __Pyx_GIVEREF(__pyx_tuple__38);
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":823
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":823
* t = child.type_num
* if end - f < 5:
* raise RuntimeError(u"Format string allocated too short.") # <<<<<<<<<<<<<<
*
* # Until ticket #99 is fixed, use integers to avoid warnings
*/
- __pyx_tuple__35 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__35)) __PYX_ERR(1, 823, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__35);
- __Pyx_GIVEREF(__pyx_tuple__35);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":989
- * _import_array()
- * except Exception:
- * raise ImportError("numpy.core.multiarray failed to import") # <<<<<<<<<<<<<<
- *
- * cdef inline int import_umath() except -1:
- */
- __pyx_tuple__36 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_multiarray_failed_to); if (unlikely(!__pyx_tuple__36)) __PYX_ERR(1, 989, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__36);
- __Pyx_GIVEREF(__pyx_tuple__36);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":995
- * _import_umath()
- * except Exception:
- * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<<
- *
- * cdef inline int import_ufunc() except -1:
- */
- __pyx_tuple__37 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__37)) __PYX_ERR(1, 995, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__37);
- __Pyx_GIVEREF(__pyx_tuple__37);
-
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":1001
- * _import_umath()
- * except Exception:
- * raise ImportError("numpy.core.umath failed to import") # <<<<<<<<<<<<<<
- */
- __pyx_tuple__38 = PyTuple_Pack(1, __pyx_kp_s_numpy_core_umath_failed_to_impor); if (unlikely(!__pyx_tuple__38)) __PYX_ERR(1, 1001, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__38);
- __Pyx_GIVEREF(__pyx_tuple__38);
+ __pyx_tuple__39 = PyTuple_Pack(1, __pyx_kp_u_Format_string_allocated_too_shor_2); if (unlikely(!__pyx_tuple__39)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 823; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__39);
+ __Pyx_GIVEREF(__pyx_tuple__39);
/* "silx/io/specfile.pyx":233
*
@@ -18789,10 +16859,10 @@ static int __Pyx_InitCachedConstants(void) {
* self._scan = scan
*
*/
- __pyx_tuple__39 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_scan); if (unlikely(!__pyx_tuple__39)) __PYX_ERR(0, 233, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__39);
- __Pyx_GIVEREF(__pyx_tuple__39);
- __pyx_codeobj__40 = (PyObject*)__Pyx_PyCode_New(2, 0, 2, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__39, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_init, 233, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__40)) __PYX_ERR(0, 233, __pyx_L1_error)
+ __pyx_tuple__40 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_scan); if (unlikely(!__pyx_tuple__40)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__40);
+ __Pyx_GIVEREF(__pyx_tuple__40);
+ __pyx_codeobj__41 = (PyObject*)__Pyx_PyCode_New(2, 0, 2, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__40, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_init, 233, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__41)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":251
* self._parse_channels()
@@ -18801,10 +16871,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Fill :attr:`channels`"""
* # Channels list
*/
- __pyx_tuple__41 = PyTuple_Pack(9, __pyx_n_s_self, __pyx_n_s_chann_lines, __pyx_n_s_all_chann_values, __pyx_n_s_one_line_chann_values, __pyx_n_s_length, __pyx_n_s_start, __pyx_n_s_stop, __pyx_n_s_increment, __pyx_n_s_chann_line); if (unlikely(!__pyx_tuple__41)) __PYX_ERR(0, 251, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__41);
- __Pyx_GIVEREF(__pyx_tuple__41);
- __pyx_codeobj__42 = (PyObject*)__Pyx_PyCode_New(1, 0, 9, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__41, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_parse_channels, 251, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__42)) __PYX_ERR(0, 251, __pyx_L1_error)
+ __pyx_tuple__42 = PyTuple_Pack(9, __pyx_n_s_self, __pyx_n_s_chann_lines, __pyx_n_s_all_chann_values, __pyx_n_s_one_line_chann_values, __pyx_n_s_length, __pyx_n_s_start, __pyx_n_s_stop, __pyx_n_s_increment, __pyx_n_s_chann_line); if (unlikely(!__pyx_tuple__42)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 251; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__42);
+ __Pyx_GIVEREF(__pyx_tuple__42);
+ __pyx_codeobj__43 = (PyObject*)__Pyx_PyCode_New(1, 0, 9, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__42, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_parse_channels, 251, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__43)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 251; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":266
* self.channels.append(list(range(start, stop + 1, increment)))
@@ -18813,10 +16883,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Fill :attr:`calibration`"""
* # Channels list
*/
- __pyx_tuple__43 = PyTuple_Pack(5, __pyx_n_s_self, __pyx_n_s_calib_lines, __pyx_n_s_all_calib_values, __pyx_n_s_one_line_calib_values, __pyx_n_s_calib_line); if (unlikely(!__pyx_tuple__43)) __PYX_ERR(0, 266, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__43);
- __Pyx_GIVEREF(__pyx_tuple__43);
- __pyx_codeobj__44 = (PyObject*)__Pyx_PyCode_New(1, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__43, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_parse_calibration, 266, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__44)) __PYX_ERR(0, 266, __pyx_L1_error)
+ __pyx_tuple__44 = PyTuple_Pack(5, __pyx_n_s_self, __pyx_n_s_calib_lines, __pyx_n_s_all_calib_values, __pyx_n_s_one_line_calib_values, __pyx_n_s_calib_line); if (unlikely(!__pyx_tuple__44)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__44);
+ __Pyx_GIVEREF(__pyx_tuple__44);
+ __pyx_codeobj__45 = (PyObject*)__Pyx_PyCode_New(1, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__44, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_parse_calibration, 266, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__45)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":278
* self.calibration.append([0., 1., 0.])
@@ -18825,10 +16895,10 @@ static int __Pyx_InitCachedConstants(void) {
* """
*
*/
- __pyx_tuple__45 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__45)) __PYX_ERR(0, 278, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__45);
- __Pyx_GIVEREF(__pyx_tuple__45);
- __pyx_codeobj__46 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__45, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_len, 278, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__46)) __PYX_ERR(0, 278, __pyx_L1_error)
+ __pyx_tuple__46 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__46)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 278; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__46);
+ __Pyx_GIVEREF(__pyx_tuple__46);
+ __pyx_codeobj__47 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__46, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_len, 278, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__47)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 278; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":286
* return self._scan._specfile.number_of_mca(self._scan.index)
@@ -18837,10 +16907,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Return a single MCA data line
*
*/
- __pyx_tuple__47 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_key, __pyx_n_s_mca_index, __pyx_n_s_msg); if (unlikely(!__pyx_tuple__47)) __PYX_ERR(0, 286, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__47);
- __Pyx_GIVEREF(__pyx_tuple__47);
- __pyx_codeobj__48 = (PyObject*)__Pyx_PyCode_New(2, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__47, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_getitem, 286, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__48)) __PYX_ERR(0, 286, __pyx_L1_error)
+ __pyx_tuple__48 = PyTuple_Pack(4, __pyx_n_s_self, __pyx_n_s_key, __pyx_n_s_mca_index, __pyx_n_s_msg); if (unlikely(!__pyx_tuple__48)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__48);
+ __Pyx_GIVEREF(__pyx_tuple__48);
+ __pyx_codeobj__49 = (PyObject*)__Pyx_PyCode_New(2, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__48, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_getitem, 286, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__49)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":314
* mca_index)
@@ -18849,10 +16919,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Return the next MCA data line each time this method is called.
*
*/
- __pyx_tuple__49 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_mca_index); if (unlikely(!__pyx_tuple__49)) __PYX_ERR(0, 314, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__49);
- __Pyx_GIVEREF(__pyx_tuple__49);
- __pyx_codeobj__50 = (PyObject*)__Pyx_PyCode_New(1, 0, 2, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__49, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_iter, 314, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__50)) __PYX_ERR(0, 314, __pyx_L1_error)
+ __pyx_tuple__50 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_mca_index); if (unlikely(!__pyx_tuple__50)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 314; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__50);
+ __Pyx_GIVEREF(__pyx_tuple__50);
+ __pyx_codeobj__51 = (PyObject*)__Pyx_PyCode_New(1, 0, 2, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__50, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_iter, 314, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__51)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 314; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":324
*
@@ -18861,10 +16931,10 @@ static int __Pyx_InitCachedConstants(void) {
* """If key doesn't exist in dictionary, create a new ``key: value`` pair.
* Else append/concatenate the new value to the existing one
*/
- __pyx_tuple__51 = PyTuple_Pack(3, __pyx_n_s_dictionary, __pyx_n_s_key, __pyx_n_s_value); if (unlikely(!__pyx_tuple__51)) __PYX_ERR(0, 324, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__51);
- __Pyx_GIVEREF(__pyx_tuple__51);
- __pyx_codeobj__52 = (PyObject*)__Pyx_PyCode_New(3, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__51, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_add_or_concatenate, 324, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__52)) __PYX_ERR(0, 324, __pyx_L1_error)
+ __pyx_tuple__52 = PyTuple_Pack(3, __pyx_n_s_dictionary, __pyx_n_s_key, __pyx_n_s_value); if (unlikely(!__pyx_tuple__52)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 324; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__52);
+ __Pyx_GIVEREF(__pyx_tuple__52);
+ __pyx_codeobj__53 = (PyObject*)__Pyx_PyCode_New(3, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__52, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_add_or_concatenate, 324, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__53)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 324; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":362
* scan2 = sf["3.1"]
@@ -18873,10 +16943,10 @@ static int __Pyx_InitCachedConstants(void) {
* self._specfile = specfile
*
*/
- __pyx_tuple__53 = PyTuple_Pack(9, __pyx_n_s_self, __pyx_n_s_specfile_2, __pyx_n_s_scan_index, __pyx_n_s_line, __pyx_n_s_match, __pyx_n_s_match_mca, __pyx_n_s_hkey, __pyx_n_s_hvalue, __pyx_n_s_L_header); if (unlikely(!__pyx_tuple__53)) __PYX_ERR(0, 362, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__53);
- __Pyx_GIVEREF(__pyx_tuple__53);
- __pyx_codeobj__54 = (PyObject*)__Pyx_PyCode_New(3, 0, 9, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__53, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_init, 362, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__54)) __PYX_ERR(0, 362, __pyx_L1_error)
+ __pyx_tuple__54 = PyTuple_Pack(9, __pyx_n_s_self, __pyx_n_s_specfile_2, __pyx_n_s_scan_index, __pyx_n_s_line, __pyx_n_s_match, __pyx_n_s_match_mca, __pyx_n_s_hkey, __pyx_n_s_hvalue, __pyx_n_s_L_header); if (unlikely(!__pyx_tuple__54)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 362; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__54);
+ __Pyx_GIVEREF(__pyx_tuple__54);
+ __pyx_codeobj__55 = (PyObject*)__Pyx_PyCode_New(3, 0, 9, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__54, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_init, 362, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__55)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 362; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":423
* @cython.embedsignature(False)
@@ -18885,10 +16955,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Unique scan index 0 - len(specfile)-1
*
*/
- __pyx_tuple__55 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__55)) __PYX_ERR(0, 423, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__55);
- __Pyx_GIVEREF(__pyx_tuple__55);
- __pyx_codeobj__56 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__55, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_index, 423, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__56)) __PYX_ERR(0, 423, __pyx_L1_error)
+ __pyx_tuple__56 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__56)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 423; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__56);
+ __Pyx_GIVEREF(__pyx_tuple__56);
+ __pyx_codeobj__57 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__56, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_index, 423, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__57)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 423; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":433
* @cython.embedsignature(False)
@@ -18897,10 +16967,10 @@ static int __Pyx_InitCachedConstants(void) {
* """First value on #S line (as int)"""
* return self._number
*/
- __pyx_tuple__57 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__57)) __PYX_ERR(0, 433, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__57);
- __Pyx_GIVEREF(__pyx_tuple__57);
- __pyx_codeobj__58 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__57, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_number, 433, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__58)) __PYX_ERR(0, 433, __pyx_L1_error)
+ __pyx_tuple__58 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__58)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 433; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__58);
+ __Pyx_GIVEREF(__pyx_tuple__58);
+ __pyx_codeobj__59 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__58, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_number, 433, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__59)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 433; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":439
* @cython.embedsignature(False)
@@ -18909,10 +16979,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Order can be > 1 if the same number is repeated in a specfile"""
* return self._order
*/
- __pyx_tuple__59 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__59)) __PYX_ERR(0, 439, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__59);
- __Pyx_GIVEREF(__pyx_tuple__59);
- __pyx_codeobj__60 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__59, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_order, 439, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__60)) __PYX_ERR(0, 439, __pyx_L1_error)
+ __pyx_tuple__60 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__60)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__60);
+ __Pyx_GIVEREF(__pyx_tuple__60);
+ __pyx_codeobj__61 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__60, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_order, 439, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__61)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":445
* @cython.embedsignature(False)
@@ -18921,10 +16991,10 @@ static int __Pyx_InitCachedConstants(void) {
* """List of raw header lines (as a list of strings).
*
*/
- __pyx_tuple__61 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__61)) __PYX_ERR(0, 445, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__61);
- __Pyx_GIVEREF(__pyx_tuple__61);
- __pyx_codeobj__62 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__61, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_header_2, 445, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__62)) __PYX_ERR(0, 445, __pyx_L1_error)
+ __pyx_tuple__62 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__62)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 445; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__62);
+ __Pyx_GIVEREF(__pyx_tuple__62);
+ __pyx_codeobj__63 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__62, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_header_2, 445, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__63)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 445; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":455
* @cython.embedsignature(False)
@@ -18933,10 +17003,10 @@ static int __Pyx_InitCachedConstants(void) {
* """List of raw scan header lines (as a list of strings).
* """
*/
- __pyx_tuple__63 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__63)) __PYX_ERR(0, 455, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__63);
- __Pyx_GIVEREF(__pyx_tuple__63);
- __pyx_codeobj__64 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__63, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_scan_header, 455, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__64)) __PYX_ERR(0, 455, __pyx_L1_error)
+ __pyx_tuple__64 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__64)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 455; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__64);
+ __Pyx_GIVEREF(__pyx_tuple__64);
+ __pyx_codeobj__65 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__64, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_scan_header, 455, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__65)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 455; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":462
* @cython.embedsignature(False)
@@ -18945,10 +17015,10 @@ static int __Pyx_InitCachedConstants(void) {
* """List of raw file header lines (as a list of strings).
* """
*/
- __pyx_tuple__65 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__65)) __PYX_ERR(0, 462, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__65);
- __Pyx_GIVEREF(__pyx_tuple__65);
- __pyx_codeobj__66 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__65, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_file_header, 462, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__66)) __PYX_ERR(0, 462, __pyx_L1_error)
+ __pyx_tuple__66 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__66)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 462; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__66);
+ __Pyx_GIVEREF(__pyx_tuple__66);
+ __pyx_codeobj__67 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__66, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_file_header, 462, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__67)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 462; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":469
* @cython.embedsignature(False)
@@ -18957,10 +17027,10 @@ static int __Pyx_InitCachedConstants(void) {
* """
* Dictionary of scan header strings, keys without the leading``#``
*/
- __pyx_tuple__67 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__67)) __PYX_ERR(0, 469, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__67);
- __Pyx_GIVEREF(__pyx_tuple__67);
- __pyx_codeobj__68 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__67, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_scan_header_dict_2, 469, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__68)) __PYX_ERR(0, 469, __pyx_L1_error)
+ __pyx_tuple__68 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__68)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 469; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__68);
+ __Pyx_GIVEREF(__pyx_tuple__68);
+ __pyx_codeobj__69 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__68, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_scan_header_dict_2, 469, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__69)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 469; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":479
* @cython.embedsignature(False)
@@ -18969,10 +17039,10 @@ static int __Pyx_InitCachedConstants(void) {
* """
* Dictionary of MCA header strings, keys without the leading ``#@``
*/
- __pyx_tuple__69 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__69)) __PYX_ERR(0, 479, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__69);
- __Pyx_GIVEREF(__pyx_tuple__69);
- __pyx_codeobj__70 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__69, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_mca_header_dict, 479, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__70)) __PYX_ERR(0, 479, __pyx_L1_error)
+ __pyx_tuple__70 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__70)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 479; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__70);
+ __Pyx_GIVEREF(__pyx_tuple__70);
+ __pyx_codeobj__71 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__70, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_mca_header_dict, 479, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__71)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 479; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":488
* @cython.embedsignature(False)
@@ -18981,10 +17051,10 @@ static int __Pyx_InitCachedConstants(void) {
* """
* Dictionary of file header strings, keys without the leading ``#``
*/
- __pyx_tuple__71 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__71)) __PYX_ERR(0, 488, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__71);
- __Pyx_GIVEREF(__pyx_tuple__71);
- __pyx_codeobj__72 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__71, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_file_header_dict_2, 488, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__72)) __PYX_ERR(0, 488, __pyx_L1_error)
+ __pyx_tuple__72 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__72)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 488; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__72);
+ __Pyx_GIVEREF(__pyx_tuple__72);
+ __pyx_codeobj__73 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__72, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_file_header_dict_2, 488, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__73)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 488; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":497
* @cython.embedsignature(False)
@@ -18993,10 +17063,10 @@ static int __Pyx_InitCachedConstants(void) {
* """
* List of data column headers from ``#L`` scan header
*/
- __pyx_tuple__73 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__73)) __PYX_ERR(0, 497, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__73);
- __Pyx_GIVEREF(__pyx_tuple__73);
- __pyx_codeobj__74 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__73, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_labels_2, 497, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__74)) __PYX_ERR(0, 497, __pyx_L1_error)
+ __pyx_tuple__74 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__74)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 497; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__74);
+ __Pyx_GIVEREF(__pyx_tuple__74);
+ __pyx_codeobj__75 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__74, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_labels_2, 497, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__75)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 497; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":505
* @cython.embedsignature(False)
@@ -19005,10 +17075,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Scan data as a 2D numpy.ndarray with the usual attributes
* (e.g. data.shape).
*/
- __pyx_tuple__75 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__75)) __PYX_ERR(0, 505, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__75);
- __Pyx_GIVEREF(__pyx_tuple__75);
- __pyx_codeobj__76 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__75, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_data_2, 505, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__76)) __PYX_ERR(0, 505, __pyx_L1_error)
+ __pyx_tuple__76 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__76)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 505; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__76);
+ __Pyx_GIVEREF(__pyx_tuple__76);
+ __pyx_codeobj__77 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__76, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_data_2, 505, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__77)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 505; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":518
* @cython.embedsignature(False)
@@ -19017,10 +17087,10 @@ static int __Pyx_InitCachedConstants(void) {
* """MCA data in this scan.
*
*/
- __pyx_tuple__77 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__77)) __PYX_ERR(0, 518, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__77);
- __Pyx_GIVEREF(__pyx_tuple__77);
- __pyx_codeobj__78 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__77, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_mca_2, 518, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__78)) __PYX_ERR(0, 518, __pyx_L1_error)
+ __pyx_tuple__78 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__78)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 518; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__78);
+ __Pyx_GIVEREF(__pyx_tuple__78);
+ __pyx_codeobj__79 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__78, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_mca_2, 518, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__79)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 518; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":532
* @cython.embedsignature(False)
@@ -19029,10 +17099,10 @@ static int __Pyx_InitCachedConstants(void) {
* """List of motor names from the ``#O`` file header line.
* """
*/
- __pyx_tuple__79 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__79)) __PYX_ERR(0, 532, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__79);
- __Pyx_GIVEREF(__pyx_tuple__79);
- __pyx_codeobj__80 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__79, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_motor_names, 532, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__80)) __PYX_ERR(0, 532, __pyx_L1_error)
+ __pyx_tuple__80 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__80)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__80);
+ __Pyx_GIVEREF(__pyx_tuple__80);
+ __pyx_codeobj__81 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__80, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_motor_names, 532, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__81)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":539
* @cython.embedsignature(False)
@@ -19041,10 +17111,10 @@ static int __Pyx_InitCachedConstants(void) {
* """List of motor positions as floats from the ``#P`` scan header line.
* """
*/
- __pyx_tuple__81 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__81)) __PYX_ERR(0, 539, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__81);
- __Pyx_GIVEREF(__pyx_tuple__81);
- __pyx_codeobj__82 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__81, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_motor_positions, 539, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__82)) __PYX_ERR(0, 539, __pyx_L1_error)
+ __pyx_tuple__82 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__82)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 539; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__82);
+ __Pyx_GIVEREF(__pyx_tuple__82);
+ __pyx_codeobj__83 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__82, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_motor_positions, 539, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__83)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 539; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":544
* return self._motor_positions
@@ -19053,10 +17123,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Check whether a scan header line exists.
*
*/
- __pyx_tuple__83 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_record, __pyx_n_s_line); if (unlikely(!__pyx_tuple__83)) __PYX_ERR(0, 544, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__83);
- __Pyx_GIVEREF(__pyx_tuple__83);
- __pyx_codeobj__84 = (PyObject*)__Pyx_PyCode_New(2, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__83, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_record_exists_in_hdr, 544, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__84)) __PYX_ERR(0, 544, __pyx_L1_error)
+ __pyx_tuple__84 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_record, __pyx_n_s_line); if (unlikely(!__pyx_tuple__84)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 544; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__84);
+ __Pyx_GIVEREF(__pyx_tuple__84);
+ __pyx_codeobj__85 = (PyObject*)__Pyx_PyCode_New(2, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__84, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_record_exists_in_hdr, 544, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__85)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 544; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":563
* return False
@@ -19065,10 +17135,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Returns data for a given line of this scan.
*
*/
- __pyx_tuple__85 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_line_index); if (unlikely(!__pyx_tuple__85)) __PYX_ERR(0, 563, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__85);
- __Pyx_GIVEREF(__pyx_tuple__85);
- __pyx_codeobj__86 = (PyObject*)__Pyx_PyCode_New(2, 0, 2, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__85, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_data_line, 563, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__86)) __PYX_ERR(0, 563, __pyx_L1_error)
+ __pyx_tuple__86 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_line_index); if (unlikely(!__pyx_tuple__86)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 563; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__86);
+ __Pyx_GIVEREF(__pyx_tuple__86);
+ __pyx_codeobj__87 = (PyObject*)__Pyx_PyCode_New(2, 0, 2, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__86, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_data_line, 563, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__87)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 563; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":583
* return self.data[:, line_index]
@@ -19077,10 +17147,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Returns a data column
*
*/
- __pyx_tuple__87 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_label, __pyx_n_s_ret); if (unlikely(!__pyx_tuple__87)) __PYX_ERR(0, 583, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__87);
- __Pyx_GIVEREF(__pyx_tuple__87);
- __pyx_codeobj__88 = (PyObject*)__Pyx_PyCode_New(2, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__87, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_data_column_by_name, 583, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__88)) __PYX_ERR(0, 583, __pyx_L1_error)
+ __pyx_tuple__88 = PyTuple_Pack(3, __pyx_n_s_self, __pyx_n_s_label, __pyx_n_s_ret); if (unlikely(!__pyx_tuple__88)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 583; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__88);
+ __Pyx_GIVEREF(__pyx_tuple__88);
+ __pyx_codeobj__89 = (PyObject*)__Pyx_PyCode_New(2, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__88, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_data_column_by_name, 583, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__89)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 583; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":602
* return ret
@@ -19089,10 +17159,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Returns the position for a given motor
*
*/
- __pyx_tuple__89 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_name); if (unlikely(!__pyx_tuple__89)) __PYX_ERR(0, 602, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__89);
- __Pyx_GIVEREF(__pyx_tuple__89);
- __pyx_codeobj__90 = (PyObject*)__Pyx_PyCode_New(2, 0, 2, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__89, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_motor_position_by_name, 602, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__90)) __PYX_ERR(0, 602, __pyx_L1_error)
+ __pyx_tuple__90 = PyTuple_Pack(2, __pyx_n_s_self, __pyx_n_s_name); if (unlikely(!__pyx_tuple__90)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 602; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__90);
+ __Pyx_GIVEREF(__pyx_tuple__90);
+ __pyx_codeobj__91 = (PyObject*)__Pyx_PyCode_New(2, 0, 2, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__90, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_motor_position_by_name, 602, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__91)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 602; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":615
*
@@ -19101,10 +17171,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Convert a string to ASCII encoded bytes when using python3"""
* if sys.version.startswith("3") and not isinstance(string_, bytes):
*/
- __pyx_tuple__91 = PyTuple_Pack(1, __pyx_n_s_string); if (unlikely(!__pyx_tuple__91)) __PYX_ERR(0, 615, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__91);
- __Pyx_GIVEREF(__pyx_tuple__91);
- __pyx_codeobj__92 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__91, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_string_to_char_star, 615, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__92)) __PYX_ERR(0, 615, __pyx_L1_error)
+ __pyx_tuple__92 = PyTuple_Pack(1, __pyx_n_s_string); if (unlikely(!__pyx_tuple__92)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 615; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__92);
+ __Pyx_GIVEREF(__pyx_tuple__92);
+ __pyx_codeobj__93 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__92, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_string_to_char_star, 615, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__93)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 615; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":622
*
@@ -19113,10 +17183,10 @@ static int __Pyx_InitCachedConstants(void) {
* """Test if a file is a SPEC file, by checking if one of the first two
* lines starts with *#F* (SPEC file header) or *#S* (scan header).
*/
- __pyx_tuple__93 = PyTuple_Pack(4, __pyx_n_s_filename, __pyx_n_s_f, __pyx_n_s_i, __pyx_n_s_line); if (unlikely(!__pyx_tuple__93)) __PYX_ERR(0, 622, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_tuple__93);
- __Pyx_GIVEREF(__pyx_tuple__93);
- __pyx_codeobj__94 = (PyObject*)__Pyx_PyCode_New(1, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__93, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_kieffer_workspace_400_rel, __pyx_n_s_is_specfile, 622, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__94)) __PYX_ERR(0, 622, __pyx_L1_error)
+ __pyx_tuple__94 = PyTuple_Pack(5, __pyx_n_s_filename, __pyx_n_s_f, __pyx_n_s_chunk, __pyx_n_s_i, __pyx_n_s_line); if (unlikely(!__pyx_tuple__94)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 622; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_tuple__94);
+ __Pyx_GIVEREF(__pyx_tuple__94);
+ __pyx_codeobj__95 = (PyObject*)__Pyx_PyCode_New(1, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__94, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_users_knobel_git_silx_silx_io_s, __pyx_n_s_is_specfile, 622, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__95)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 622; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_RefNannyFinishContext();
return 0;
__pyx_L1_error:;
@@ -19125,26 +17195,27 @@ static int __Pyx_InitCachedConstants(void) {
}
static int __Pyx_InitGlobals(void) {
- if (__Pyx_InitStrings(__pyx_string_tab) < 0) __PYX_ERR(0, 1, __pyx_L1_error);
- __pyx_float_0_ = PyFloat_FromDouble(0.); if (unlikely(!__pyx_float_0_)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_float_1_ = PyFloat_FromDouble(1.); if (unlikely(!__pyx_float_1_)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_2 = PyInt_FromLong(2); if (unlikely(!__pyx_int_2)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_3 = PyInt_FromLong(3); if (unlikely(!__pyx_int_3)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_4 = PyInt_FromLong(4); if (unlikely(!__pyx_int_4)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_5 = PyInt_FromLong(5); if (unlikely(!__pyx_int_5)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_6 = PyInt_FromLong(6); if (unlikely(!__pyx_int_6)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_7 = PyInt_FromLong(7); if (unlikely(!__pyx_int_7)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_8 = PyInt_FromLong(8); if (unlikely(!__pyx_int_8)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_9 = PyInt_FromLong(9); if (unlikely(!__pyx_int_9)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_10 = PyInt_FromLong(10); if (unlikely(!__pyx_int_10)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_11 = PyInt_FromLong(11); if (unlikely(!__pyx_int_11)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_12 = PyInt_FromLong(12); if (unlikely(!__pyx_int_12)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_13 = PyInt_FromLong(13); if (unlikely(!__pyx_int_13)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_14 = PyInt_FromLong(14); if (unlikely(!__pyx_int_14)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_15 = PyInt_FromLong(15); if (unlikely(!__pyx_int_15)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_int_neg_1 = PyInt_FromLong(-1); if (unlikely(!__pyx_int_neg_1)) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
+ __pyx_float_0_ = PyFloat_FromDouble(0.); if (unlikely(!__pyx_float_0_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_float_1_ = PyFloat_FromDouble(1.); if (unlikely(!__pyx_float_1_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_1 = PyInt_FromLong(1); if (unlikely(!__pyx_int_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_2 = PyInt_FromLong(2); if (unlikely(!__pyx_int_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_3 = PyInt_FromLong(3); if (unlikely(!__pyx_int_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_4 = PyInt_FromLong(4); if (unlikely(!__pyx_int_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_5 = PyInt_FromLong(5); if (unlikely(!__pyx_int_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_6 = PyInt_FromLong(6); if (unlikely(!__pyx_int_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_7 = PyInt_FromLong(7); if (unlikely(!__pyx_int_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_8 = PyInt_FromLong(8); if (unlikely(!__pyx_int_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_9 = PyInt_FromLong(9); if (unlikely(!__pyx_int_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_10 = PyInt_FromLong(10); if (unlikely(!__pyx_int_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_11 = PyInt_FromLong(11); if (unlikely(!__pyx_int_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_12 = PyInt_FromLong(12); if (unlikely(!__pyx_int_12)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_13 = PyInt_FromLong(13); if (unlikely(!__pyx_int_13)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_14 = PyInt_FromLong(14); if (unlikely(!__pyx_int_14)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_15 = PyInt_FromLong(15); if (unlikely(!__pyx_int_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_2500 = PyInt_FromLong(2500); if (unlikely(!__pyx_int_2500)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_int_neg_1 = PyInt_FromLong(-1); if (unlikely(!__pyx_int_neg_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
return 0;
__pyx_L1_error:;
return -1;
@@ -19164,7 +17235,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
PyObject *__pyx_t_4 = NULL;
PyObject *__pyx_t_5 = NULL;
int __pyx_t_6;
- int __pyx_t_7;
+ int __pyx_lineno = 0;
+ const char *__pyx_filename = NULL;
+ int __pyx_clineno = 0;
__Pyx_RefNannyDeclarations
#if CYTHON_REFNANNY
__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny");
@@ -19176,24 +17249,17 @@ PyMODINIT_FUNC PyInit_specfile(void)
}
#endif
__Pyx_RefNannySetupContext("PyMODINIT_FUNC PyInit_specfile(void)", 0);
- if (__Pyx_check_binary_version() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error)
+ if ( __Pyx_check_binary_version() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#ifdef __Pyx_CyFunction_USED
- if (__pyx_CyFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (__Pyx_CyFunction_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
#ifdef __Pyx_FusedFunction_USED
- if (__pyx_FusedFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
- #endif
- #ifdef __Pyx_Coroutine_USED
- if (__pyx_Coroutine_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (__pyx_FusedFunction_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
#ifdef __Pyx_Generator_USED
- if (__pyx_Generator_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
- #endif
- #ifdef __Pyx_StopAsyncIteration_USED
- if (__pyx_StopAsyncIteration_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (__pyx_Generator_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
/*--- Library function declarations ---*/
/*--- Threads initialization code ---*/
@@ -19208,86 +17274,86 @@ PyMODINIT_FUNC PyInit_specfile(void)
#else
__pyx_m = PyModule_Create(&__pyx_moduledef);
#endif
- if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error)
- __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (unlikely(!__pyx_m)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
Py_INCREF(__pyx_d);
- __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error)
+ __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#if CYTHON_COMPILING_IN_PYPY
Py_INCREF(__pyx_b);
#endif
- if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error);
+ if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
/*--- Initialize various global constants etc. ---*/
- if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (unlikely(__Pyx_InitGlobals() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT)
- if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (__Pyx_init_sys_getdefaultencoding_params() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
#endif
if (__pyx_module_is_main_silx__io__specfile) {
- if (PyObject_SetAttrString(__pyx_m, "__name__", __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (PyObject_SetAttrString(__pyx_m, "__name__", __pyx_n_s_main) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;};
}
#if PY_MAJOR_VERSION >= 3
{
- PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error)
+ PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
if (!PyDict_GetItemString(modules, "silx.io.specfile")) {
- if (unlikely(PyDict_SetItemString(modules, "silx.io.specfile", __pyx_m) < 0)) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (unlikely(PyDict_SetItemString(modules, "silx.io.specfile", __pyx_m) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}
}
#endif
/*--- Builtin init code ---*/
- if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (unlikely(__Pyx_InitCachedBuiltins() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/*--- Constants init code ---*/
- if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (unlikely(__Pyx_InitCachedConstants() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/*--- Global init code ---*/
/*--- Variable export code ---*/
/*--- Function export code ---*/
/*--- Type init code ---*/
- if (PyType_Ready(&__pyx_type_4silx_2io_8specfile_SpecFile) < 0) __PYX_ERR(0, 644, __pyx_L1_error)
+ if (PyType_Ready(&__pyx_type_4silx_2io_8specfile_SpecFile) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 643; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_type_4silx_2io_8specfile_SpecFile.tp_print = 0;
#if CYTHON_COMPILING_IN_CPYTHON
{
- PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_4silx_2io_8specfile_SpecFile, "__len__"); if (unlikely(!wrapper)) __PYX_ERR(0, 644, __pyx_L1_error)
+ PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_4silx_2io_8specfile_SpecFile, "__len__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 643; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {
- __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_6__len__ = *((PyWrapperDescrObject *)wrapper)->d_base;
- __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_6__len__.doc = __pyx_doc_4silx_2io_8specfile_8SpecFile_6__len__;
- ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_6__len__;
+ __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_8__len__ = *((PyWrapperDescrObject *)wrapper)->d_base;
+ __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_8__len__.doc = __pyx_doc_4silx_2io_8specfile_8SpecFile_8__len__;
+ ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_8__len__;
}
}
#endif
#if CYTHON_COMPILING_IN_CPYTHON
{
- PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_4silx_2io_8specfile_SpecFile, "__iter__"); if (unlikely(!wrapper)) __PYX_ERR(0, 644, __pyx_L1_error)
+ PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_4silx_2io_8specfile_SpecFile, "__iter__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 643; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {
- __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_8__iter__ = *((PyWrapperDescrObject *)wrapper)->d_base;
- __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_8__iter__.doc = __pyx_doc_4silx_2io_8specfile_8SpecFile_8__iter__;
- ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_8__iter__;
+ __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_10__iter__ = *((PyWrapperDescrObject *)wrapper)->d_base;
+ __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_10__iter__.doc = __pyx_doc_4silx_2io_8specfile_8SpecFile_10__iter__;
+ ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_10__iter__;
}
}
#endif
#if CYTHON_COMPILING_IN_CPYTHON
{
- PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_4silx_2io_8specfile_SpecFile, "__getitem__"); if (unlikely(!wrapper)) __PYX_ERR(0, 644, __pyx_L1_error)
+ PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_4silx_2io_8specfile_SpecFile, "__getitem__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 643; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {
- __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_11__getitem__ = *((PyWrapperDescrObject *)wrapper)->d_base;
- __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_11__getitem__.doc = __pyx_doc_4silx_2io_8specfile_8SpecFile_11__getitem__;
- ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_11__getitem__;
+ __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_13__getitem__ = *((PyWrapperDescrObject *)wrapper)->d_base;
+ __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_13__getitem__.doc = __pyx_doc_4silx_2io_8specfile_8SpecFile_13__getitem__;
+ ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_13__getitem__;
}
}
#endif
#if CYTHON_COMPILING_IN_CPYTHON
{
- PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_4silx_2io_8specfile_SpecFile, "__contains__"); if (unlikely(!wrapper)) __PYX_ERR(0, 644, __pyx_L1_error)
+ PyObject *wrapper = PyObject_GetAttrString((PyObject *)&__pyx_type_4silx_2io_8specfile_SpecFile, "__contains__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 643; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {
- __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_15__contains__ = *((PyWrapperDescrObject *)wrapper)->d_base;
- __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_15__contains__.doc = __pyx_doc_4silx_2io_8specfile_8SpecFile_15__contains__;
- ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_15__contains__;
+ __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_17__contains__ = *((PyWrapperDescrObject *)wrapper)->d_base;
+ __pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_17__contains__.doc = __pyx_doc_4silx_2io_8specfile_8SpecFile_17__contains__;
+ ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_4silx_2io_8specfile_8SpecFile_17__contains__;
}
}
#endif
- if (PyObject_SetAttrString(__pyx_m, "SpecFile", (PyObject *)&__pyx_type_4silx_2io_8specfile_SpecFile) < 0) __PYX_ERR(0, 644, __pyx_L1_error)
+ if (PyObject_SetAttrString(__pyx_m, "SpecFile", (PyObject *)&__pyx_type_4silx_2io_8specfile_SpecFile) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 643; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_ptype_4silx_2io_8specfile_SpecFile = &__pyx_type_4silx_2io_8specfile_SpecFile;
- if (PyType_Ready(&__pyx_type_4silx_2io_8specfile___pyx_scope_struct____iter__) < 0) __PYX_ERR(0, 314, __pyx_L1_error)
+ if (PyType_Ready(&__pyx_type_4silx_2io_8specfile___pyx_scope_struct____iter__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 314; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_type_4silx_2io_8specfile___pyx_scope_struct____iter__.tp_print = 0;
__pyx_ptype_4silx_2io_8specfile___pyx_scope_struct____iter__ = &__pyx_type_4silx_2io_8specfile___pyx_scope_struct____iter__;
- if (PyType_Ready(&__pyx_type_4silx_2io_8specfile___pyx_scope_struct_1___iter__) < 0) __PYX_ERR(0, 694, __pyx_L1_error)
+ if (PyType_Ready(&__pyx_type_4silx_2io_8specfile___pyx_scope_struct_1___iter__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 698; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__pyx_type_4silx_2io_8specfile___pyx_scope_struct_1___iter__.tp_print = 0;
__pyx_ptype_4silx_2io_8specfile___pyx_scope_struct_1___iter__ = &__pyx_type_4silx_2io_8specfile___pyx_scope_struct_1___iter__;
/*--- Type import code ---*/
@@ -19297,18 +17363,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
#else
sizeof(PyHeapTypeObject),
#endif
- 0); if (unlikely(!__pyx_ptype_7cpython_4type_type)) __PYX_ERR(2, 9, __pyx_L1_error)
- __pyx_ptype_5numpy_dtype = __Pyx_ImportType("numpy", "dtype", sizeof(PyArray_Descr), 0); if (unlikely(!__pyx_ptype_5numpy_dtype)) __PYX_ERR(1, 155, __pyx_L1_error)
- __pyx_ptype_5numpy_flatiter = __Pyx_ImportType("numpy", "flatiter", sizeof(PyArrayIterObject), 0); if (unlikely(!__pyx_ptype_5numpy_flatiter)) __PYX_ERR(1, 168, __pyx_L1_error)
- __pyx_ptype_5numpy_broadcast = __Pyx_ImportType("numpy", "broadcast", sizeof(PyArrayMultiIterObject), 0); if (unlikely(!__pyx_ptype_5numpy_broadcast)) __PYX_ERR(1, 172, __pyx_L1_error)
- __pyx_ptype_5numpy_ndarray = __Pyx_ImportType("numpy", "ndarray", sizeof(PyArrayObject), 0); if (unlikely(!__pyx_ptype_5numpy_ndarray)) __PYX_ERR(1, 181, __pyx_L1_error)
- __pyx_ptype_5numpy_ufunc = __Pyx_ImportType("numpy", "ufunc", sizeof(PyUFuncObject), 0); if (unlikely(!__pyx_ptype_5numpy_ufunc)) __PYX_ERR(1, 861, __pyx_L1_error)
+ 0); if (unlikely(!__pyx_ptype_7cpython_4type_type)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_ptype_5numpy_dtype = __Pyx_ImportType("numpy", "dtype", sizeof(PyArray_Descr), 0); if (unlikely(!__pyx_ptype_5numpy_dtype)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 155; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_ptype_5numpy_flatiter = __Pyx_ImportType("numpy", "flatiter", sizeof(PyArrayIterObject), 0); if (unlikely(!__pyx_ptype_5numpy_flatiter)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_ptype_5numpy_broadcast = __Pyx_ImportType("numpy", "broadcast", sizeof(PyArrayMultiIterObject), 0); if (unlikely(!__pyx_ptype_5numpy_broadcast)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 169; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_ptype_5numpy_ndarray = __Pyx_ImportType("numpy", "ndarray", sizeof(PyArrayObject), 0); if (unlikely(!__pyx_ptype_5numpy_ndarray)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __pyx_ptype_5numpy_ufunc = __Pyx_ImportType("numpy", "ufunc", sizeof(PyUFuncObject), 0); if (unlikely(!__pyx_ptype_5numpy_ufunc)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 861; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/*--- Variable import code ---*/
/*--- Function import code ---*/
/*--- Execution code ---*/
- #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
- if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error)
- #endif
/* "silx/io/specfile.pyx":106
* """
@@ -19317,12 +17380,12 @@ PyMODINIT_FUNC PyInit_specfile(void)
* __license__ = "MIT"
* __date__ = "11/08/2017"
*/
- __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 106, __pyx_L1_error)
+ __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_INCREF(__pyx_kp_s_P_Knobel);
- __Pyx_GIVEREF(__pyx_kp_s_P_Knobel);
PyList_SET_ITEM(__pyx_t_1, 0, __pyx_kp_s_P_Knobel);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_authors, __pyx_t_1) < 0) __PYX_ERR(0, 106, __pyx_L1_error)
+ __Pyx_GIVEREF(__pyx_kp_s_P_Knobel);
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_authors, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":107
@@ -19332,7 +17395,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* __date__ = "11/08/2017"
*
*/
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_license, __pyx_n_s_MIT) < 0) __PYX_ERR(0, 107, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_license, __pyx_n_s_MIT) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":108
* __authors__ = ["P. Knobel"]
@@ -19341,7 +17404,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
*
* import os.path
*/
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_date, __pyx_kp_s_11_08_2017) < 0) __PYX_ERR(0, 108, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_date, __pyx_kp_s_11_08_2017) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":110
* __date__ = "11/08/2017"
@@ -19350,9 +17413,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* import logging
* import numpy
*/
- __pyx_t_1 = __Pyx_Import(__pyx_n_s_os_path, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 110, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_Import(__pyx_n_s_os_path, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_os, __pyx_t_1) < 0) __PYX_ERR(0, 110, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_os, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":111
@@ -19362,9 +17425,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* import numpy
* import re
*/
- __pyx_t_1 = __Pyx_Import(__pyx_n_s_logging, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 111, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_Import(__pyx_n_s_logging, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_logging, __pyx_t_1) < 0) __PYX_ERR(0, 111, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_logging, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":112
@@ -19374,9 +17437,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* import re
* import sys
*/
- __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 112, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_numpy, __pyx_t_1) < 0) __PYX_ERR(0, 112, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_numpy, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":113
@@ -19386,9 +17449,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* import sys
*
*/
- __pyx_t_1 = __Pyx_Import(__pyx_n_s_re, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 113, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_Import(__pyx_n_s_re, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_re, __pyx_t_1) < 0) __PYX_ERR(0, 113, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_re, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":114
@@ -19398,9 +17461,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
*
* _logger = logging.getLogger(__name__)
*/
- __pyx_t_1 = __Pyx_Import(__pyx_n_s_sys, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 114, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_Import(__pyx_n_s_sys, 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 114; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_sys, __pyx_t_1) < 0) __PYX_ERR(0, 114, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_sys, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 114; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":116
@@ -19410,15 +17473,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
*
* cimport numpy
*/
- __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_logging); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 116, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_logging); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_getLogger); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 116, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_getLogger); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_name_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 116, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_name_2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
+ if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_3))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
@@ -19428,42 +17491,22 @@ PyMODINIT_FUNC PyInit_specfile(void)
}
}
if (!__pyx_t_4) {
- __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_GOTREF(__pyx_t_1);
} else {
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_2};
- __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- } else
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
- PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_2};
- __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error)
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- } else
- #endif
- {
- __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 116, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __pyx_t_4 = NULL;
- __Pyx_GIVEREF(__pyx_t_2);
- PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_t_2);
- __pyx_t_2 = 0;
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 116, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- }
+ __pyx_t_5 = PyTuple_New(1+1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_5);
+ PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); __pyx_t_4 = NULL;
+ PyTuple_SET_ITEM(__pyx_t_5, 0+1, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
+ __pyx_t_2 = 0;
+ __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_5, NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_1);
+ __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_logger, __pyx_t_1) < 0) __PYX_ERR(0, 116, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_logger, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":131
@@ -19493,15 +17536,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* numpy.import_array()
*/
import_umath();
-
- /* "silx/io/specfile.pyx":131
- * void import_umath()
- *
- * if FALSE: # <<<<<<<<<<<<<<
- * import_array()
- * import_umath()
- */
+ goto __pyx_L2;
}
+ __pyx_L2:;
/* "silx/io/specfile.pyx":135
* import_umath()
@@ -19510,7 +17547,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
*
*
*/
- __pyx_t_7 = __pyx_f_5numpy_import_array(); if (unlikely(__pyx_t_7 == -1)) __PYX_ERR(0, 135, __pyx_L1_error)
+ import_array();
/* "silx/io/specfile.pyx":138
*
@@ -19519,7 +17556,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* SF_ERR_FILE_OPEN = 2
* SF_ERR_SCAN_NOT_FOUND = 7
*/
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SF_ERR_NO_ERRORS, __pyx_int_0) < 0) __PYX_ERR(0, 138, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SF_ERR_NO_ERRORS, __pyx_int_0) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 138; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":139
*
@@ -19528,7 +17565,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* SF_ERR_SCAN_NOT_FOUND = 7
*
*/
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SF_ERR_FILE_OPEN, __pyx_int_2) < 0) __PYX_ERR(0, 139, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SF_ERR_FILE_OPEN, __pyx_int_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":140
* SF_ERR_NO_ERRORS = 0
@@ -19537,7 +17574,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
*
*
*/
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SF_ERR_SCAN_NOT_FOUND, __pyx_int_7) < 0) __PYX_ERR(0, 140, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SF_ERR_SCAN_NOT_FOUND, __pyx_int_7) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 140; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
/* "silx/io/specfile.pyx":144
*
@@ -19546,18 +17583,18 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Base exception inherited by all exceptions raised when a
* C function from the legacy SpecFile library returns an error
*/
- __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 144, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_INCREF(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0])));
- __Pyx_GIVEREF(((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0])));
- PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)(&((PyTypeObject*)PyExc_Exception)[0])));
- __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 144, __pyx_L1_error)
+ __Pyx_INCREF(__pyx_builtin_Exception);
+ PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_builtin_Exception);
+ __Pyx_GIVEREF(__pyx_builtin_Exception);
+ __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfError, __pyx_n_s_SfError, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, __pyx_kp_s_Base_exception_inherited_by_all); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 144, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfError, __pyx_n_s_SfError, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, __pyx_kp_s_Base_exception_inherited_by_all); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfError, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 144, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfError, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfError, __pyx_t_2) < 0) __PYX_ERR(0, 144, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfError, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -19570,23 +17607,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrFileOpen(SfError, IOError): pass
* class SfErrFileClose(SfError, IOError): pass
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 151, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 151, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
+ __Pyx_GIVEREF(__pyx_t_1);
__Pyx_INCREF(__pyx_builtin_MemoryError);
- __Pyx_GIVEREF(__pyx_builtin_MemoryError);
PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_builtin_MemoryError);
+ __Pyx_GIVEREF(__pyx_builtin_MemoryError);
__pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 151, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrMemoryAlloc, __pyx_n_s_SfErrMemoryAlloc, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 151, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrMemoryAlloc, __pyx_n_s_SfErrMemoryAlloc, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrMemoryAlloc, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 151, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrMemoryAlloc, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrMemoryAlloc, __pyx_t_2) < 0) __PYX_ERR(0, 151, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrMemoryAlloc, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 151; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -19599,23 +17636,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrFileClose(SfError, IOError): pass
* class SfErrFileRead(SfError, IOError): pass
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 152, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 152, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_3);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3);
+ __Pyx_GIVEREF(__pyx_t_3);
__Pyx_INCREF(__pyx_builtin_IOError);
- __Pyx_GIVEREF(__pyx_builtin_IOError);
PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_builtin_IOError);
+ __Pyx_GIVEREF(__pyx_builtin_IOError);
__pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 152, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrFileOpen, __pyx_n_s_SfErrFileOpen, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 152, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrFileOpen, __pyx_n_s_SfErrFileOpen, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrFileOpen, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 152, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrFileOpen, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrFileOpen, __pyx_t_2) < 0) __PYX_ERR(0, 152, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrFileOpen, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -19628,23 +17665,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrFileRead(SfError, IOError): pass
* class SfErrFileWrite(SfError, IOError): pass
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 153, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 153, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
+ __Pyx_GIVEREF(__pyx_t_1);
__Pyx_INCREF(__pyx_builtin_IOError);
- __Pyx_GIVEREF(__pyx_builtin_IOError);
PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_builtin_IOError);
+ __Pyx_GIVEREF(__pyx_builtin_IOError);
__pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 153, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrFileClose, __pyx_n_s_SfErrFileClose, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 153, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrFileClose, __pyx_n_s_SfErrFileClose, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrFileClose, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 153, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrFileClose, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrFileClose, __pyx_t_2) < 0) __PYX_ERR(0, 153, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrFileClose, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -19657,23 +17694,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrFileWrite(SfError, IOError): pass
* class SfErrLineNotFound(SfError, KeyError): pass
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 154, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 154; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 154, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 154; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_3);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3);
+ __Pyx_GIVEREF(__pyx_t_3);
__Pyx_INCREF(__pyx_builtin_IOError);
- __Pyx_GIVEREF(__pyx_builtin_IOError);
PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_builtin_IOError);
+ __Pyx_GIVEREF(__pyx_builtin_IOError);
__pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 154, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 154; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrFileRead, __pyx_n_s_SfErrFileRead, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 154, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrFileRead, __pyx_n_s_SfErrFileRead, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 154; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrFileRead, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 154, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrFileRead, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 154; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrFileRead, __pyx_t_2) < 0) __PYX_ERR(0, 154, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrFileRead, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 154; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -19686,23 +17723,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrLineNotFound(SfError, KeyError): pass
* class SfErrScanNotFound(SfError, IndexError): pass
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 155, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 155; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 155, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 155; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
+ __Pyx_GIVEREF(__pyx_t_1);
__Pyx_INCREF(__pyx_builtin_IOError);
- __Pyx_GIVEREF(__pyx_builtin_IOError);
PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_builtin_IOError);
+ __Pyx_GIVEREF(__pyx_builtin_IOError);
__pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 155, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 155; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrFileWrite, __pyx_n_s_SfErrFileWrite, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 155, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrFileWrite, __pyx_n_s_SfErrFileWrite, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 155; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrFileWrite, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 155, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrFileWrite, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 155; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrFileWrite, __pyx_t_2) < 0) __PYX_ERR(0, 155, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrFileWrite, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 155; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -19715,23 +17752,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrScanNotFound(SfError, IndexError): pass
* class SfErrHeaderNotFound(SfError, KeyError): pass
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 156, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 156, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_3);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3);
+ __Pyx_GIVEREF(__pyx_t_3);
__Pyx_INCREF(__pyx_builtin_KeyError);
- __Pyx_GIVEREF(__pyx_builtin_KeyError);
PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_builtin_KeyError);
+ __Pyx_GIVEREF(__pyx_builtin_KeyError);
__pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 156, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrLineNotFound, __pyx_n_s_SfErrLineNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 156, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrLineNotFound, __pyx_n_s_SfErrLineNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrLineNotFound, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 156, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrLineNotFound, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrLineNotFound, __pyx_t_2) < 0) __PYX_ERR(0, 156, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrLineNotFound, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -19744,23 +17781,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrHeaderNotFound(SfError, KeyError): pass
* class SfErrLabelNotFound(SfError, KeyError): pass
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 157, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 157, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
+ __Pyx_GIVEREF(__pyx_t_1);
__Pyx_INCREF(__pyx_builtin_IndexError);
- __Pyx_GIVEREF(__pyx_builtin_IndexError);
PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_builtin_IndexError);
+ __Pyx_GIVEREF(__pyx_builtin_IndexError);
__pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 157, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrScanNotFound, __pyx_n_s_SfErrScanNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 157, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrScanNotFound, __pyx_n_s_SfErrScanNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrScanNotFound, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 157, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrScanNotFound, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrScanNotFound, __pyx_t_2) < 0) __PYX_ERR(0, 157, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrScanNotFound, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -19773,23 +17810,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrLabelNotFound(SfError, KeyError): pass
* class SfErrMotorNotFound(SfError, KeyError): pass
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 158, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 158, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_3);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3);
+ __Pyx_GIVEREF(__pyx_t_3);
__Pyx_INCREF(__pyx_builtin_KeyError);
- __Pyx_GIVEREF(__pyx_builtin_KeyError);
PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_builtin_KeyError);
+ __Pyx_GIVEREF(__pyx_builtin_KeyError);
__pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 158, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrHeaderNotFound, __pyx_n_s_SfErrHeaderNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 158, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrHeaderNotFound, __pyx_n_s_SfErrHeaderNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrHeaderNotFound, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 158, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrHeaderNotFound, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrHeaderNotFound, __pyx_t_2) < 0) __PYX_ERR(0, 158, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrHeaderNotFound, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -19802,23 +17839,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrMotorNotFound(SfError, KeyError): pass
* class SfErrPositionNotFound(SfError, KeyError): pass
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 159, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 159; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 159, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 159; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
+ __Pyx_GIVEREF(__pyx_t_1);
__Pyx_INCREF(__pyx_builtin_KeyError);
- __Pyx_GIVEREF(__pyx_builtin_KeyError);
PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_builtin_KeyError);
+ __Pyx_GIVEREF(__pyx_builtin_KeyError);
__pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 159, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 159; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrLabelNotFound, __pyx_n_s_SfErrLabelNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 159, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrLabelNotFound, __pyx_n_s_SfErrLabelNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 159; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrLabelNotFound, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 159, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrLabelNotFound, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 159; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrLabelNotFound, __pyx_t_2) < 0) __PYX_ERR(0, 159, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrLabelNotFound, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 159; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -19831,23 +17868,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrPositionNotFound(SfError, KeyError): pass
* class SfErrLineEmpty(SfError, IOError): pass
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 160, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 160, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_3);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3);
+ __Pyx_GIVEREF(__pyx_t_3);
__Pyx_INCREF(__pyx_builtin_KeyError);
- __Pyx_GIVEREF(__pyx_builtin_KeyError);
PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_builtin_KeyError);
+ __Pyx_GIVEREF(__pyx_builtin_KeyError);
__pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 160, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrMotorNotFound, __pyx_n_s_SfErrMotorNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 160, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrMotorNotFound, __pyx_n_s_SfErrMotorNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrMotorNotFound, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 160, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrMotorNotFound, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrMotorNotFound, __pyx_t_2) < 0) __PYX_ERR(0, 160, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrMotorNotFound, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -19860,23 +17897,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrLineEmpty(SfError, IOError): pass
* class SfErrUserNotFound(SfError, KeyError): pass
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 161, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 161, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
+ __Pyx_GIVEREF(__pyx_t_1);
__Pyx_INCREF(__pyx_builtin_KeyError);
- __Pyx_GIVEREF(__pyx_builtin_KeyError);
PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_builtin_KeyError);
+ __Pyx_GIVEREF(__pyx_builtin_KeyError);
__pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 161, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrPositionNotFound, __pyx_n_s_SfErrPositionNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 161, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrPositionNotFound, __pyx_n_s_SfErrPositionNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrPositionNotFound, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 161, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrPositionNotFound, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrPositionNotFound, __pyx_t_2) < 0) __PYX_ERR(0, 161, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrPositionNotFound, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -19889,23 +17926,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrUserNotFound(SfError, KeyError): pass
* class SfErrColNotFound(SfError, KeyError): pass
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 162, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 162; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 162, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 162; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_3);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3);
+ __Pyx_GIVEREF(__pyx_t_3);
__Pyx_INCREF(__pyx_builtin_IOError);
- __Pyx_GIVEREF(__pyx_builtin_IOError);
PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_builtin_IOError);
+ __Pyx_GIVEREF(__pyx_builtin_IOError);
__pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 162, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 162; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrLineEmpty, __pyx_n_s_SfErrLineEmpty, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 162, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrLineEmpty, __pyx_n_s_SfErrLineEmpty, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 162; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrLineEmpty, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 162, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrLineEmpty, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 162; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrLineEmpty, __pyx_t_2) < 0) __PYX_ERR(0, 162, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrLineEmpty, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 162; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -19918,23 +17955,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrColNotFound(SfError, KeyError): pass
* class SfErrMcaNotFound(SfError, IndexError): pass
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 163, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 163, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
+ __Pyx_GIVEREF(__pyx_t_1);
__Pyx_INCREF(__pyx_builtin_KeyError);
- __Pyx_GIVEREF(__pyx_builtin_KeyError);
PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_builtin_KeyError);
+ __Pyx_GIVEREF(__pyx_builtin_KeyError);
__pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 163, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrUserNotFound, __pyx_n_s_SfErrUserNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 163, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrUserNotFound, __pyx_n_s_SfErrUserNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrUserNotFound, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 163, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrUserNotFound, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrUserNotFound, __pyx_t_2) < 0) __PYX_ERR(0, 163, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrUserNotFound, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -19947,23 +17984,23 @@ PyMODINIT_FUNC PyInit_specfile(void)
* class SfErrMcaNotFound(SfError, IndexError): pass
*
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 164, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 164, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_3);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3);
+ __Pyx_GIVEREF(__pyx_t_3);
__Pyx_INCREF(__pyx_builtin_KeyError);
- __Pyx_GIVEREF(__pyx_builtin_KeyError);
PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_builtin_KeyError);
+ __Pyx_GIVEREF(__pyx_builtin_KeyError);
__pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 164, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrColNotFound, __pyx_n_s_SfErrColNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 164, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfErrColNotFound, __pyx_n_s_SfErrColNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrColNotFound, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 164, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfErrColNotFound, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrColNotFound, __pyx_t_2) < 0) __PYX_ERR(0, 164, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrColNotFound, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -19976,28 +18013,38 @@ PyMODINIT_FUNC PyInit_specfile(void)
*
*
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 165, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 165, __pyx_L1_error)
+ __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_1);
PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
+ __Pyx_GIVEREF(__pyx_t_1);
__Pyx_INCREF(__pyx_builtin_IndexError);
- __Pyx_GIVEREF(__pyx_builtin_IndexError);
PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_builtin_IndexError);
+ __Pyx_GIVEREF(__pyx_builtin_IndexError);
__pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 165, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_CalculateMetaclass(NULL, __pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrMcaNotFound, __pyx_n_s_SfErrMcaNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 165, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_1, __pyx_t_3, __pyx_n_s_SfErrMcaNotFound, __pyx_n_s_SfErrMcaNotFound, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, (PyObject *) NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrMcaNotFound, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 165, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_1, __pyx_n_s_SfErrMcaNotFound, __pyx_t_3, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrMcaNotFound, __pyx_t_2) < 0) __PYX_ERR(0, 165, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfErrMcaNotFound, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+ /* "silx/io/specfile.pyx":168
+ *
+ *
+ * ERRORS = { # <<<<<<<<<<<<<<
+ * 1: SfErrMemoryAlloc,
+ * 2: SfErrFileOpen,
+ */
+ __pyx_t_3 = PyDict_New(); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+ __Pyx_GOTREF(__pyx_t_3);
+
/* "silx/io/specfile.pyx":169
*
* ERRORS = {
@@ -20005,11 +18052,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 2: SfErrFileOpen,
* 3: SfErrFileClose,
*/
- __pyx_t_3 = PyDict_New(); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 169, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrMemoryAlloc); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 169, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrMemoryAlloc); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 169; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_1, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_1, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":170
@@ -20019,9 +18064,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 3: SfErrFileClose,
* 4: SfErrFileRead,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrFileOpen); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 170, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrFileOpen); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_2, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_2, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":171
@@ -20031,9 +18076,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 4: SfErrFileRead,
* 5: SfErrFileWrite,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrFileClose); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 171, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrFileClose); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 171; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_3, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_3, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":172
@@ -20043,9 +18088,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 5: SfErrFileWrite,
* 6: SfErrLineNotFound,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrFileRead); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 172, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrFileRead); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 172; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_4, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_4, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":173
@@ -20055,9 +18100,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 6: SfErrLineNotFound,
* 7: SfErrScanNotFound,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrFileWrite); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 173, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrFileWrite); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 173; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_5, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_5, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":174
@@ -20067,9 +18112,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 7: SfErrScanNotFound,
* 8: SfErrHeaderNotFound,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrLineNotFound); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 174, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrLineNotFound); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 174; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_6, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_6, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":175
@@ -20079,9 +18124,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 8: SfErrHeaderNotFound,
* 9: SfErrLabelNotFound,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrScanNotFound); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 175, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrScanNotFound); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 175; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_7, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_7, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":176
@@ -20091,9 +18136,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 9: SfErrLabelNotFound,
* 10: SfErrMotorNotFound,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrHeaderNotFound); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 176, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrHeaderNotFound); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_8, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_8, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":177
@@ -20103,9 +18148,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 10: SfErrMotorNotFound,
* 11: SfErrPositionNotFound,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrLabelNotFound); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 177, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrLabelNotFound); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 177; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_9, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_9, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":178
@@ -20115,9 +18160,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 11: SfErrPositionNotFound,
* 12: SfErrLineEmpty,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrMotorNotFound); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 178, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrMotorNotFound); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_10, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_10, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":179
@@ -20127,9 +18172,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 12: SfErrLineEmpty,
* 13: SfErrUserNotFound,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrPositionNotFound); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 179, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrPositionNotFound); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 179; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_11, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_11, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":180
@@ -20139,9 +18184,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 13: SfErrUserNotFound,
* 14: SfErrColNotFound,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrLineEmpty); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 180, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrLineEmpty); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 180; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_12, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_12, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":181
@@ -20151,9 +18196,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 14: SfErrColNotFound,
* 15: SfErrMcaNotFound,
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrUserNotFound); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 181, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrUserNotFound); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 181; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_13, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_13, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":182
@@ -20163,9 +18208,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* 15: SfErrMcaNotFound,
* }
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrColNotFound); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 182, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrColNotFound); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 182; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_14, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_14, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":183
@@ -20175,11 +18220,11 @@ PyMODINIT_FUNC PyInit_specfile(void)
* }
*
*/
- __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrMcaNotFound); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 183, __pyx_L1_error)
+ __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfErrMcaNotFound); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 183; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_t_3, __pyx_int_15, __pyx_t_1) < 0) __PYX_ERR(0, 169, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_t_3, __pyx_int_15, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_ERRORS, __pyx_t_3) < 0) __PYX_ERR(0, 168, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_ERRORS, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
/* "silx/io/specfile.pyx":187
@@ -20189,20 +18234,20 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Custom exception raised when ``SfNoMca()`` returns ``-1``
* """
*/
- __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 187, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_SfError); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 187, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_3);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3);
+ __Pyx_GIVEREF(__pyx_t_3);
__pyx_t_3 = 0;
- __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 187, __pyx_L1_error)
+ __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfNoMcaError, __pyx_n_s_SfNoMcaError, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, __pyx_kp_s_Custom_exception_raised_when_SfN); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 187, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_SfNoMcaError, __pyx_n_s_SfNoMcaError, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, __pyx_kp_s_Custom_exception_raised_when_SfN); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfNoMcaError, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 187, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_SfNoMcaError, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfNoMcaError, __pyx_t_2) < 0) __PYX_ERR(0, 187, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_SfNoMcaError, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -20215,14 +18260,14 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """
*
*/
- __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 193, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 193; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_INCREF(__pyx_builtin_object);
- __Pyx_GIVEREF(__pyx_builtin_object);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_builtin_object);
- __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 193, __pyx_L1_error)
+ __Pyx_GIVEREF(__pyx_builtin_object);
+ __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 193; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_MCA, __pyx_n_s_MCA, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, __pyx_kp_s_param_scan_Parent_Scan_instance); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 193, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_MCA, __pyx_n_s_MCA, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, __pyx_kp_s_param_scan_Parent_Scan_instance); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 193; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
/* "silx/io/specfile.pyx":233
@@ -20232,9 +18277,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* self._scan = scan
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_1__init__, 0, __pyx_n_s_MCA___init, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__40)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 233, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_1__init__, 0, __pyx_n_s_MCA___init, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__41)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_init, __pyx_t_2) < 0) __PYX_ERR(0, 233, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_init, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":251
@@ -20244,9 +18289,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Fill :attr:`channels`"""
* # Channels list
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_3_parse_channels, 0, __pyx_n_s_MCA__parse_channels, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__42)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 251, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_3_parse_channels, 0, __pyx_n_s_MCA__parse_channels, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__43)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 251; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_parse_channels, __pyx_t_2) < 0) __PYX_ERR(0, 251, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_parse_channels, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 251; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":266
@@ -20256,9 +18301,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Fill :attr:`calibration`"""
* # Channels list
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_5_parse_calibration, 0, __pyx_n_s_MCA__parse_calibration, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__44)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 266, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_5_parse_calibration, 0, __pyx_n_s_MCA__parse_calibration, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__45)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_parse_calibration, __pyx_t_2) < 0) __PYX_ERR(0, 266, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_parse_calibration, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 266; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":278
@@ -20268,9 +18313,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_7__len__, 0, __pyx_n_s_MCA___len, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__46)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 278, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_7__len__, 0, __pyx_n_s_MCA___len, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__47)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 278; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_len, __pyx_t_2) < 0) __PYX_ERR(0, 278, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_len, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 278; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":286
@@ -20280,9 +18325,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Return a single MCA data line
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_9__getitem__, 0, __pyx_n_s_MCA___getitem, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__48)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 286, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_9__getitem__, 0, __pyx_n_s_MCA___getitem, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__49)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_getitem, __pyx_t_2) < 0) __PYX_ERR(0, 286, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_getitem, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 286; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":314
@@ -20292,9 +18337,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Return the next MCA data line each time this method is called.
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_11__iter__, 0, __pyx_n_s_MCA___iter, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__50)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 314, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3MCA_11__iter__, 0, __pyx_n_s_MCA___iter, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__51)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 314; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_iter, __pyx_t_2) < 0) __PYX_ERR(0, 314, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_iter, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 314; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":193
@@ -20304,9 +18349,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """
*
*/
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_MCA, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 193, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_MCA, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 193; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_MCA, __pyx_t_2) < 0) __PYX_ERR(0, 193, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_MCA, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 193; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -20319,9 +18364,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """If key doesn't exist in dictionary, create a new ``key: value`` pair.
* Else append/concatenate the new value to the existing one
*/
- __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_1_add_or_concatenate, NULL, __pyx_n_s_silx_io_specfile); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 324, __pyx_L1_error)
+ __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_1_add_or_concatenate, NULL, __pyx_n_s_silx_io_specfile); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 324; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_add_or_concatenate, __pyx_t_1) < 0) __PYX_ERR(0, 324, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_add_or_concatenate, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 324; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":337
@@ -20331,14 +18376,14 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """
*
*/
- __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 337, __pyx_L1_error)
+ __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 337; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__Pyx_INCREF(__pyx_builtin_object);
- __Pyx_GIVEREF(__pyx_builtin_object);
PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_builtin_object);
- __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 337, __pyx_L1_error)
+ __Pyx_GIVEREF(__pyx_builtin_object);
+ __pyx_t_3 = __Pyx_CalculateMetaclass(NULL, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 337; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
- __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_Scan, __pyx_n_s_Scan, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, __pyx_kp_s_param_specfile_Parent_SpecFile); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 337, __pyx_L1_error)
+ __pyx_t_5 = __Pyx_Py3MetaclassPrepare(__pyx_t_3, __pyx_t_1, __pyx_n_s_Scan, __pyx_n_s_Scan, (PyObject *) NULL, __pyx_n_s_silx_io_specfile, __pyx_kp_s_param_specfile_Parent_SpecFile); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 337; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_5);
/* "silx/io/specfile.pyx":362
@@ -20348,9 +18393,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* self._specfile = specfile
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_1__init__, 0, __pyx_n_s_Scan___init, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__54)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 362, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_1__init__, 0, __pyx_n_s_Scan___init, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__55)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 362; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_init, __pyx_t_2) < 0) __PYX_ERR(0, 362, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_init, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 362; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":423
@@ -20360,7 +18405,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Unique scan index 0 - len(specfile)-1
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_3index, 0, __pyx_n_s_Scan_index, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__56)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 423, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_3index, 0, __pyx_n_s_Scan_index, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__57)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 423; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":422
@@ -20370,15 +18415,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def index(self):
* """Unique scan index 0 - len(specfile)-1
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 422, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 422; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 422, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 422; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_index, __pyx_t_2) < 0) __PYX_ERR(0, 423, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_index, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 423; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":433
@@ -20388,7 +18433,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """First value on #S line (as int)"""
* return self._number
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_5number, 0, __pyx_n_s_Scan_number, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__58)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 433, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_5number, 0, __pyx_n_s_Scan_number, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__59)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 433; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":432
@@ -20398,15 +18443,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def number(self):
* """First value on #S line (as int)"""
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 432, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 432; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 432, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 432; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_number, __pyx_t_2) < 0) __PYX_ERR(0, 433, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_number, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 433; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":439
@@ -20416,7 +18461,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Order can be > 1 if the same number is repeated in a specfile"""
* return self._order
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_7order, 0, __pyx_n_s_Scan_order, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__60)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 439, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_7order, 0, __pyx_n_s_Scan_order, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__61)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":438
@@ -20426,15 +18471,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def order(self):
* """Order can be > 1 if the same number is repeated in a specfile"""
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 438, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 438; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 438, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 438; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_order, __pyx_t_2) < 0) __PYX_ERR(0, 439, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_order, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 439; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":445
@@ -20444,7 +18489,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """List of raw header lines (as a list of strings).
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_9header, 0, __pyx_n_s_Scan_header, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__62)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 445, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_9header, 0, __pyx_n_s_Scan_header, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__63)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 445; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":444
@@ -20454,15 +18499,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def header(self):
* """List of raw header lines (as a list of strings).
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 444, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 444; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 444, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 444; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_header_2, __pyx_t_2) < 0) __PYX_ERR(0, 445, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_header_2, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 445; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":455
@@ -20472,7 +18517,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """List of raw scan header lines (as a list of strings).
* """
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_11scan_header, 0, __pyx_n_s_Scan_scan_header, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__64)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 455, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_11scan_header, 0, __pyx_n_s_Scan_scan_header, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__65)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 455; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":454
@@ -20482,15 +18527,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def scan_header(self):
* """List of raw scan header lines (as a list of strings).
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 454, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 454; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 454, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 454; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_scan_header, __pyx_t_2) < 0) __PYX_ERR(0, 455, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_scan_header, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 455; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":462
@@ -20500,7 +18545,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """List of raw file header lines (as a list of strings).
* """
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_13file_header, 0, __pyx_n_s_Scan_file_header, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__66)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 462, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_13file_header, 0, __pyx_n_s_Scan_file_header, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__67)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 462; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":461
@@ -20510,15 +18555,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def file_header(self):
* """List of raw file header lines (as a list of strings).
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 461, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 461; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 461, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 461; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_file_header, __pyx_t_2) < 0) __PYX_ERR(0, 462, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_file_header, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 462; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":469
@@ -20528,7 +18573,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """
* Dictionary of scan header strings, keys without the leading``#``
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_15scan_header_dict, 0, __pyx_n_s_Scan_scan_header_dict, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__68)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 469, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_15scan_header_dict, 0, __pyx_n_s_Scan_scan_header_dict, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__69)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 469; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":468
@@ -20538,15 +18583,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def scan_header_dict(self):
* """
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 468, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 468; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 468, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 468; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_scan_header_dict_2, __pyx_t_2) < 0) __PYX_ERR(0, 469, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_scan_header_dict_2, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 469; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":479
@@ -20556,7 +18601,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """
* Dictionary of MCA header strings, keys without the leading ``#@``
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_17mca_header_dict, 0, __pyx_n_s_Scan_mca_header_dict, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__70)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 479, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_17mca_header_dict, 0, __pyx_n_s_Scan_mca_header_dict, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__71)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 479; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":478
@@ -20566,15 +18611,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def mca_header_dict(self):
* """
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 478, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 478; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 478, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 478; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_mca_header_dict, __pyx_t_2) < 0) __PYX_ERR(0, 479, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_mca_header_dict, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 479; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":488
@@ -20584,7 +18629,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """
* Dictionary of file header strings, keys without the leading ``#``
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_19file_header_dict, 0, __pyx_n_s_Scan_file_header_dict, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__72)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 488, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_19file_header_dict, 0, __pyx_n_s_Scan_file_header_dict, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__73)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 488; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":487
@@ -20594,15 +18639,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def file_header_dict(self):
* """
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 487, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 487; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 487, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 487; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_file_header_dict_2, __pyx_t_2) < 0) __PYX_ERR(0, 488, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_file_header_dict_2, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 488; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":497
@@ -20612,7 +18657,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """
* List of data column headers from ``#L`` scan header
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_21labels, 0, __pyx_n_s_Scan_labels, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__74)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 497, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_21labels, 0, __pyx_n_s_Scan_labels, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__75)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 497; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":496
@@ -20622,15 +18667,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def labels(self):
* """
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 496, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 496; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 496, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 496; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_labels_2, __pyx_t_2) < 0) __PYX_ERR(0, 497, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_labels_2, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 497; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":505
@@ -20640,7 +18685,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Scan data as a 2D numpy.ndarray with the usual attributes
* (e.g. data.shape).
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_23data, 0, __pyx_n_s_Scan_data, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__76)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 505, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_23data, 0, __pyx_n_s_Scan_data, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__77)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 505; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":504
@@ -20650,15 +18695,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def data(self):
* """Scan data as a 2D numpy.ndarray with the usual attributes
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 504, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 504; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 504, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 504; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_data_2, __pyx_t_2) < 0) __PYX_ERR(0, 505, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_data_2, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 505; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":518
@@ -20668,7 +18713,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """MCA data in this scan.
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_25mca, 0, __pyx_n_s_Scan_mca, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__78)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 518, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_25mca, 0, __pyx_n_s_Scan_mca, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__79)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 518; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":517
@@ -20678,15 +18723,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def mca(self):
* """MCA data in this scan.
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 517, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 517; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 517, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 517; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_mca_2, __pyx_t_2) < 0) __PYX_ERR(0, 518, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_mca_2, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 518; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":532
@@ -20696,7 +18741,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """List of motor names from the ``#O`` file header line.
* """
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_27motor_names, 0, __pyx_n_s_Scan_motor_names, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__80)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 532, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_27motor_names, 0, __pyx_n_s_Scan_motor_names, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__81)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":531
@@ -20706,15 +18751,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def motor_names(self):
* """List of motor names from the ``#O`` file header line.
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 531, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 531; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 531, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 531; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_motor_names, __pyx_t_2) < 0) __PYX_ERR(0, 532, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_motor_names, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 532; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":539
@@ -20724,7 +18769,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """List of motor positions as floats from the ``#P`` scan header line.
* """
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_29motor_positions, 0, __pyx_n_s_Scan_motor_positions, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__82)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 539, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_29motor_positions, 0, __pyx_n_s_Scan_motor_positions, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__83)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 539; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
/* "silx/io/specfile.pyx":538
@@ -20734,15 +18779,15 @@ PyMODINIT_FUNC PyInit_specfile(void)
* def motor_positions(self):
* """List of motor positions as floats from the ``#P`` scan header line.
*/
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 538, __pyx_L1_error)
+ __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 538; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_2);
PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
+ __Pyx_GIVEREF(__pyx_t_2);
__pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 538, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_PyObject_Call(__pyx_builtin_property, __pyx_t_4, NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 538; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_motor_positions, __pyx_t_2) < 0) __PYX_ERR(0, 539, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_motor_positions, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 539; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":544
@@ -20752,9 +18797,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Check whether a scan header line exists.
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_31record_exists_in_hdr, 0, __pyx_n_s_Scan_record_exists_in_hdr, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__84)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 544, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_31record_exists_in_hdr, 0, __pyx_n_s_Scan_record_exists_in_hdr, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__85)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 544; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_record_exists_in_hdr, __pyx_t_2) < 0) __PYX_ERR(0, 544, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_record_exists_in_hdr, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 544; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":563
@@ -20764,9 +18809,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Returns data for a given line of this scan.
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_33data_line, 0, __pyx_n_s_Scan_data_line, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__86)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 563, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_33data_line, 0, __pyx_n_s_Scan_data_line, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__87)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 563; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_data_line, __pyx_t_2) < 0) __PYX_ERR(0, 563, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_data_line, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 563; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":583
@@ -20776,9 +18821,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Returns a data column
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_35data_column_by_name, 0, __pyx_n_s_Scan_data_column_by_name, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__88)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 583, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_35data_column_by_name, 0, __pyx_n_s_Scan_data_column_by_name, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__89)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 583; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_data_column_by_name, __pyx_t_2) < 0) __PYX_ERR(0, 583, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_data_column_by_name, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 583; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":602
@@ -20788,9 +18833,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Returns the position for a given motor
*
*/
- __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_37motor_position_by_name, 0, __pyx_n_s_Scan_motor_position_by_name, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__90)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 602, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_CyFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_4Scan_37motor_position_by_name, 0, __pyx_n_s_Scan_motor_position_by_name, NULL, __pyx_n_s_silx_io_specfile, __pyx_d, ((PyObject *)__pyx_codeobj__91)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 602; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_motor_position_by_name, __pyx_t_2) < 0) __PYX_ERR(0, 602, __pyx_L1_error)
+ if (PyObject_SetItem(__pyx_t_5, __pyx_n_s_motor_position_by_name, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 602; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* "silx/io/specfile.pyx":337
@@ -20800,9 +18845,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """
*
*/
- __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_Scan, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 337, __pyx_L1_error)
+ __pyx_t_2 = __Pyx_Py3ClassCreate(__pyx_t_3, __pyx_n_s_Scan, __pyx_t_1, __pyx_t_5, NULL, 0, 1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 337; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_Scan, __pyx_t_2) < 0) __PYX_ERR(0, 337, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_Scan, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 337; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
@@ -20815,9 +18860,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Convert a string to ASCII encoded bytes when using python3"""
* if sys.version.startswith("3") and not isinstance(string_, bytes):
*/
- __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3_string_to_char_star, NULL, __pyx_n_s_silx_io_specfile); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 615, __pyx_L1_error)
+ __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_3_string_to_char_star, NULL, __pyx_n_s_silx_io_specfile); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 615; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_string_to_char_star, __pyx_t_1) < 0) __PYX_ERR(0, 615, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_string_to_char_star, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 615; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":622
@@ -20827,9 +18872,9 @@ PyMODINIT_FUNC PyInit_specfile(void)
* """Test if a file is a SPEC file, by checking if one of the first two
* lines starts with *#F* (SPEC file header) or *#S* (scan header).
*/
- __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_5is_specfile, NULL, __pyx_n_s_silx_io_specfile); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 622, __pyx_L1_error)
+ __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_4silx_2io_8specfile_5is_specfile, NULL, __pyx_n_s_silx_io_specfile); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 622; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_is_specfile, __pyx_t_1) < 0) __PYX_ERR(0, 622, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_is_specfile, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 622; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* "silx/io/specfile.pyx":1
@@ -20837,17 +18882,17 @@ PyMODINIT_FUNC PyInit_specfile(void)
* # /[inserted by cython to avoid comment start]*##########################################################################
* # Copyright (C) 2016-2017 European Synchrotron Radiation Facility
*/
- __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)
+ __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
- if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
+ if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- /* "../../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":997
- * raise ImportError("numpy.core.umath failed to import")
+ /* "../../../../usr/lib/python2.7/dist-packages/Cython/Includes/numpy/__init__.pxd":976
+ * arr.base = baseptr
*
- * cdef inline int import_ufunc() except -1: # <<<<<<<<<<<<<<
- * try:
- * _import_umath()
+ * cdef inline object get_array_base(ndarray arr): # <<<<<<<<<<<<<<
+ * if arr.base is NULL:
+ * return None
*/
/*--- Wrapped vars code ---*/
@@ -20876,8 +18921,7 @@ PyMODINIT_FUNC PyInit_specfile(void)
#endif
}
-/* --- Runtime support code --- */
-/* Refnanny */
+/* Runtime support code */
#if CYTHON_REFNANNY
static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) {
PyObject *m = NULL, *p = NULL;
@@ -20894,7 +18938,6 @@ end:
}
#endif
-/* GetBuiltinName */
static PyObject *__Pyx_GetBuiltinName(PyObject *name) {
PyObject* result = __Pyx_PyObject_GetAttrStr(__pyx_b, name);
if (unlikely(!result)) {
@@ -20908,7 +18951,6 @@ static PyObject *__Pyx_GetBuiltinName(PyObject *name) {
return result;
}
-/* RaiseArgTupleInvalid */
static void __Pyx_RaiseArgtupleInvalid(
const char* func_name,
int exact,
@@ -20934,7 +18976,6 @@ static void __Pyx_RaiseArgtupleInvalid(
(num_expected == 1) ? "" : "s", num_found);
}
-/* RaiseDoubleKeywords */
static void __Pyx_RaiseDoubleKeywordsError(
const char* func_name,
PyObject* kw_name)
@@ -20948,7 +18989,6 @@ static void __Pyx_RaiseDoubleKeywordsError(
#endif
}
-/* ParseKeywords */
static int __Pyx_ParseOptionalKeywords(
PyObject *kwds,
PyObject **argnames[],
@@ -21050,145 +19090,6 @@ bad:
return -1;
}
-/* PyCFunctionFastCall */
-#if CYTHON_FAST_PYCCALL
-static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) {
- PyCFunctionObject *func = (PyCFunctionObject*)func_obj;
- PyCFunction meth = PyCFunction_GET_FUNCTION(func);
- PyObject *self = PyCFunction_GET_SELF(func);
- assert(PyCFunction_Check(func));
- assert(METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)));
- assert(nargs >= 0);
- assert(nargs == 0 || args != NULL);
- /* _PyCFunction_FastCallDict() must not be called with an exception set,
- because it may clear it (directly or indirectly) and so the
- caller loses its exception */
- assert(!PyErr_Occurred());
- return (*((__Pyx_PyCFunctionFast)meth)) (self, args, nargs, NULL);
-}
-#endif // CYTHON_FAST_PYCCALL
-
-/* PyFunctionFastCall */
-#if CYTHON_FAST_PYCALL
-#include "frameobject.h"
-static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na,
- PyObject *globals) {
- PyFrameObject *f;
- PyThreadState *tstate = PyThreadState_GET();
- PyObject **fastlocals;
- Py_ssize_t i;
- PyObject *result;
- assert(globals != NULL);
- /* XXX Perhaps we should create a specialized
- PyFrame_New() that doesn't take locals, but does
- take builtins without sanity checking them.
- */
- assert(tstate != NULL);
- f = PyFrame_New(tstate, co, globals, NULL);
- if (f == NULL) {
- return NULL;
- }
- fastlocals = f->f_localsplus;
- for (i = 0; i < na; i++) {
- Py_INCREF(*args);
- fastlocals[i] = *args++;
- }
- result = PyEval_EvalFrameEx(f,0);
- ++tstate->recursion_depth;
- Py_DECREF(f);
- --tstate->recursion_depth;
- return result;
-}
-#if 1 || PY_VERSION_HEX < 0x030600B1
-static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) {
- PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
- PyObject *globals = PyFunction_GET_GLOBALS(func);
- PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
- PyObject *closure;
-#if PY_MAJOR_VERSION >= 3
- PyObject *kwdefs;
-#endif
- PyObject *kwtuple, **k;
- PyObject **d;
- Py_ssize_t nd;
- Py_ssize_t nk;
- PyObject *result;
- assert(kwargs == NULL || PyDict_Check(kwargs));
- nk = kwargs ? PyDict_Size(kwargs) : 0;
- if (Py_EnterRecursiveCall((char*)" while calling a Python object")) {
- return NULL;
- }
- if (
-#if PY_MAJOR_VERSION >= 3
- co->co_kwonlyargcount == 0 &&
-#endif
- likely(kwargs == NULL || nk == 0) &&
- co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) {
- if (argdefs == NULL && co->co_argcount == nargs) {
- result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals);
- goto done;
- }
- else if (nargs == 0 && argdefs != NULL
- && co->co_argcount == Py_SIZE(argdefs)) {
- /* function called with no arguments, but all parameters have
- a default value: use default values as arguments .*/
- args = &PyTuple_GET_ITEM(argdefs, 0);
- result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals);
- goto done;
- }
- }
- if (kwargs != NULL) {
- Py_ssize_t pos, i;
- kwtuple = PyTuple_New(2 * nk);
- if (kwtuple == NULL) {
- result = NULL;
- goto done;
- }
- k = &PyTuple_GET_ITEM(kwtuple, 0);
- pos = i = 0;
- while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) {
- Py_INCREF(k[i]);
- Py_INCREF(k[i+1]);
- i += 2;
- }
- nk = i / 2;
- }
- else {
- kwtuple = NULL;
- k = NULL;
- }
- closure = PyFunction_GET_CLOSURE(func);
-#if PY_MAJOR_VERSION >= 3
- kwdefs = PyFunction_GET_KW_DEFAULTS(func);
-#endif
- if (argdefs != NULL) {
- d = &PyTuple_GET_ITEM(argdefs, 0);
- nd = Py_SIZE(argdefs);
- }
- else {
- d = NULL;
- nd = 0;
- }
-#if PY_MAJOR_VERSION >= 3
- result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL,
- args, nargs,
- k, (int)nk,
- d, (int)nd, kwdefs, closure);
-#else
- result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL,
- args, nargs,
- k, (int)nk,
- d, (int)nd, closure);
-#endif
- Py_XDECREF(kwtuple);
-done:
- Py_LeaveRecursiveCall();
- return result;
-}
-#endif // CPython < 3.6
-#endif // CYTHON_FAST_PYCALL
-
-/* PyObjectCall */
#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) {
PyObject *result;
@@ -21208,7 +19109,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg
}
#endif
-/* PyObjectCallMethO */
#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) {
PyObject *self, *result;
@@ -21228,7 +19128,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject
}
#endif
-/* PyObjectCallOneArg */
#if CYTHON_COMPILING_IN_CPYTHON
static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) {
PyObject *result;
@@ -21241,11 +19140,6 @@ static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) {
return result;
}
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) {
-#if CYTHON_FAST_PYCALL
- if (PyFunction_Check(func)) {
- return __Pyx_PyFunction_FastCall(func, &arg, 1);
- }
-#endif
#ifdef __Pyx_CyFunction_USED
if (likely(PyCFunction_Check(func) || PyObject_TypeCheck(func, __pyx_CyFunctionType))) {
#else
@@ -21253,33 +19147,19 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec
#endif
if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) {
return __Pyx_PyObject_CallMethO(func, arg);
-#if CYTHON_FAST_PYCCALL
- } else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) {
- return __Pyx_PyCFunction_FastCall(func, &arg, 1);
-#endif
}
}
return __Pyx__PyObject_CallOneArg(func, arg);
}
#else
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) {
- PyObject *result;
- PyObject *args = PyTuple_Pack(1, arg);
- if (unlikely(!args)) return NULL;
- result = __Pyx_PyObject_Call(func, args, NULL);
- Py_DECREF(args);
- return result;
+ PyObject* args = PyTuple_Pack(1, arg);
+ return (likely(args)) ? __Pyx_PyObject_Call(func, args, NULL) : NULL;
}
#endif
-/* PyObjectCallNoArg */
- #if CYTHON_COMPILING_IN_CPYTHON
+#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
-#if CYTHON_FAST_PYCALL
- if (PyFunction_Check(func)) {
- return __Pyx_PyFunction_FastCall(func, NULL, 0);
- }
-#endif
#ifdef __Pyx_CyFunction_USED
if (likely(PyCFunction_Check(func) || PyObject_TypeCheck(func, __pyx_CyFunctionType))) {
#else
@@ -21293,22 +19173,19 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
}
#endif
-/* RaiseTooManyValuesToUnpack */
- static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) {
+static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) {
PyErr_Format(PyExc_ValueError,
"too many values to unpack (expected %" CYTHON_FORMAT_SSIZE_T "d)", expected);
}
-/* RaiseNeedMoreValuesToUnpack */
- static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
+static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
PyErr_Format(PyExc_ValueError,
"need more than %" CYTHON_FORMAT_SSIZE_T "d value%.1s to unpack",
index, (index == 1) ? "" : "s");
}
-/* IterFinish */
- static CYTHON_INLINE int __Pyx_IterFinish(void) {
-#if CYTHON_FAST_THREAD_STATE
+static CYTHON_INLINE int __Pyx_IterFinish(void) {
+#if CYTHON_COMPILING_IN_CPYTHON
PyThreadState *tstate = PyThreadState_GET();
PyObject* exc_type = tstate->curexc_type;
if (unlikely(exc_type)) {
@@ -21341,8 +19218,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
#endif
}
-/* UnpackItemEndCheck */
- static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) {
+static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) {
if (unlikely(retval)) {
Py_DECREF(retval);
__Pyx_RaiseTooManyValuesError(expected);
@@ -21353,33 +19229,18 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
return 0;
}
-/* PyObjectCallMethod1 */
- static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) {
+static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) {
PyObject *method, *result = NULL;
method = __Pyx_PyObject_GetAttrStr(obj, method_name);
- if (unlikely(!method)) goto done;
-#if CYTHON_UNPACK_METHODS
+ if (unlikely(!method)) goto bad;
+#if CYTHON_COMPILING_IN_CPYTHON
if (likely(PyMethod_Check(method))) {
PyObject *self = PyMethod_GET_SELF(method);
if (likely(self)) {
PyObject *args;
PyObject *function = PyMethod_GET_FUNCTION(method);
- #if CYTHON_FAST_PYCALL
- if (PyFunction_Check(function)) {
- PyObject *args[2] = {self, arg};
- result = __Pyx_PyFunction_FastCall(function, args, 2);
- goto done;
- }
- #endif
- #if CYTHON_FAST_PYCCALL
- if (__Pyx_PyFastCFunction_Check(function)) {
- PyObject *args[2] = {self, arg};
- result = __Pyx_PyCFunction_FastCall(function, args, 2);
- goto done;
- }
- #endif
args = PyTuple_New(2);
- if (unlikely(!args)) goto done;
+ if (unlikely(!args)) goto bad;
Py_INCREF(self);
PyTuple_SET_ITEM(args, 0, self);
Py_INCREF(arg);
@@ -21394,13 +19255,12 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
}
#endif
result = __Pyx_PyObject_CallOneArg(method, arg);
-done:
+bad:
Py_XDECREF(method);
return result;
}
-/* append */
- static CYTHON_INLINE int __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
+static CYTHON_INLINE int __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
if (likely(PyList_CheckExact(L))) {
if (unlikely(__Pyx_PyList_Append(L, x) < 0)) return -1;
} else {
@@ -21412,124 +19272,7 @@ done:
return 0;
}
-/* PyIntBinop */
- #if !CYTHON_COMPILING_IN_PYPY
-static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) {
- #if PY_MAJOR_VERSION < 3
- if (likely(PyInt_CheckExact(op1))) {
- const long b = intval;
- long x;
- long a = PyInt_AS_LONG(op1);
- x = (long)((unsigned long)a + b);
- if (likely((x^a) >= 0 || (x^b) >= 0))
- return PyInt_FromLong(x);
- return PyLong_Type.tp_as_number->nb_add(op1, op2);
- }
- #endif
- #if CYTHON_USE_PYLONG_INTERNALS
- if (likely(PyLong_CheckExact(op1))) {
- const long b = intval;
- long a, x;
-#ifdef HAVE_LONG_LONG
- const PY_LONG_LONG llb = intval;
- PY_LONG_LONG lla, llx;
-#endif
- const digit* digits = ((PyLongObject*)op1)->ob_digit;
- const Py_ssize_t size = Py_SIZE(op1);
- if (likely(__Pyx_sst_abs(size) <= 1)) {
- a = likely(size) ? digits[0] : 0;
- if (size == -1) a = -a;
- } else {
- switch (size) {
- case -2:
- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
- a = -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) {
- lla = -(PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- case 2:
- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
- a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) {
- lla = (PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- case -3:
- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
- a = -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) {
- lla = -(PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- case 3:
- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
- a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) {
- lla = (PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- case -4:
- if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
- a = -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) {
- lla = -(PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- case 4:
- if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
- a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) {
- lla = (PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- default: return PyLong_Type.tp_as_number->nb_add(op1, op2);
- }
- }
- x = a + b;
- return PyLong_FromLong(x);
-#ifdef HAVE_LONG_LONG
- long_long:
- llx = lla + llb;
- return PyLong_FromLongLong(llx);
-#endif
-
-
- }
- #endif
- if (PyFloat_CheckExact(op1)) {
- const long b = intval;
- double a = PyFloat_AS_DOUBLE(op1);
- double result;
- PyFPE_START_PROTECT("add", return NULL)
- result = ((double)a) + (double)b;
- PyFPE_END_PROTECT(result)
- return PyFloat_FromDouble(result);
- }
- return (inplace ? PyNumber_InPlaceAdd : PyNumber_Add)(op1, op2);
-}
-#endif
-
-/* GetItemInt */
- static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
PyObject *r;
if (!j) return NULL;
r = PyObject_GetItem(o, j);
@@ -21537,9 +19280,8 @@ static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED
return r;
}
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i,
- CYTHON_NCP_UNUSED int wraparound,
- CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+ int wraparound, int boundscheck) {
+#if CYTHON_COMPILING_IN_CPYTHON
if (wraparound & unlikely(i < 0)) i += PyList_GET_SIZE(o);
if ((!boundscheck) || likely((0 <= i) & (i < PyList_GET_SIZE(o)))) {
PyObject *r = PyList_GET_ITEM(o, i);
@@ -21552,9 +19294,8 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_
#endif
}
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i,
- CYTHON_NCP_UNUSED int wraparound,
- CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+ int wraparound, int boundscheck) {
+#if CYTHON_COMPILING_IN_CPYTHON
if (wraparound & unlikely(i < 0)) i += PyTuple_GET_SIZE(o);
if ((!boundscheck) || likely((0 <= i) & (i < PyTuple_GET_SIZE(o)))) {
PyObject *r = PyTuple_GET_ITEM(o, i);
@@ -21566,10 +19307,9 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize
return PySequence_GetItem(o, i);
#endif
}
-static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list,
- CYTHON_NCP_UNUSED int wraparound,
- CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS
+static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
+ int is_list, int wraparound, int boundscheck) {
+#if CYTHON_COMPILING_IN_CPYTHON
if (is_list || PyList_CheckExact(o)) {
Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o);
if ((!boundscheck) || (likely((n >= 0) & (n < PyList_GET_SIZE(o))))) {
@@ -21593,9 +19333,10 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
if (likely(l >= 0)) {
i += l;
} else {
- if (!PyErr_ExceptionMatches(PyExc_OverflowError))
+ if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ PyErr_Clear();
+ else
return NULL;
- PyErr_Clear();
}
}
return m->sq_item(o, i);
@@ -21609,126 +19350,10 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
}
-/* PyIntBinop */
- #if !CYTHON_COMPILING_IN_PYPY
-static PyObject* __Pyx_PyInt_SubtractObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) {
- #if PY_MAJOR_VERSION < 3
- if (likely(PyInt_CheckExact(op1))) {
- const long b = intval;
- long x;
- long a = PyInt_AS_LONG(op1);
- x = (long)((unsigned long)a - b);
- if (likely((x^a) >= 0 || (x^~b) >= 0))
- return PyInt_FromLong(x);
- return PyLong_Type.tp_as_number->nb_subtract(op1, op2);
- }
- #endif
- #if CYTHON_USE_PYLONG_INTERNALS
- if (likely(PyLong_CheckExact(op1))) {
- const long b = intval;
- long a, x;
-#ifdef HAVE_LONG_LONG
- const PY_LONG_LONG llb = intval;
- PY_LONG_LONG lla, llx;
-#endif
- const digit* digits = ((PyLongObject*)op1)->ob_digit;
- const Py_ssize_t size = Py_SIZE(op1);
- if (likely(__Pyx_sst_abs(size) <= 1)) {
- a = likely(size) ? digits[0] : 0;
- if (size == -1) a = -a;
- } else {
- switch (size) {
- case -2:
- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
- a = -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) {
- lla = -(PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- case 2:
- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
- a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) {
- lla = (PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- case -3:
- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
- a = -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) {
- lla = -(PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- case 3:
- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
- a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) {
- lla = (PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- case -4:
- if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
- a = -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) {
- lla = -(PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- case 4:
- if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
- a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
-#ifdef HAVE_LONG_LONG
- } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) {
- lla = (PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0]));
- goto long_long;
-#endif
- }
- default: return PyLong_Type.tp_as_number->nb_subtract(op1, op2);
- }
- }
- x = a - b;
- return PyLong_FromLong(x);
-#ifdef HAVE_LONG_LONG
- long_long:
- llx = lla - llb;
- return PyLong_FromLongLong(llx);
-#endif
-
-
- }
- #endif
- if (PyFloat_CheckExact(op1)) {
- const long b = intval;
- double a = PyFloat_AS_DOUBLE(op1);
- double result;
- PyFPE_START_PROTECT("subtract", return NULL)
- result = ((double)a) - (double)b;
- PyFPE_END_PROTECT(result)
- return PyFloat_FromDouble(result);
- }
- return (inplace ? PyNumber_InPlaceSubtract : PyNumber_Subtract)(op1, op2);
-}
-#endif
-
-/* PyErrFetchRestore */
- #if CYTHON_FAST_THREAD_STATE
-static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) {
+static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {
+#if CYTHON_COMPILING_IN_CPYTHON
PyObject *tmp_type, *tmp_value, *tmp_tb;
+ PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->curexc_type;
tmp_value = tstate->curexc_value;
tmp_tb = tstate->curexc_traceback;
@@ -21738,22 +19363,27 @@ static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObjec
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
+#else
+ PyErr_Restore(type, value, tb);
+#endif
}
-static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
+static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {
+#if CYTHON_COMPILING_IN_CPYTHON
+ PyThreadState *tstate = PyThreadState_GET();
*type = tstate->curexc_type;
*value = tstate->curexc_value;
*tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
-}
+#else
+ PyErr_Fetch(type, value, tb);
#endif
+}
-/* RaiseException */
- #if PY_MAJOR_VERSION < 3
+#if PY_MAJOR_VERSION < 3
static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb,
CYTHON_UNUSED PyObject *cause) {
- __Pyx_PyThreadState_declare
Py_XINCREF(type);
if (!value || value == Py_None)
value = NULL;
@@ -21792,7 +19422,6 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb,
goto raise_error;
}
}
- __Pyx_PyThreadState_assign
__Pyx_ErrRestore(type, value, tb);
return;
raise_error:
@@ -21826,13 +19455,10 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject
if (value && PyExceptionInstance_Check(value)) {
instance_class = (PyObject*) Py_TYPE(value);
if (instance_class != type) {
- int is_subclass = PyObject_IsSubclass(instance_class, type);
- if (!is_subclass) {
- instance_class = NULL;
- } else if (unlikely(is_subclass == -1)) {
- goto bad;
- } else {
+ if (PyObject_IsSubclass(instance_class, type)) {
type = instance_class;
+ } else {
+ instance_class = NULL;
}
}
}
@@ -21892,7 +19518,7 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject
if (tb) {
#if CYTHON_COMPILING_IN_PYPY
PyObject *tmp_type, *tmp_value, *tmp_tb;
- PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb);
+ PyErr_Fetch(tmp_type, tmp_value, tmp_tb);
Py_INCREF(tb);
PyErr_Restore(tmp_type, tmp_value, tb);
Py_XDECREF(tmp_tb);
@@ -21912,18 +19538,23 @@ bad:
}
#endif
-/* SaveResetException */
- #if CYTHON_FAST_THREAD_STATE
-static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
+static CYTHON_INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb) {
+#if CYTHON_COMPILING_IN_CPYTHON
+ PyThreadState *tstate = PyThreadState_GET();
*type = tstate->exc_type;
*value = tstate->exc_value;
*tb = tstate->exc_traceback;
Py_XINCREF(*type);
Py_XINCREF(*value);
Py_XINCREF(*tb);
+#else
+ PyErr_GetExcInfo(type, value, tb);
+#endif
}
-static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) {
+static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) {
+#if CYTHON_COMPILING_IN_CPYTHON
PyObject *tmp_type, *tmp_value, *tmp_tb;
+ PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
@@ -21933,28 +19564,16 @@ static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
-}
+#else
+ PyErr_SetExcInfo(type, value, tb);
#endif
-
-/* PyErrExceptionMatches */
- #if CYTHON_FAST_THREAD_STATE
-static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err) {
- PyObject *exc_type = tstate->curexc_type;
- if (exc_type == err) return 1;
- if (unlikely(!exc_type)) return 0;
- return PyErr_GivenExceptionMatches(exc_type, err);
}
-#endif
-/* GetException */
- #if CYTHON_FAST_THREAD_STATE
-static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
-#else
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
-#endif
PyObject *local_type, *local_value, *local_tb;
-#if CYTHON_FAST_THREAD_STATE
+#if CYTHON_COMPILING_IN_CPYTHON
PyObject *tmp_type, *tmp_value, *tmp_tb;
+ PyThreadState *tstate = PyThreadState_GET();
local_type = tstate->curexc_type;
local_value = tstate->curexc_value;
local_tb = tstate->curexc_traceback;
@@ -21965,7 +19584,7 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb)
PyErr_Fetch(&local_type, &local_value, &local_tb);
#endif
PyErr_NormalizeException(&local_type, &local_value, &local_tb);
-#if CYTHON_FAST_THREAD_STATE
+#if CYTHON_COMPILING_IN_CPYTHON
if (unlikely(tstate->curexc_type))
#else
if (unlikely(PyErr_Occurred()))
@@ -21983,7 +19602,7 @@ static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb)
*type = local_type;
*value = local_value;
*tb = local_tb;
-#if CYTHON_FAST_THREAD_STATE
+#if CYTHON_COMPILING_IN_CPYTHON
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
@@ -22007,10 +19626,9 @@ bad:
return -1;
}
-/* GetModuleGlobalName */
- static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) {
+static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) {
PyObject *result;
-#if !CYTHON_AVOID_BORROWED_REFS
+#if CYTHON_COMPILING_IN_CPYTHON
result = PyDict_GetItem(__pyx_d, name);
if (likely(result)) {
Py_INCREF(result);
@@ -22025,22 +19643,15 @@ bad:
return result;
}
-/* WriteUnraisableException */
- static void __Pyx_WriteUnraisable(const char *name, CYTHON_UNUSED int clineno,
+static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname) {
+ PyErr_Format(PyExc_UnboundLocalError, "local variable '%s' referenced before assignment", varname);
+}
+
+static void __Pyx_WriteUnraisable(const char *name, CYTHON_UNUSED int clineno,
CYTHON_UNUSED int lineno, CYTHON_UNUSED const char *filename,
- int full_traceback, CYTHON_UNUSED int nogil) {
+ int full_traceback) {
PyObject *old_exc, *old_val, *old_tb;
PyObject *ctx;
- __Pyx_PyThreadState_declare
-#ifdef WITH_THREAD
- PyGILState_STATE state;
- if (nogil)
- state = PyGILState_Ensure();
-#ifdef _MSC_VER
- else state = (PyGILState_STATE)-1;
-#endif
-#endif
- __Pyx_PyThreadState_assign
__Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
if (full_traceback) {
Py_XINCREF(old_exc);
@@ -22061,21 +19672,15 @@ bad:
PyErr_WriteUnraisable(ctx);
Py_DECREF(ctx);
}
-#ifdef WITH_THREAD
- if (nogil)
- PyGILState_Release(state);
-#endif
}
-/* StringJoin */
- #if !CYTHON_COMPILING_IN_CPYTHON
+#if !CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE PyObject* __Pyx_PyBytes_Join(PyObject* sep, PyObject* values) {
return PyObject_CallMethodObjArgs(sep, __pyx_n_s_join, values, NULL);
}
#endif
-/* decode_c_bytes */
- static CYTHON_INLINE PyObject* __Pyx_decode_c_bytes(
+static CYTHON_INLINE PyObject* __Pyx_decode_c_bytes(
const char* cstring, Py_ssize_t length, Py_ssize_t start, Py_ssize_t stop,
const char* encoding, const char* errors,
PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) {
@@ -22101,93 +19706,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyBytes_Join(PyObject* sep, PyObject* value
}
}
-/* PyIntBinop */
- #if !CYTHON_COMPILING_IN_PYPY
-static PyObject* __Pyx_PyInt_EqObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED long intval, CYTHON_UNUSED int inplace) {
- if (op1 == op2) {
- Py_RETURN_TRUE;
- }
- #if PY_MAJOR_VERSION < 3
- if (likely(PyInt_CheckExact(op1))) {
- const long b = intval;
- long a = PyInt_AS_LONG(op1);
- if (a == b) {
- Py_RETURN_TRUE;
- } else {
- Py_RETURN_FALSE;
- }
- }
- #endif
- #if CYTHON_USE_PYLONG_INTERNALS
- if (likely(PyLong_CheckExact(op1))) {
- const long b = intval;
- long a;
- const digit* digits = ((PyLongObject*)op1)->ob_digit;
- const Py_ssize_t size = Py_SIZE(op1);
- if (likely(__Pyx_sst_abs(size) <= 1)) {
- a = likely(size) ? digits[0] : 0;
- if (size == -1) a = -a;
- } else {
- switch (size) {
- case -2:
- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
- a = -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
- }
- case 2:
- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
- a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
- }
- case -3:
- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
- a = -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
- }
- case 3:
- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
- a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
- }
- case -4:
- if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
- a = -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
- }
- case 4:
- if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
- a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]));
- break;
- }
- #if PyLong_SHIFT < 30 && PyLong_SHIFT != 15
- default: return PyLong_Type.tp_richcompare(op1, op2, Py_EQ);
- #else
- default: Py_RETURN_FALSE;
- #endif
- }
- }
- if (a == b) {
- Py_RETURN_TRUE;
- } else {
- Py_RETURN_FALSE;
- }
- }
- #endif
- if (PyFloat_CheckExact(op1)) {
- const long b = intval;
- double a = PyFloat_AS_DOUBLE(op1);
- if ((double)a == (double)b) {
- Py_RETURN_TRUE;
- } else {
- Py_RETURN_FALSE;
- }
- }
- return PyObject_RichCompare(op1, op2, Py_EQ);
-}
-#endif
-
-/* ExtTypeTest */
- static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
+static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
if (unlikely(!type)) {
PyErr_SetString(PyExc_SystemError, "Missing type object");
return 0;
@@ -22199,17 +19718,16 @@ static PyObject* __Pyx_PyInt_EqObjC(PyObject *op1, PyObject *op2, CYTHON_UNUSED
return 0;
}
-/* SetItemInt */
- static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) {
+static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) {
int r;
if (!j) return -1;
r = PyObject_SetItem(o, j, v);
Py_DECREF(j);
return r;
}
-static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, int is_list,
- CYTHON_NCP_UNUSED int wraparound, CYTHON_NCP_UNUSED int boundscheck) {
-#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS
+static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v,
+ int is_list, int wraparound, int boundscheck) {
+#if CYTHON_COMPILING_IN_CPYTHON
if (is_list || PyList_CheckExact(o)) {
Py_ssize_t n = (!wraparound) ? i : ((likely(i >= 0)) ? i : i + PyList_GET_SIZE(o));
if ((!boundscheck) || likely((n >= 0) & (n < PyList_GET_SIZE(o)))) {
@@ -22227,9 +19745,10 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
if (likely(l >= 0)) {
i += l;
} else {
- if (!PyErr_ExceptionMatches(PyExc_OverflowError))
+ if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ PyErr_Clear();
+ else
return -1;
- PyErr_Clear();
}
}
return m->sq_ass_item(o, i, v);
@@ -22247,20 +19766,13 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
return __Pyx_SetItemInt_Generic(o, PyInt_FromSsize_t(i), v);
}
-/* decode_c_string */
- static CYTHON_INLINE PyObject* __Pyx_decode_c_string(
+static CYTHON_INLINE PyObject* __Pyx_decode_c_string(
const char* cstring, Py_ssize_t start, Py_ssize_t stop,
const char* encoding, const char* errors,
PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) {
Py_ssize_t length;
if (unlikely((start < 0) | (stop < 0))) {
- size_t slen = strlen(cstring);
- if (unlikely(slen > (size_t) PY_SSIZE_T_MAX)) {
- PyErr_SetString(PyExc_OverflowError,
- "c-string too long to convert to Python");
- return NULL;
- }
- length = (Py_ssize_t) slen;
+ length = strlen(cstring);
if (start < 0) {
start += length;
if (start < 0)
@@ -22280,87 +19792,11 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
}
}
-/* RaiseNoneIterError */
- static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) {
+static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
}
-/* Import */
- static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
- PyObject *empty_list = 0;
- PyObject *module = 0;
- PyObject *global_dict = 0;
- PyObject *empty_dict = 0;
- PyObject *list;
- #if PY_VERSION_HEX < 0x03030000
- PyObject *py_import;
- py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import);
- if (!py_import)
- goto bad;
- #endif
- if (from_list)
- list = from_list;
- else {
- empty_list = PyList_New(0);
- if (!empty_list)
- goto bad;
- list = empty_list;
- }
- global_dict = PyModule_GetDict(__pyx_m);
- if (!global_dict)
- goto bad;
- empty_dict = PyDict_New();
- if (!empty_dict)
- goto bad;
- {
- #if PY_MAJOR_VERSION >= 3
- if (level == -1) {
- if (strchr(__Pyx_MODULE_NAME, '.')) {
- #if PY_VERSION_HEX < 0x03030000
- PyObject *py_level = PyInt_FromLong(1);
- if (!py_level)
- goto bad;
- module = PyObject_CallFunctionObjArgs(py_import,
- name, global_dict, empty_dict, list, py_level, NULL);
- Py_DECREF(py_level);
- #else
- module = PyImport_ImportModuleLevelObject(
- name, global_dict, empty_dict, list, 1);
- #endif
- if (!module) {
- if (!PyErr_ExceptionMatches(PyExc_ImportError))
- goto bad;
- PyErr_Clear();
- }
- }
- level = 0;
- }
- #endif
- if (!module) {
- #if PY_VERSION_HEX < 0x03030000
- PyObject *py_level = PyInt_FromLong(level);
- if (!py_level)
- goto bad;
- module = PyObject_CallFunctionObjArgs(py_import,
- name, global_dict, empty_dict, list, py_level, NULL);
- Py_DECREF(py_level);
- #else
- module = PyImport_ImportModuleLevelObject(
- name, global_dict, empty_dict, list, level);
- #endif
- }
- }
-bad:
- #if PY_VERSION_HEX < 0x03030000
- Py_XDECREF(py_import);
- #endif
- Py_XDECREF(empty_list);
- Py_XDECREF(empty_dict);
- return module;
-}
-
-/* CalculateMetaclass */
- static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases) {
+static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases) {
Py_ssize_t i, nbases = PyTuple_GET_SIZE(bases);
for (i=0; i < nbases; i++) {
PyTypeObject *tmptype;
@@ -22398,8 +19834,7 @@ bad:
return (PyObject*) metaclass;
}
-/* Py3ClassCreate */
- static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name,
+static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name,
PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc) {
PyObject *ns;
if (metaclass) {
@@ -22465,8 +19900,7 @@ static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObj
return result;
}
-/* FetchCommonType */
- static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) {
+static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) {
PyObject* fake_module;
PyTypeObject* cached_type = NULL;
fake_module = PyImport_AddModule((char*) "_cython_" CYTHON_ABI);
@@ -22504,8 +19938,7 @@ bad:
goto done;
}
-/* CythonFunction */
- static PyObject *
+static PyObject *
__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, CYTHON_UNUSED void *closure)
{
if (unlikely(op->func_doc == NULL)) {
@@ -22658,25 +20091,15 @@ __Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op)
}
static int
__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) {
- int result = 0;
PyObject *res = op->defaults_getter((PyObject *) op);
if (unlikely(!res))
return -1;
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
op->defaults_tuple = PyTuple_GET_ITEM(res, 0);
Py_INCREF(op->defaults_tuple);
op->defaults_kwdict = PyTuple_GET_ITEM(res, 1);
Py_INCREF(op->defaults_kwdict);
- #else
- op->defaults_tuple = PySequence_ITEM(res, 0);
- if (unlikely(!op->defaults_tuple)) result = -1;
- else {
- op->defaults_kwdict = PySequence_ITEM(res, 1);
- if (unlikely(!op->defaults_kwdict)) result = -1;
- }
- #endif
Py_DECREF(res);
- return result;
+ return 0;
}
static int
__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value) {
@@ -22786,6 +20209,9 @@ static PyGetSetDef __pyx_CyFunction_getsets[] = {
{(char *) "__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0},
{0, 0, 0, 0, 0}
};
+#ifndef PY_WRITE_RESTRICTED
+#define PY_WRITE_RESTRICTED WRITE_RESTRICTED
+#endif
static PyMemberDef __pyx_CyFunction_members[] = {
{(char *) "__module__", T_OBJECT, offsetof(__pyx_CyFunctionObject, func.m_module), PY_WRITE_RESTRICTED, 0},
{0, 0, 0, 0, 0}
@@ -22860,7 +20286,7 @@ __Pyx_CyFunction_clear(__pyx_CyFunctionObject *m)
int i;
for (i = 0; i < m->defaults_pyobjects; i++)
Py_XDECREF(pydefaults[i]);
- PyObject_Free(m->defaults);
+ PyMem_Free(m->defaults);
m->defaults = NULL;
}
return 0;
@@ -22921,40 +20347,37 @@ __Pyx_CyFunction_repr(__pyx_CyFunctionObject *op)
PyString_AsString(op->func_qualname), (void *)op);
#endif
}
-static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) {
+#if CYTHON_COMPILING_IN_PYPY
+static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) {
PyCFunctionObject* f = (PyCFunctionObject*)func;
- PyCFunction meth = f->m_ml->ml_meth;
+ PyCFunction meth = PyCFunction_GET_FUNCTION(func);
+ PyObject *self = PyCFunction_GET_SELF(func);
Py_ssize_t size;
- switch (f->m_ml->ml_flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) {
+ switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) {
case METH_VARARGS:
- if (likely(kw == NULL || PyDict_Size(kw) == 0))
+ if (likely(kw == NULL) || PyDict_Size(kw) == 0)
return (*meth)(self, arg);
break;
case METH_VARARGS | METH_KEYWORDS:
return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);
case METH_NOARGS:
- if (likely(kw == NULL || PyDict_Size(kw) == 0)) {
+ if (likely(kw == NULL) || PyDict_Size(kw) == 0) {
size = PyTuple_GET_SIZE(arg);
- if (likely(size == 0))
+ if (size == 0)
return (*meth)(self, NULL);
PyErr_Format(PyExc_TypeError,
- "%.200s() takes no arguments (%" CYTHON_FORMAT_SSIZE_T "d given)",
+ "%.200s() takes no arguments (%zd given)",
f->m_ml->ml_name, size);
return NULL;
}
break;
case METH_O:
- if (likely(kw == NULL || PyDict_Size(kw) == 0)) {
+ if (likely(kw == NULL) || PyDict_Size(kw) == 0) {
size = PyTuple_GET_SIZE(arg);
- if (likely(size == 1)) {
- PyObject *result, *arg0 = PySequence_ITEM(arg, 0);
- if (unlikely(!arg0)) return NULL;
- result = (*meth)(self, arg0);
- Py_DECREF(arg0);
- return result;
- }
+ if (size == 1)
+ return (*meth)(self, PyTuple_GET_ITEM(arg, 0));
PyErr_Format(PyExc_TypeError,
- "%.200s() takes exactly one argument (%" CYTHON_FORMAT_SSIZE_T "d given)",
+ "%.200s() takes exactly one argument (%zd given)",
f->m_ml->ml_name, size);
return NULL;
}
@@ -22969,32 +20392,11 @@ static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, Py
f->m_ml->ml_name);
return NULL;
}
-static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) {
- return __Pyx_CyFunction_CallMethod(func, ((PyCFunctionObject*)func)->m_self, arg, kw);
-}
-static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) {
- PyObject *result;
- __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func;
- if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) {
- Py_ssize_t argc;
- PyObject *new_args;
- PyObject *self;
- argc = PyTuple_GET_SIZE(args);
- new_args = PyTuple_GetSlice(args, 1, argc);
- if (unlikely(!new_args))
- return NULL;
- self = PyTuple_GetItem(args, 0);
- if (unlikely(!self)) {
- Py_DECREF(new_args);
- return NULL;
- }
- result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw);
- Py_DECREF(new_args);
- } else {
- result = __Pyx_CyFunction_Call(func, args, kw);
- }
- return result;
+#else
+static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) {
+ return PyCFunction_Call(func, arg, kw);
}
+#endif
static PyTypeObject __pyx_CyFunctionType_type = {
PyVarObject_HEAD_INIT(0, 0)
"cython_function_or_method",
@@ -23014,7 +20416,7 @@ static PyTypeObject __pyx_CyFunctionType_type = {
0,
0,
0,
- __Pyx_CyFunction_CallAsMethod,
+ __Pyx_CyFunction_Call,
0,
0,
0,
@@ -23055,7 +20457,10 @@ static PyTypeObject __pyx_CyFunctionType_type = {
0,
#endif
};
-static int __pyx_CyFunction_init(void) {
+static int __Pyx_CyFunction_init(void) {
+#if !CYTHON_COMPILING_IN_PYPY
+ __pyx_CyFunctionType_type.tp_call = PyCFunction_Call;
+#endif
__pyx_CyFunctionType = __Pyx_FetchCommonType(&__pyx_CyFunctionType_type);
if (__pyx_CyFunctionType == NULL) {
return -1;
@@ -23064,7 +20469,7 @@ static int __pyx_CyFunction_init(void) {
}
static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t size, int pyobjects) {
__pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func;
- m->defaults = PyObject_Malloc(size);
+ m->defaults = PyMem_Malloc(size);
if (!m->defaults)
return PyErr_NoMemory();
memset(m->defaults, 0, size);
@@ -23087,14 +20492,13 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, Py
Py_INCREF(dict);
}
-/* CodeObjectCache */
- static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) {
+static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) {
int start = 0, mid = 0, end = count - 1;
if (end >= 0 && code_line > entries[end].code_line) {
return count;
}
while (start < end) {
- mid = start + (end - start) / 2;
+ mid = (start + end) / 2;
if (code_line < entries[mid].code_line) {
end = mid;
} else if (code_line > entries[mid].code_line) {
@@ -23167,8 +20571,7 @@ static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) {
Py_INCREF(code_object);
}
-/* AddTraceback */
- #include "compile.h"
+#include "compile.h"
#include "frameobject.h"
#include "traceback.h"
static PyCodeObject* __Pyx_CreateCodeObjectForTraceback(
@@ -23241,34 +20644,102 @@ static void __Pyx_AddTraceback(const char *funcname, int c_line,
0 /*PyObject *locals*/
);
if (!py_frame) goto bad;
- __Pyx_PyFrame_SetLineNumber(py_frame, py_line);
+ py_frame->f_lineno = py_line;
PyTraceBack_Here(py_frame);
bad:
Py_XDECREF(py_code);
Py_XDECREF(py_frame);
}
-/* CIntToPy */
- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) {
- const long neg_one = (long) -1, const_zero = (long) 0;
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
+ PyObject *empty_list = 0;
+ PyObject *module = 0;
+ PyObject *global_dict = 0;
+ PyObject *empty_dict = 0;
+ PyObject *list;
+ #if PY_VERSION_HEX < 0x03030000
+ PyObject *py_import;
+ py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import);
+ if (!py_import)
+ goto bad;
+ #endif
+ if (from_list)
+ list = from_list;
+ else {
+ empty_list = PyList_New(0);
+ if (!empty_list)
+ goto bad;
+ list = empty_list;
+ }
+ global_dict = PyModule_GetDict(__pyx_m);
+ if (!global_dict)
+ goto bad;
+ empty_dict = PyDict_New();
+ if (!empty_dict)
+ goto bad;
+ {
+ #if PY_MAJOR_VERSION >= 3
+ if (level == -1) {
+ if (strchr(__Pyx_MODULE_NAME, '.')) {
+ #if PY_VERSION_HEX < 0x03030000
+ PyObject *py_level = PyInt_FromLong(1);
+ if (!py_level)
+ goto bad;
+ module = PyObject_CallFunctionObjArgs(py_import,
+ name, global_dict, empty_dict, list, py_level, NULL);
+ Py_DECREF(py_level);
+ #else
+ module = PyImport_ImportModuleLevelObject(
+ name, global_dict, empty_dict, list, 1);
+ #endif
+ if (!module) {
+ if (!PyErr_ExceptionMatches(PyExc_ImportError))
+ goto bad;
+ PyErr_Clear();
+ }
+ }
+ level = 0;
+ }
+ #endif
+ if (!module) {
+ #if PY_VERSION_HEX < 0x03030000
+ PyObject *py_level = PyInt_FromLong(level);
+ if (!py_level)
+ goto bad;
+ module = PyObject_CallFunctionObjArgs(py_import,
+ name, global_dict, empty_dict, list, py_level, NULL);
+ Py_DECREF(py_level);
+ #else
+ module = PyImport_ImportModuleLevelObject(
+ name, global_dict, empty_dict, list, level);
+ #endif
+ }
+ }
+bad:
+ #if PY_VERSION_HEX < 0x03030000
+ Py_XDECREF(py_import);
+ #endif
+ Py_XDECREF(empty_list);
+ Py_XDECREF(empty_dict);
+ return module;
+}
+
+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) {
+ const long neg_one = (long) -1, const_zero = 0;
const int is_unsigned = neg_one > const_zero;
if (is_unsigned) {
if (sizeof(long) < sizeof(long)) {
return PyInt_FromLong((long) value);
} else if (sizeof(long) <= sizeof(unsigned long)) {
return PyLong_FromUnsignedLong((unsigned long) value);
-#ifdef HAVE_LONG_LONG
- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
-#endif
+ } else if (sizeof(long) <= sizeof(unsigned long long)) {
+ return PyLong_FromUnsignedLongLong((unsigned long long) value);
}
} else {
if (sizeof(long) <= sizeof(long)) {
return PyInt_FromLong((long) value);
-#ifdef HAVE_LONG_LONG
- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
- return PyLong_FromLongLong((PY_LONG_LONG) value);
-#endif
+ } else if (sizeof(long) <= sizeof(long long)) {
+ return PyLong_FromLongLong((long long) value);
}
}
{
@@ -23279,49 +20750,138 @@ bad:
}
}
-/* CIntFromPyVerify */
- #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\
- __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0)
-#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\
- __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1)
-#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\
- {\
- func_type value = func_value;\
- if (sizeof(target_type) < sizeof(func_type)) {\
- if (unlikely(value != (func_type) (target_type) value)) {\
- func_type zero = 0;\
- if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\
- return (target_type) -1;\
- if (is_unsigned && unlikely(value < zero))\
- goto raise_neg_overflow;\
- else\
- goto raise_overflow;\
- }\
- }\
- return (target_type) value;\
- }
-
-/* CIntToPy */
- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) {
- const int neg_one = (int) -1, const_zero = (int) 0;
+#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value) \
+ { \
+ func_type value = func_value; \
+ if (sizeof(target_type) < sizeof(func_type)) { \
+ if (unlikely(value != (func_type) (target_type) value)) { \
+ func_type zero = 0; \
+ if (is_unsigned && unlikely(value < zero)) \
+ goto raise_neg_overflow; \
+ else \
+ goto raise_overflow; \
+ } \
+ } \
+ return (target_type) value; \
+ }
+
+#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
+ #if CYTHON_USE_PYLONG_INTERNALS
+ #include "longintrepr.h"
+ #endif
+#endif
+
+static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
+ const int neg_one = (int) -1, const_zero = 0;
+ const int is_unsigned = neg_one > const_zero;
+#if PY_MAJOR_VERSION < 3
+ if (likely(PyInt_Check(x))) {
+ if (sizeof(int) < sizeof(long)) {
+ __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x))
+ } else {
+ long val = PyInt_AS_LONG(x);
+ if (is_unsigned && unlikely(val < 0)) {
+ goto raise_neg_overflow;
+ }
+ return (int) val;
+ }
+ } else
+#endif
+ if (likely(PyLong_Check(x))) {
+ if (is_unsigned) {
+#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
+ #if CYTHON_USE_PYLONG_INTERNALS
+ switch (Py_SIZE(x)) {
+ case 0: return 0;
+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, ((PyLongObject*)x)->ob_digit[0]);
+ }
+ #endif
+#endif
+ if (unlikely(Py_SIZE(x) < 0)) {
+ goto raise_neg_overflow;
+ }
+ if (sizeof(int) <= sizeof(unsigned long)) {
+ __PYX_VERIFY_RETURN_INT(int, unsigned long, PyLong_AsUnsignedLong(x))
+ } else if (sizeof(int) <= sizeof(unsigned long long)) {
+ __PYX_VERIFY_RETURN_INT(int, unsigned long long, PyLong_AsUnsignedLongLong(x))
+ }
+ } else {
+#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
+ #if CYTHON_USE_PYLONG_INTERNALS
+ switch (Py_SIZE(x)) {
+ case 0: return 0;
+ case 1: __PYX_VERIFY_RETURN_INT(int, digit, +(((PyLongObject*)x)->ob_digit[0]));
+ case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, -(sdigit) ((PyLongObject*)x)->ob_digit[0]);
+ }
+ #endif
+#endif
+ if (sizeof(int) <= sizeof(long)) {
+ __PYX_VERIFY_RETURN_INT(int, long, PyLong_AsLong(x))
+ } else if (sizeof(int) <= sizeof(long long)) {
+ __PYX_VERIFY_RETURN_INT(int, long long, PyLong_AsLongLong(x))
+ }
+ }
+ {
+#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray)
+ PyErr_SetString(PyExc_RuntimeError,
+ "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers");
+#else
+ int val;
+ PyObject *v = __Pyx_PyNumber_Int(x);
+ #if PY_MAJOR_VERSION < 3
+ if (likely(v) && !PyLong_Check(v)) {
+ PyObject *tmp = v;
+ v = PyNumber_Long(tmp);
+ Py_DECREF(tmp);
+ }
+ #endif
+ if (likely(v)) {
+ int one = 1; int is_little = (int)*(unsigned char *)&one;
+ unsigned char *bytes = (unsigned char *)&val;
+ int ret = _PyLong_AsByteArray((PyLongObject *)v,
+ bytes, sizeof(val),
+ is_little, !is_unsigned);
+ Py_DECREF(v);
+ if (likely(!ret))
+ return val;
+ }
+#endif
+ return (int) -1;
+ }
+ } else {
+ int val;
+ PyObject *tmp = __Pyx_PyNumber_Int(x);
+ if (!tmp) return (int) -1;
+ val = __Pyx_PyInt_As_int(tmp);
+ Py_DECREF(tmp);
+ return val;
+ }
+raise_overflow:
+ PyErr_SetString(PyExc_OverflowError,
+ "value too large to convert to int");
+ return (int) -1;
+raise_neg_overflow:
+ PyErr_SetString(PyExc_OverflowError,
+ "can't convert negative value to int");
+ return (int) -1;
+}
+
+static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) {
+ const int neg_one = (int) -1, const_zero = 0;
const int is_unsigned = neg_one > const_zero;
if (is_unsigned) {
if (sizeof(int) < sizeof(long)) {
return PyInt_FromLong((long) value);
} else if (sizeof(int) <= sizeof(unsigned long)) {
return PyLong_FromUnsignedLong((unsigned long) value);
-#ifdef HAVE_LONG_LONG
- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) {
- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
-#endif
+ } else if (sizeof(int) <= sizeof(unsigned long long)) {
+ return PyLong_FromUnsignedLongLong((unsigned long long) value);
}
} else {
if (sizeof(int) <= sizeof(long)) {
return PyInt_FromLong((long) value);
-#ifdef HAVE_LONG_LONG
- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) {
- return PyLong_FromLongLong((PY_LONG_LONG) value);
-#endif
+ } else if (sizeof(int) <= sizeof(long long)) {
+ return PyLong_FromLongLong((long long) value);
}
}
{
@@ -23332,8 +20892,102 @@ bad:
}
}
-/* Declarations */
- #if CYTHON_CCOMPLEX
+static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
+ const long neg_one = (long) -1, const_zero = 0;
+ const int is_unsigned = neg_one > const_zero;
+#if PY_MAJOR_VERSION < 3
+ if (likely(PyInt_Check(x))) {
+ if (sizeof(long) < sizeof(long)) {
+ __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x))
+ } else {
+ long val = PyInt_AS_LONG(x);
+ if (is_unsigned && unlikely(val < 0)) {
+ goto raise_neg_overflow;
+ }
+ return (long) val;
+ }
+ } else
+#endif
+ if (likely(PyLong_Check(x))) {
+ if (is_unsigned) {
+#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
+ #if CYTHON_USE_PYLONG_INTERNALS
+ switch (Py_SIZE(x)) {
+ case 0: return 0;
+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, ((PyLongObject*)x)->ob_digit[0]);
+ }
+ #endif
+#endif
+ if (unlikely(Py_SIZE(x) < 0)) {
+ goto raise_neg_overflow;
+ }
+ if (sizeof(long) <= sizeof(unsigned long)) {
+ __PYX_VERIFY_RETURN_INT(long, unsigned long, PyLong_AsUnsignedLong(x))
+ } else if (sizeof(long) <= sizeof(unsigned long long)) {
+ __PYX_VERIFY_RETURN_INT(long, unsigned long long, PyLong_AsUnsignedLongLong(x))
+ }
+ } else {
+#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
+ #if CYTHON_USE_PYLONG_INTERNALS
+ switch (Py_SIZE(x)) {
+ case 0: return 0;
+ case 1: __PYX_VERIFY_RETURN_INT(long, digit, +(((PyLongObject*)x)->ob_digit[0]));
+ case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, -(sdigit) ((PyLongObject*)x)->ob_digit[0]);
+ }
+ #endif
+#endif
+ if (sizeof(long) <= sizeof(long)) {
+ __PYX_VERIFY_RETURN_INT(long, long, PyLong_AsLong(x))
+ } else if (sizeof(long) <= sizeof(long long)) {
+ __PYX_VERIFY_RETURN_INT(long, long long, PyLong_AsLongLong(x))
+ }
+ }
+ {
+#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray)
+ PyErr_SetString(PyExc_RuntimeError,
+ "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers");
+#else
+ long val;
+ PyObject *v = __Pyx_PyNumber_Int(x);
+ #if PY_MAJOR_VERSION < 3
+ if (likely(v) && !PyLong_Check(v)) {
+ PyObject *tmp = v;
+ v = PyNumber_Long(tmp);
+ Py_DECREF(tmp);
+ }
+ #endif
+ if (likely(v)) {
+ int one = 1; int is_little = (int)*(unsigned char *)&one;
+ unsigned char *bytes = (unsigned char *)&val;
+ int ret = _PyLong_AsByteArray((PyLongObject *)v,
+ bytes, sizeof(val),
+ is_little, !is_unsigned);
+ Py_DECREF(v);
+ if (likely(!ret))
+ return val;
+ }
+#endif
+ return (long) -1;
+ }
+ } else {
+ long val;
+ PyObject *tmp = __Pyx_PyNumber_Int(x);
+ if (!tmp) return (long) -1;
+ val = __Pyx_PyInt_As_long(tmp);
+ Py_DECREF(tmp);
+ return val;
+ }
+raise_overflow:
+ PyErr_SetString(PyExc_OverflowError,
+ "value too large to convert to long");
+ return (long) -1;
+raise_neg_overflow:
+ PyErr_SetString(PyExc_OverflowError,
+ "can't convert negative value to long");
+ return (long) -1;
+}
+
+#if CYTHON_CCOMPLEX
#ifdef __cplusplus
static CYTHON_INLINE __pyx_t_float_complex __pyx_t_float_complex_from_parts(float x, float y) {
return ::std::complex< float >(x, y);
@@ -23352,86 +21006,60 @@ bad:
}
#endif
-/* Arithmetic */
- #if CYTHON_CCOMPLEX
+#if CYTHON_CCOMPLEX
#else
- static CYTHON_INLINE int __Pyx_c_eq_float(__pyx_t_float_complex a, __pyx_t_float_complex b) {
+ static CYTHON_INLINE int __Pyx_c_eqf(__pyx_t_float_complex a, __pyx_t_float_complex b) {
return (a.real == b.real) && (a.imag == b.imag);
}
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_sum_float(__pyx_t_float_complex a, __pyx_t_float_complex b) {
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_sumf(__pyx_t_float_complex a, __pyx_t_float_complex b) {
__pyx_t_float_complex z;
z.real = a.real + b.real;
z.imag = a.imag + b.imag;
return z;
}
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_diff_float(__pyx_t_float_complex a, __pyx_t_float_complex b) {
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_difff(__pyx_t_float_complex a, __pyx_t_float_complex b) {
__pyx_t_float_complex z;
z.real = a.real - b.real;
z.imag = a.imag - b.imag;
return z;
}
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_prod_float(__pyx_t_float_complex a, __pyx_t_float_complex b) {
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_prodf(__pyx_t_float_complex a, __pyx_t_float_complex b) {
__pyx_t_float_complex z;
z.real = a.real * b.real - a.imag * b.imag;
z.imag = a.real * b.imag + a.imag * b.real;
return z;
}
- #if 1
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_quot_float(__pyx_t_float_complex a, __pyx_t_float_complex b) {
- if (b.imag == 0) {
- return __pyx_t_float_complex_from_parts(a.real / b.real, a.imag / b.real);
- } else if (fabsf(b.real) >= fabsf(b.imag)) {
- if (b.real == 0 && b.imag == 0) {
- return __pyx_t_float_complex_from_parts(a.real / b.real, a.imag / b.imag);
- } else {
- float r = b.imag / b.real;
- float s = 1.0 / (b.real + b.imag * r);
- return __pyx_t_float_complex_from_parts(
- (a.real + a.imag * r) * s, (a.imag - a.real * r) * s);
- }
- } else {
- float r = b.real / b.imag;
- float s = 1.0 / (b.imag + b.real * r);
- return __pyx_t_float_complex_from_parts(
- (a.real * r + a.imag) * s, (a.imag * r - a.real) * s);
- }
- }
- #else
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_quot_float(__pyx_t_float_complex a, __pyx_t_float_complex b) {
- if (b.imag == 0) {
- return __pyx_t_float_complex_from_parts(a.real / b.real, a.imag / b.real);
- } else {
- float denom = b.real * b.real + b.imag * b.imag;
- return __pyx_t_float_complex_from_parts(
- (a.real * b.real + a.imag * b.imag) / denom,
- (a.imag * b.real - a.real * b.imag) / denom);
- }
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_quotf(__pyx_t_float_complex a, __pyx_t_float_complex b) {
+ __pyx_t_float_complex z;
+ float denom = b.real * b.real + b.imag * b.imag;
+ z.real = (a.real * b.real + a.imag * b.imag) / denom;
+ z.imag = (a.imag * b.real - a.real * b.imag) / denom;
+ return z;
}
- #endif
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_neg_float(__pyx_t_float_complex a) {
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_negf(__pyx_t_float_complex a) {
__pyx_t_float_complex z;
z.real = -a.real;
z.imag = -a.imag;
return z;
}
- static CYTHON_INLINE int __Pyx_c_is_zero_float(__pyx_t_float_complex a) {
+ static CYTHON_INLINE int __Pyx_c_is_zerof(__pyx_t_float_complex a) {
return (a.real == 0) && (a.imag == 0);
}
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_conj_float(__pyx_t_float_complex a) {
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_conjf(__pyx_t_float_complex a) {
__pyx_t_float_complex z;
z.real = a.real;
z.imag = -a.imag;
return z;
}
#if 1
- static CYTHON_INLINE float __Pyx_c_abs_float(__pyx_t_float_complex z) {
+ static CYTHON_INLINE float __Pyx_c_absf(__pyx_t_float_complex z) {
#if !defined(HAVE_HYPOT) || defined(_MSC_VER)
return sqrtf(z.real*z.real + z.imag*z.imag);
#else
return hypotf(z.real, z.imag);
#endif
}
- static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_pow_float(__pyx_t_float_complex a, __pyx_t_float_complex b) {
+ static CYTHON_INLINE __pyx_t_float_complex __Pyx_c_powf(__pyx_t_float_complex a, __pyx_t_float_complex b) {
__pyx_t_float_complex z;
float r, lnr, theta, z_r, z_theta;
if (b.imag == 0 && b.real == (int)b.real) {
@@ -23449,32 +21077,24 @@ bad:
case 1:
return a;
case 2:
- z = __Pyx_c_prod_float(a, a);
- return __Pyx_c_prod_float(a, a);
+ z = __Pyx_c_prodf(a, a);
+ return __Pyx_c_prodf(a, a);
case 3:
- z = __Pyx_c_prod_float(a, a);
- return __Pyx_c_prod_float(z, a);
+ z = __Pyx_c_prodf(a, a);
+ return __Pyx_c_prodf(z, a);
case 4:
- z = __Pyx_c_prod_float(a, a);
- return __Pyx_c_prod_float(z, z);
+ z = __Pyx_c_prodf(a, a);
+ return __Pyx_c_prodf(z, z);
}
}
if (a.imag == 0) {
if (a.real == 0) {
return a;
- } else if (b.imag == 0) {
- z.real = powf(a.real, b.real);
- z.imag = 0;
- return z;
- } else if (a.real > 0) {
- r = a.real;
- theta = 0;
- } else {
- r = -a.real;
- theta = atan2f(0, -1);
}
+ r = a.real;
+ theta = 0;
} else {
- r = __Pyx_c_abs_float(a);
+ r = __Pyx_c_absf(a);
theta = atan2f(a.imag, a.real);
}
lnr = logf(r);
@@ -23487,8 +21107,7 @@ bad:
#endif
#endif
-/* Declarations */
- #if CYTHON_CCOMPLEX
+#if CYTHON_CCOMPLEX
#ifdef __cplusplus
static CYTHON_INLINE __pyx_t_double_complex __pyx_t_double_complex_from_parts(double x, double y) {
return ::std::complex< double >(x, y);
@@ -23507,86 +21126,60 @@ bad:
}
#endif
-/* Arithmetic */
- #if CYTHON_CCOMPLEX
+#if CYTHON_CCOMPLEX
#else
- static CYTHON_INLINE int __Pyx_c_eq_double(__pyx_t_double_complex a, __pyx_t_double_complex b) {
+ static CYTHON_INLINE int __Pyx_c_eq(__pyx_t_double_complex a, __pyx_t_double_complex b) {
return (a.real == b.real) && (a.imag == b.imag);
}
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_sum_double(__pyx_t_double_complex a, __pyx_t_double_complex b) {
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_sum(__pyx_t_double_complex a, __pyx_t_double_complex b) {
__pyx_t_double_complex z;
z.real = a.real + b.real;
z.imag = a.imag + b.imag;
return z;
}
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_diff_double(__pyx_t_double_complex a, __pyx_t_double_complex b) {
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_diff(__pyx_t_double_complex a, __pyx_t_double_complex b) {
__pyx_t_double_complex z;
z.real = a.real - b.real;
z.imag = a.imag - b.imag;
return z;
}
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_prod_double(__pyx_t_double_complex a, __pyx_t_double_complex b) {
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_prod(__pyx_t_double_complex a, __pyx_t_double_complex b) {
__pyx_t_double_complex z;
z.real = a.real * b.real - a.imag * b.imag;
z.imag = a.real * b.imag + a.imag * b.real;
return z;
}
- #if 1
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_quot_double(__pyx_t_double_complex a, __pyx_t_double_complex b) {
- if (b.imag == 0) {
- return __pyx_t_double_complex_from_parts(a.real / b.real, a.imag / b.real);
- } else if (fabs(b.real) >= fabs(b.imag)) {
- if (b.real == 0 && b.imag == 0) {
- return __pyx_t_double_complex_from_parts(a.real / b.real, a.imag / b.imag);
- } else {
- double r = b.imag / b.real;
- double s = 1.0 / (b.real + b.imag * r);
- return __pyx_t_double_complex_from_parts(
- (a.real + a.imag * r) * s, (a.imag - a.real * r) * s);
- }
- } else {
- double r = b.real / b.imag;
- double s = 1.0 / (b.imag + b.real * r);
- return __pyx_t_double_complex_from_parts(
- (a.real * r + a.imag) * s, (a.imag * r - a.real) * s);
- }
- }
- #else
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_quot_double(__pyx_t_double_complex a, __pyx_t_double_complex b) {
- if (b.imag == 0) {
- return __pyx_t_double_complex_from_parts(a.real / b.real, a.imag / b.real);
- } else {
- double denom = b.real * b.real + b.imag * b.imag;
- return __pyx_t_double_complex_from_parts(
- (a.real * b.real + a.imag * b.imag) / denom,
- (a.imag * b.real - a.real * b.imag) / denom);
- }
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_quot(__pyx_t_double_complex a, __pyx_t_double_complex b) {
+ __pyx_t_double_complex z;
+ double denom = b.real * b.real + b.imag * b.imag;
+ z.real = (a.real * b.real + a.imag * b.imag) / denom;
+ z.imag = (a.imag * b.real - a.real * b.imag) / denom;
+ return z;
}
- #endif
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_neg_double(__pyx_t_double_complex a) {
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_neg(__pyx_t_double_complex a) {
__pyx_t_double_complex z;
z.real = -a.real;
z.imag = -a.imag;
return z;
}
- static CYTHON_INLINE int __Pyx_c_is_zero_double(__pyx_t_double_complex a) {
+ static CYTHON_INLINE int __Pyx_c_is_zero(__pyx_t_double_complex a) {
return (a.real == 0) && (a.imag == 0);
}
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_conj_double(__pyx_t_double_complex a) {
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_conj(__pyx_t_double_complex a) {
__pyx_t_double_complex z;
z.real = a.real;
z.imag = -a.imag;
return z;
}
#if 1
- static CYTHON_INLINE double __Pyx_c_abs_double(__pyx_t_double_complex z) {
+ static CYTHON_INLINE double __Pyx_c_abs(__pyx_t_double_complex z) {
#if !defined(HAVE_HYPOT) || defined(_MSC_VER)
return sqrt(z.real*z.real + z.imag*z.imag);
#else
return hypot(z.real, z.imag);
#endif
}
- static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_pow_double(__pyx_t_double_complex a, __pyx_t_double_complex b) {
+ static CYTHON_INLINE __pyx_t_double_complex __Pyx_c_pow(__pyx_t_double_complex a, __pyx_t_double_complex b) {
__pyx_t_double_complex z;
double r, lnr, theta, z_r, z_theta;
if (b.imag == 0 && b.real == (int)b.real) {
@@ -23604,32 +21197,24 @@ bad:
case 1:
return a;
case 2:
- z = __Pyx_c_prod_double(a, a);
- return __Pyx_c_prod_double(a, a);
+ z = __Pyx_c_prod(a, a);
+ return __Pyx_c_prod(a, a);
case 3:
- z = __Pyx_c_prod_double(a, a);
- return __Pyx_c_prod_double(z, a);
+ z = __Pyx_c_prod(a, a);
+ return __Pyx_c_prod(z, a);
case 4:
- z = __Pyx_c_prod_double(a, a);
- return __Pyx_c_prod_double(z, z);
+ z = __Pyx_c_prod(a, a);
+ return __Pyx_c_prod(z, z);
}
}
if (a.imag == 0) {
if (a.real == 0) {
return a;
- } else if (b.imag == 0) {
- z.real = pow(a.real, b.real);
- z.imag = 0;
- return z;
- } else if (a.real > 0) {
- r = a.real;
- theta = 0;
- } else {
- r = -a.real;
- theta = atan2(0, -1);
}
+ r = a.real;
+ theta = 0;
} else {
- r = __Pyx_c_abs_double(a);
+ r = __Pyx_c_abs(a);
theta = atan2(a.imag, a.real);
}
lnr = log(r);
@@ -23642,453 +21227,36 @@ bad:
#endif
#endif
-/* CIntToPy */
- static CYTHON_INLINE PyObject* __Pyx_PyInt_From_enum__NPY_TYPES(enum NPY_TYPES value) {
- const enum NPY_TYPES neg_one = (enum NPY_TYPES) -1, const_zero = (enum NPY_TYPES) 0;
- const int is_unsigned = neg_one > const_zero;
- if (is_unsigned) {
- if (sizeof(enum NPY_TYPES) < sizeof(long)) {
- return PyInt_FromLong((long) value);
- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned long)) {
- return PyLong_FromUnsignedLong((unsigned long) value);
-#ifdef HAVE_LONG_LONG
- } else if (sizeof(enum NPY_TYPES) <= sizeof(unsigned PY_LONG_LONG)) {
- return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
-#endif
- }
- } else {
- if (sizeof(enum NPY_TYPES) <= sizeof(long)) {
- return PyInt_FromLong((long) value);
-#ifdef HAVE_LONG_LONG
- } else if (sizeof(enum NPY_TYPES) <= sizeof(PY_LONG_LONG)) {
- return PyLong_FromLongLong((PY_LONG_LONG) value);
-#endif
- }
- }
- {
- int one = 1; int little = (int)*(unsigned char *)&one;
- unsigned char *bytes = (unsigned char *)&value;
- return _PyLong_FromByteArray(bytes, sizeof(enum NPY_TYPES),
- little, !is_unsigned);
- }
-}
-
-/* CIntFromPy */
- static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) {
- const int neg_one = (int) -1, const_zero = (int) 0;
- const int is_unsigned = neg_one > const_zero;
-#if PY_MAJOR_VERSION < 3
- if (likely(PyInt_Check(x))) {
- if (sizeof(int) < sizeof(long)) {
- __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x))
- } else {
- long val = PyInt_AS_LONG(x);
- if (is_unsigned && unlikely(val < 0)) {
- goto raise_neg_overflow;
- }
- return (int) val;
- }
- } else
-#endif
- if (likely(PyLong_Check(x))) {
- if (is_unsigned) {
-#if CYTHON_USE_PYLONG_INTERNALS
- const digit* digits = ((PyLongObject*)x)->ob_digit;
- switch (Py_SIZE(x)) {
- case 0: return (int) 0;
- case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0])
- case 2:
- if (8 * sizeof(int) > 1 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) {
- return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]));
- }
- }
- break;
- case 3:
- if (8 * sizeof(int) > 2 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) {
- return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]));
- }
- }
- break;
- case 4:
- if (8 * sizeof(int) > 3 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) {
- return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]));
- }
- }
- break;
- }
-#endif
-#if CYTHON_COMPILING_IN_CPYTHON
- if (unlikely(Py_SIZE(x) < 0)) {
- goto raise_neg_overflow;
- }
-#else
- {
- int result = PyObject_RichCompareBool(x, Py_False, Py_LT);
- if (unlikely(result < 0))
- return (int) -1;
- if (unlikely(result == 1))
- goto raise_neg_overflow;
- }
-#endif
- if (sizeof(int) <= sizeof(unsigned long)) {
- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x))
-#ifdef HAVE_LONG_LONG
- } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) {
- __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x))
-#endif
- }
- } else {
-#if CYTHON_USE_PYLONG_INTERNALS
- const digit* digits = ((PyLongObject*)x)->ob_digit;
- switch (Py_SIZE(x)) {
- case 0: return (int) 0;
- case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0]))
- case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0])
- case -2:
- if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) {
- return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
- }
- }
- break;
- case 2:
- if (8 * sizeof(int) > 1 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) {
- return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
- }
- }
- break;
- case -3:
- if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) {
- return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
- }
- }
- break;
- case 3:
- if (8 * sizeof(int) > 2 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) {
- return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
- }
- }
- break;
- case -4:
- if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) {
- return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
- }
- }
- break;
- case 4:
- if (8 * sizeof(int) > 3 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) {
- return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])));
- }
- }
- break;
- }
-#endif
- if (sizeof(int) <= sizeof(long)) {
- __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x))
-#ifdef HAVE_LONG_LONG
- } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) {
- __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x))
-#endif
- }
- }
- {
-#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray)
- PyErr_SetString(PyExc_RuntimeError,
- "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers");
-#else
- int val;
- PyObject *v = __Pyx_PyNumber_IntOrLong(x);
- #if PY_MAJOR_VERSION < 3
- if (likely(v) && !PyLong_Check(v)) {
- PyObject *tmp = v;
- v = PyNumber_Long(tmp);
- Py_DECREF(tmp);
- }
- #endif
- if (likely(v)) {
- int one = 1; int is_little = (int)*(unsigned char *)&one;
- unsigned char *bytes = (unsigned char *)&val;
- int ret = _PyLong_AsByteArray((PyLongObject *)v,
- bytes, sizeof(val),
- is_little, !is_unsigned);
- Py_DECREF(v);
- if (likely(!ret))
- return val;
- }
-#endif
- return (int) -1;
- }
- } else {
- int val;
- PyObject *tmp = __Pyx_PyNumber_IntOrLong(x);
- if (!tmp) return (int) -1;
- val = __Pyx_PyInt_As_int(tmp);
- Py_DECREF(tmp);
- return val;
- }
-raise_overflow:
- PyErr_SetString(PyExc_OverflowError,
- "value too large to convert to int");
- return (int) -1;
-raise_neg_overflow:
- PyErr_SetString(PyExc_OverflowError,
- "can't convert negative value to int");
- return (int) -1;
-}
-
-/* CIntFromPy */
- static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) {
- const long neg_one = (long) -1, const_zero = (long) 0;
- const int is_unsigned = neg_one > const_zero;
-#if PY_MAJOR_VERSION < 3
- if (likely(PyInt_Check(x))) {
- if (sizeof(long) < sizeof(long)) {
- __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x))
- } else {
- long val = PyInt_AS_LONG(x);
- if (is_unsigned && unlikely(val < 0)) {
- goto raise_neg_overflow;
- }
- return (long) val;
- }
- } else
-#endif
- if (likely(PyLong_Check(x))) {
- if (is_unsigned) {
-#if CYTHON_USE_PYLONG_INTERNALS
- const digit* digits = ((PyLongObject*)x)->ob_digit;
- switch (Py_SIZE(x)) {
- case 0: return (long) 0;
- case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0])
- case 2:
- if (8 * sizeof(long) > 1 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) {
- return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]));
- }
- }
- break;
- case 3:
- if (8 * sizeof(long) > 2 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) {
- return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]));
- }
- }
- break;
- case 4:
- if (8 * sizeof(long) > 3 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) {
- return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]));
- }
- }
- break;
- }
-#endif
-#if CYTHON_COMPILING_IN_CPYTHON
- if (unlikely(Py_SIZE(x) < 0)) {
- goto raise_neg_overflow;
- }
-#else
- {
- int result = PyObject_RichCompareBool(x, Py_False, Py_LT);
- if (unlikely(result < 0))
- return (long) -1;
- if (unlikely(result == 1))
- goto raise_neg_overflow;
- }
-#endif
- if (sizeof(long) <= sizeof(unsigned long)) {
- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x))
-#ifdef HAVE_LONG_LONG
- } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
- __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x))
-#endif
- }
- } else {
-#if CYTHON_USE_PYLONG_INTERNALS
- const digit* digits = ((PyLongObject*)x)->ob_digit;
- switch (Py_SIZE(x)) {
- case 0: return (long) 0;
- case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0]))
- case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0])
- case -2:
- if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
- return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
- }
- }
- break;
- case 2:
- if (8 * sizeof(long) > 1 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
- return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
- }
- }
- break;
- case -3:
- if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
- return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
- }
- }
- break;
- case 3:
- if (8 * sizeof(long) > 2 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
- return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
- }
- }
- break;
- case -4:
- if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
- return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
- }
- }
- break;
- case 4:
- if (8 * sizeof(long) > 3 * PyLong_SHIFT) {
- if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) {
- __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])))
- } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) {
- return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])));
- }
- }
- break;
- }
-#endif
- if (sizeof(long) <= sizeof(long)) {
- __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x))
-#ifdef HAVE_LONG_LONG
- } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) {
- __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x))
-#endif
- }
- }
- {
-#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray)
- PyErr_SetString(PyExc_RuntimeError,
- "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers");
-#else
- long val;
- PyObject *v = __Pyx_PyNumber_IntOrLong(x);
- #if PY_MAJOR_VERSION < 3
- if (likely(v) && !PyLong_Check(v)) {
- PyObject *tmp = v;
- v = PyNumber_Long(tmp);
- Py_DECREF(tmp);
- }
- #endif
- if (likely(v)) {
- int one = 1; int is_little = (int)*(unsigned char *)&one;
- unsigned char *bytes = (unsigned char *)&val;
- int ret = _PyLong_AsByteArray((PyLongObject *)v,
- bytes, sizeof(val),
- is_little, !is_unsigned);
- Py_DECREF(v);
- if (likely(!ret))
- return val;
- }
-#endif
- return (long) -1;
- }
- } else {
- long val;
- PyObject *tmp = __Pyx_PyNumber_IntOrLong(x);
- if (!tmp) return (long) -1;
- val = __Pyx_PyInt_As_long(tmp);
- Py_DECREF(tmp);
- return val;
- }
-raise_overflow:
- PyErr_SetString(PyExc_OverflowError,
- "value too large to convert to long");
- return (long) -1;
-raise_neg_overflow:
- PyErr_SetString(PyExc_OverflowError,
- "can't convert negative value to long");
- return (long) -1;
-}
-
-/* SwapException */
- #if CYTHON_FAST_THREAD_STATE
-static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
+static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
+#if CYTHON_COMPILING_IN_CPYTHON
+ PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = *type;
tstate->exc_value = *value;
tstate->exc_traceback = *tb;
- *type = tmp_type;
- *value = tmp_value;
- *tb = tmp_tb;
-}
#else
-static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) {
- PyObject *tmp_type, *tmp_value, *tmp_tb;
PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb);
PyErr_SetExcInfo(*type, *value, *tb);
+#endif
*type = tmp_type;
*value = tmp_value;
*tb = tmp_tb;
}
-#endif
-/* CoroutineBase */
- #include <structmember.h>
-#include <frameobject.h>
-static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value);
-static PyObject *__Pyx_Coroutine_Close(PyObject *self);
-static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args);
-#define __Pyx_Coroutine_Undelegate(gen) Py_CLEAR((gen)->yieldfrom)
+static PyObject *__Pyx_Generator_Next(PyObject *self);
+static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value);
+static PyObject *__Pyx_Generator_Close(PyObject *self);
+static PyObject *__Pyx_Generator_Throw(PyObject *gen, PyObject *args);
+static PyTypeObject *__pyx_GeneratorType = 0;
+#define __Pyx_Generator_CheckExact(obj) (Py_TYPE(obj) == __pyx_GeneratorType)
+#define __Pyx_Generator_Undelegate(gen) Py_CLEAR((gen)->yieldfrom)
#if 1 || PY_VERSION_HEX < 0x030300B0
static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) {
PyObject *et, *ev, *tb;
PyObject *value = NULL;
- __Pyx_PyThreadState_declare
- __Pyx_PyThreadState_assign
__Pyx_ErrFetch(&et, &ev, &tb);
if (!et) {
Py_XDECREF(tb);
@@ -24097,47 +21265,25 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) {
*pvalue = Py_None;
return 0;
}
+ if (unlikely(et != PyExc_StopIteration) &&
+ unlikely(!PyErr_GivenExceptionMatches(et, PyExc_StopIteration))) {
+ __Pyx_ErrRestore(et, ev, tb);
+ return -1;
+ }
if (likely(et == PyExc_StopIteration)) {
- if (!ev) {
- Py_INCREF(Py_None);
- value = Py_None;
- }
-#if PY_VERSION_HEX >= 0x030300A0
- else if (Py_TYPE(ev) == (PyTypeObject*)PyExc_StopIteration) {
- value = ((PyStopIterationObject *)ev)->value;
- Py_INCREF(value);
- Py_DECREF(ev);
- }
-#endif
- else if (unlikely(PyTuple_Check(ev))) {
- if (PyTuple_GET_SIZE(ev) >= 1) {
-#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- value = PyTuple_GET_ITEM(ev, 0);
- Py_INCREF(value);
-#else
- value = PySequence_ITEM(ev, 0);
-#endif
- } else {
+ if (likely(!ev) || !PyObject_IsInstance(ev, PyExc_StopIteration)) {
+ if (!ev) {
Py_INCREF(Py_None);
- value = Py_None;
+ ev = Py_None;
}
- Py_DECREF(ev);
- }
- else if (!PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) {
- value = ev;
- }
- if (likely(value)) {
Py_XDECREF(tb);
Py_DECREF(et);
- *pvalue = value;
+ *pvalue = ev;
return 0;
}
- } else if (!PyErr_GivenExceptionMatches(et, PyExc_StopIteration)) {
- __Pyx_ErrRestore(et, ev, tb);
- return -1;
}
PyErr_NormalizeException(&et, &ev, &tb);
- if (unlikely(!PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration))) {
+ if (unlikely(!PyObject_IsInstance(ev, PyExc_StopIteration))) {
__Pyx_ErrRestore(et, ev, tb);
return -1;
}
@@ -24149,10 +21295,10 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) {
Py_DECREF(ev);
#else
{
- PyObject* args = __Pyx_PyObject_GetAttrStr(ev, __pyx_n_s_args);
+ PyObject* args = PyObject_GetAttr(ev, __pyx_n_s_args);
Py_DECREF(ev);
if (likely(args)) {
- value = PySequence_GetItem(args, 0);
+ value = PyObject_GetItem(args, 0);
Py_DECREF(args);
}
if (unlikely(!value)) {
@@ -24167,7 +21313,7 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) {
}
#endif
static CYTHON_INLINE
-void __Pyx_Coroutine_ExceptionClear(__pyx_CoroutineObject *self) {
+void __Pyx_Generator_ExceptionClear(__pyx_GeneratorObject *self) {
PyObject *exc_type = self->exc_type;
PyObject *exc_value = self->exc_value;
PyObject *exc_traceback = self->exc_traceback;
@@ -24179,7 +21325,7 @@ void __Pyx_Coroutine_ExceptionClear(__pyx_CoroutineObject *self) {
Py_XDECREF(exc_traceback);
}
static CYTHON_INLINE
-int __Pyx_Coroutine_CheckRunning(__pyx_CoroutineObject *gen) {
+int __Pyx_Generator_CheckRunning(__pyx_GeneratorObject *gen) {
if (unlikely(gen->is_running)) {
PyErr_SetString(PyExc_ValueError,
"generator already executing");
@@ -24188,9 +21334,8 @@ int __Pyx_Coroutine_CheckRunning(__pyx_CoroutineObject *gen) {
return 0;
}
static CYTHON_INLINE
-PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
+PyObject *__Pyx_Generator_SendEx(__pyx_GeneratorObject *self, PyObject *value) {
PyObject *retval;
- __Pyx_PyThreadState_declare
assert(!self->is_running);
if (unlikely(self->resume_label == 0)) {
if (unlikely(value && value != Py_None)) {
@@ -24204,22 +21349,22 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
- __Pyx_PyThreadState_assign
if (value) {
-#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON
+#if CYTHON_COMPILING_IN_PYPY
#else
if (self->exc_traceback) {
+ PyThreadState *tstate = PyThreadState_GET();
PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback;
PyFrameObject *f = tb->tb_frame;
- Py_XINCREF(__pyx_tstate->frame);
+ Py_XINCREF(tstate->frame);
assert(f->f_back == NULL);
- f->f_back = __pyx_tstate->frame;
+ f->f_back = tstate->frame;
}
#endif
__Pyx_ExceptionSwap(&self->exc_type, &self->exc_value,
&self->exc_traceback);
} else {
- __Pyx_Coroutine_ExceptionClear(self);
+ __Pyx_Generator_ExceptionClear(self);
}
self->is_running = 1;
retval = self->body((PyObject *) self, value);
@@ -24227,7 +21372,7 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
if (retval) {
__Pyx_ExceptionSwap(&self->exc_type, &self->exc_value,
&self->exc_traceback);
-#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_PYSTON
+#if CYTHON_COMPILING_IN_PYPY
#else
if (self->exc_traceback) {
PyTracebackObject *tb = (PyTracebackObject *) self->exc_traceback;
@@ -24236,49 +21381,50 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
}
#endif
} else {
- __Pyx_Coroutine_ExceptionClear(self);
- }
- return retval;
-}
-static CYTHON_INLINE
-PyObject *__Pyx_Coroutine_MethodReturn(PyObject *retval) {
- if (unlikely(!retval && !PyErr_Occurred())) {
- PyErr_SetNone(PyExc_StopIteration);
+ __Pyx_Generator_ExceptionClear(self);
}
return retval;
}
static CYTHON_INLINE
-PyObject *__Pyx_Coroutine_FinishDelegation(__pyx_CoroutineObject *gen) {
+PyObject *__Pyx_Generator_FinishDelegation(__pyx_GeneratorObject *gen) {
PyObject *ret;
PyObject *val = NULL;
- __Pyx_Coroutine_Undelegate(gen);
+ __Pyx_Generator_Undelegate(gen);
__Pyx_PyGen_FetchStopIterationValue(&val);
- ret = __Pyx_Coroutine_SendEx(gen, val);
+ ret = __Pyx_Generator_SendEx(gen, val);
Py_XDECREF(val);
return ret;
}
-static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
- PyObject *retval;
- __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self;
+static PyObject *__Pyx_Generator_Next(PyObject *self) {
+ __pyx_GeneratorObject *gen = (__pyx_GeneratorObject*) self;
PyObject *yf = gen->yieldfrom;
- if (unlikely(__Pyx_Coroutine_CheckRunning(gen)))
+ if (unlikely(__Pyx_Generator_CheckRunning(gen)))
+ return NULL;
+ if (yf) {
+ PyObject *ret;
+ gen->is_running = 1;
+ ret = Py_TYPE(yf)->tp_iternext(yf);
+ gen->is_running = 0;
+ if (likely(ret)) {
+ return ret;
+ }
+ return __Pyx_Generator_FinishDelegation(gen);
+ }
+ return __Pyx_Generator_SendEx(gen, Py_None);
+}
+static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value) {
+ __pyx_GeneratorObject *gen = (__pyx_GeneratorObject*) self;
+ PyObject *yf = gen->yieldfrom;
+ if (unlikely(__Pyx_Generator_CheckRunning(gen)))
return NULL;
if (yf) {
PyObject *ret;
gen->is_running = 1;
- #ifdef __Pyx_Generator_USED
if (__Pyx_Generator_CheckExact(yf)) {
- ret = __Pyx_Coroutine_Send(yf, value);
- } else
- #endif
- #ifdef __Pyx_Coroutine_USED
- if (__Pyx_Coroutine_CheckExact(yf)) {
- ret = __Pyx_Coroutine_Send(yf, value);
- } else
- #endif
- {
+ ret = __Pyx_Generator_Send(yf, value);
+ } else {
if (value == Py_None)
- ret = Py_TYPE(yf)->tp_iternext(yf);
+ ret = PyIter_Next(yf);
else
ret = __Pyx_PyObject_CallMethod1(yf, __pyx_n_s_send, value);
}
@@ -24286,33 +21432,21 @@ static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
if (likely(ret)) {
return ret;
}
- retval = __Pyx_Coroutine_FinishDelegation(gen);
- } else {
- retval = __Pyx_Coroutine_SendEx(gen, value);
+ return __Pyx_Generator_FinishDelegation(gen);
}
- return __Pyx_Coroutine_MethodReturn(retval);
+ return __Pyx_Generator_SendEx(gen, value);
}
-static int __Pyx_Coroutine_CloseIter(__pyx_CoroutineObject *gen, PyObject *yf) {
+static int __Pyx_Generator_CloseIter(__pyx_GeneratorObject *gen, PyObject *yf) {
PyObject *retval = NULL;
int err = 0;
- #ifdef __Pyx_Generator_USED
if (__Pyx_Generator_CheckExact(yf)) {
- retval = __Pyx_Coroutine_Close(yf);
+ retval = __Pyx_Generator_Close(yf);
if (!retval)
return -1;
- } else
- #endif
- #ifdef __Pyx_Coroutine_USED
- if (__Pyx_Coroutine_CheckExact(yf)) {
- retval = __Pyx_Coroutine_Close(yf);
- if (!retval)
- return -1;
- } else
- #endif
- {
+ } else {
PyObject *meth;
gen->is_running = 1;
- meth = __Pyx_PyObject_GetAttrStr(yf, __pyx_n_s_close);
+ meth = PyObject_GetAttr(yf, __pyx_n_s_close);
if (unlikely(!meth)) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_WriteUnraisable(yf);
@@ -24329,44 +21463,22 @@ static int __Pyx_Coroutine_CloseIter(__pyx_CoroutineObject *gen, PyObject *yf) {
Py_XDECREF(retval);
return err;
}
-static PyObject *__Pyx_Generator_Next(PyObject *self) {
- __pyx_CoroutineObject *gen = (__pyx_CoroutineObject*) self;
- PyObject *yf = gen->yieldfrom;
- if (unlikely(__Pyx_Coroutine_CheckRunning(gen)))
- return NULL;
- if (yf) {
- PyObject *ret;
- gen->is_running = 1;
- #ifdef __Pyx_Generator_USED
- if (__Pyx_Generator_CheckExact(yf)) {
- ret = __Pyx_Generator_Next(yf);
- } else
- #endif
- ret = Py_TYPE(yf)->tp_iternext(yf);
- gen->is_running = 0;
- if (likely(ret)) {
- return ret;
- }
- return __Pyx_Coroutine_FinishDelegation(gen);
- }
- return __Pyx_Coroutine_SendEx(gen, Py_None);
-}
-static PyObject *__Pyx_Coroutine_Close(PyObject *self) {
- __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self;
+static PyObject *__Pyx_Generator_Close(PyObject *self) {
+ __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
PyObject *retval, *raised_exception;
PyObject *yf = gen->yieldfrom;
int err = 0;
- if (unlikely(__Pyx_Coroutine_CheckRunning(gen)))
+ if (unlikely(__Pyx_Generator_CheckRunning(gen)))
return NULL;
if (yf) {
Py_INCREF(yf);
- err = __Pyx_Coroutine_CloseIter(gen, yf);
- __Pyx_Coroutine_Undelegate(gen);
+ err = __Pyx_Generator_CloseIter(gen, yf);
+ __Pyx_Generator_Undelegate(gen);
Py_DECREF(yf);
}
if (err == 0)
PyErr_SetNone(PyExc_GeneratorExit);
- retval = __Pyx_Coroutine_SendEx(gen, NULL);
+ retval = __Pyx_Generator_SendEx(gen, NULL);
if (retval) {
Py_DECREF(retval);
PyErr_SetString(PyExc_RuntimeError,
@@ -24386,40 +21498,32 @@ static PyObject *__Pyx_Coroutine_Close(PyObject *self) {
}
return NULL;
}
-static PyObject *__Pyx_Coroutine_Throw(PyObject *self, PyObject *args) {
- __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self;
+static PyObject *__Pyx_Generator_Throw(PyObject *self, PyObject *args) {
+ __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
PyObject *typ;
PyObject *tb = NULL;
PyObject *val = NULL;
PyObject *yf = gen->yieldfrom;
if (!PyArg_UnpackTuple(args, (char *)"throw", 1, 3, &typ, &val, &tb))
return NULL;
- if (unlikely(__Pyx_Coroutine_CheckRunning(gen)))
+ if (unlikely(__Pyx_Generator_CheckRunning(gen)))
return NULL;
if (yf) {
PyObject *ret;
Py_INCREF(yf);
if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit)) {
- int err = __Pyx_Coroutine_CloseIter(gen, yf);
+ int err = __Pyx_Generator_CloseIter(gen, yf);
Py_DECREF(yf);
- __Pyx_Coroutine_Undelegate(gen);
+ __Pyx_Generator_Undelegate(gen);
if (err < 0)
- return __Pyx_Coroutine_MethodReturn(__Pyx_Coroutine_SendEx(gen, NULL));
+ return __Pyx_Generator_SendEx(gen, NULL);
goto throw_here;
}
gen->is_running = 1;
- #ifdef __Pyx_Generator_USED
if (__Pyx_Generator_CheckExact(yf)) {
- ret = __Pyx_Coroutine_Throw(yf, args);
- } else
- #endif
- #ifdef __Pyx_Coroutine_USED
- if (__Pyx_Coroutine_CheckExact(yf)) {
- ret = __Pyx_Coroutine_Throw(yf, args);
- } else
- #endif
- {
- PyObject *meth = __Pyx_PyObject_GetAttrStr(yf, __pyx_n_s_throw);
+ ret = __Pyx_Generator_Throw(yf, args);
+ } else {
+ PyObject *meth = PyObject_GetAttr(yf, __pyx_n_s_throw);
if (unlikely(!meth)) {
Py_DECREF(yf);
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
@@ -24427,7 +21531,7 @@ static PyObject *__Pyx_Coroutine_Throw(PyObject *self, PyObject *args) {
return NULL;
}
PyErr_Clear();
- __Pyx_Coroutine_Undelegate(gen);
+ __Pyx_Generator_Undelegate(gen);
gen->is_running = 0;
goto throw_here;
}
@@ -24437,16 +21541,16 @@ static PyObject *__Pyx_Coroutine_Throw(PyObject *self, PyObject *args) {
gen->is_running = 0;
Py_DECREF(yf);
if (!ret) {
- ret = __Pyx_Coroutine_FinishDelegation(gen);
+ ret = __Pyx_Generator_FinishDelegation(gen);
}
- return __Pyx_Coroutine_MethodReturn(ret);
+ return ret;
}
throw_here:
__Pyx_Raise(typ, val, tb, NULL);
- return __Pyx_Coroutine_MethodReturn(__Pyx_Coroutine_SendEx(gen, NULL));
+ return __Pyx_Generator_SendEx(gen, NULL);
}
-static int __Pyx_Coroutine_traverse(PyObject *self, visitproc visit, void *arg) {
- __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self;
+static int __Pyx_Generator_traverse(PyObject *self, visitproc visit, void *arg) {
+ __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
Py_VISIT(gen->closure);
Py_VISIT(gen->classobj);
Py_VISIT(gen->yieldfrom);
@@ -24455,8 +21559,8 @@ static int __Pyx_Coroutine_traverse(PyObject *self, visitproc visit, void *arg)
Py_VISIT(gen->exc_traceback);
return 0;
}
-static int __Pyx_Coroutine_clear(PyObject *self) {
- __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self;
+static int __Pyx_Generator_clear(PyObject *self) {
+ __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
Py_CLEAR(gen->closure);
Py_CLEAR(gen->classobj);
Py_CLEAR(gen->yieldfrom);
@@ -24467,8 +21571,8 @@ static int __Pyx_Coroutine_clear(PyObject *self) {
Py_CLEAR(gen->gi_qualname);
return 0;
}
-static void __Pyx_Coroutine_dealloc(PyObject *self) {
- __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self;
+static void __Pyx_Generator_dealloc(PyObject *self) {
+ __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
PyObject_GC_UnTrack(gen);
if (gen->gi_weakreflist != NULL)
PyObject_ClearWeakRefs(self);
@@ -24485,23 +21589,21 @@ static void __Pyx_Coroutine_dealloc(PyObject *self) {
}
PyObject_GC_UnTrack(self);
}
- __Pyx_Coroutine_clear(self);
+ __Pyx_Generator_clear(self);
PyObject_GC_Del(gen);
}
-static void __Pyx_Coroutine_del(PyObject *self) {
+static void __Pyx_Generator_del(PyObject *self) {
PyObject *res;
PyObject *error_type, *error_value, *error_traceback;
- __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self;
- __Pyx_PyThreadState_declare
+ __pyx_GeneratorObject *gen = (__pyx_GeneratorObject *) self;
if (gen->resume_label <= 0)
return ;
#if PY_VERSION_HEX < 0x030400a1
assert(self->ob_refcnt == 0);
self->ob_refcnt = 1;
#endif
- __Pyx_PyThreadState_assign
__Pyx_ErrFetch(&error_type, &error_value, &error_traceback);
- res = __Pyx_Coroutine_Close(self);
+ res = __Pyx_Generator_Close(self);
if (res == NULL)
PyErr_WriteUnraisable(self);
else
@@ -24529,15 +21631,13 @@ static void __Pyx_Coroutine_del(PyObject *self) {
#endif
}
static PyObject *
-__Pyx_Coroutine_get_name(__pyx_CoroutineObject *self)
+__Pyx_Generator_get_name(__pyx_GeneratorObject *self)
{
- PyObject *name = self->gi_name;
- if (unlikely(!name)) name = Py_None;
- Py_INCREF(name);
- return name;
+ Py_INCREF(self->gi_name);
+ return self->gi_name;
}
static int
-__Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value)
+__Pyx_Generator_set_name(__pyx_GeneratorObject *self, PyObject *value)
{
PyObject *tmp;
#if PY_MAJOR_VERSION >= 3
@@ -24556,15 +21656,13 @@ __Pyx_Coroutine_set_name(__pyx_CoroutineObject *self, PyObject *value)
return 0;
}
static PyObject *
-__Pyx_Coroutine_get_qualname(__pyx_CoroutineObject *self)
+__Pyx_Generator_get_qualname(__pyx_GeneratorObject *self)
{
- PyObject *name = self->gi_qualname;
- if (unlikely(!name)) name = Py_None;
- Py_INCREF(name);
- return name;
+ Py_INCREF(self->gi_qualname);
+ return self->gi_qualname;
}
static int
-__Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value)
+__Pyx_Generator_set_qualname(__pyx_GeneratorObject *self, PyObject *value)
{
PyObject *tmp;
#if PY_MAJOR_VERSION >= 3
@@ -24582,160 +21680,37 @@ __Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value)
Py_XDECREF(tmp);
return 0;
}
-static __pyx_CoroutineObject *__Pyx__Coroutine_New(
- PyTypeObject* type, __pyx_coroutine_body_t body, PyObject *closure,
- PyObject *name, PyObject *qualname, PyObject *module_name) {
- __pyx_CoroutineObject *gen = PyObject_GC_New(__pyx_CoroutineObject, type);
- if (gen == NULL)
- return NULL;
- gen->body = body;
- gen->closure = closure;
- Py_XINCREF(closure);
- gen->is_running = 0;
- gen->resume_label = 0;
- gen->classobj = NULL;
- gen->yieldfrom = NULL;
- gen->exc_type = NULL;
- gen->exc_value = NULL;
- gen->exc_traceback = NULL;
- gen->gi_weakreflist = NULL;
- Py_XINCREF(qualname);
- gen->gi_qualname = qualname;
- Py_XINCREF(name);
- gen->gi_name = name;
- Py_XINCREF(module_name);
- gen->gi_modulename = module_name;
- PyObject_GC_Track(gen);
- return gen;
-}
-
-/* PatchModuleWithCoroutine */
- static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_code) {
-#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
- int result;
- PyObject *globals, *result_obj;
- globals = PyDict_New(); if (unlikely(!globals)) goto ignore;
- result = PyDict_SetItemString(globals, "_cython_coroutine_type",
- #ifdef __Pyx_Coroutine_USED
- (PyObject*)__pyx_CoroutineType);
- #else
- Py_None);
- #endif
- if (unlikely(result < 0)) goto ignore;
- result = PyDict_SetItemString(globals, "_cython_generator_type",
- #ifdef __Pyx_Generator_USED
- (PyObject*)__pyx_GeneratorType);
- #else
- Py_None);
- #endif
- if (unlikely(result < 0)) goto ignore;
- if (unlikely(PyDict_SetItemString(globals, "_module", module) < 0)) goto ignore;
- if (unlikely(PyDict_SetItemString(globals, "__builtins__", __pyx_b) < 0)) goto ignore;
- result_obj = PyRun_String(py_code, Py_file_input, globals, globals);
- if (unlikely(!result_obj)) goto ignore;
- Py_DECREF(result_obj);
- Py_DECREF(globals);
- return module;
-ignore:
- Py_XDECREF(globals);
- PyErr_WriteUnraisable(module);
- if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning, "Cython module failed to patch module with custom type", 1) < 0)) {
- Py_DECREF(module);
- module = NULL;
- }
-#else
- py_code++;
-#endif
- return module;
-}
-
-/* PatchGeneratorABC */
- #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
-static PyObject* __Pyx_patch_abc_module(PyObject *module);
-static PyObject* __Pyx_patch_abc_module(PyObject *module) {
- module = __Pyx_Coroutine_patch_module(
- module, ""
-"if _cython_generator_type is not None:\n"
-" try: Generator = _module.Generator\n"
-" except AttributeError: pass\n"
-" else: Generator.register(_cython_generator_type)\n"
-"if _cython_coroutine_type is not None:\n"
-" try: Coroutine = _module.Coroutine\n"
-" except AttributeError: pass\n"
-" else: Coroutine.register(_cython_coroutine_type)\n"
- );
- return module;
-}
-#endif
-static int __Pyx_patch_abc(void) {
-#if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)
- static int abc_patched = 0;
- if (!abc_patched) {
- PyObject *module;
- module = PyImport_ImportModule((PY_VERSION_HEX >= 0x03030000) ? "collections.abc" : "collections");
- if (!module) {
- PyErr_WriteUnraisable(NULL);
- if (unlikely(PyErr_WarnEx(PyExc_RuntimeWarning,
- ((PY_VERSION_HEX >= 0x03030000) ?
- "Cython module failed to register with collections.abc module" :
- "Cython module failed to register with collections module"), 1) < 0)) {
- return -1;
- }
- } else {
- module = __Pyx_patch_abc_module(module);
- abc_patched = 1;
- if (unlikely(!module))
- return -1;
- Py_DECREF(module);
- }
- module = PyImport_ImportModule("backports_abc");
- if (module) {
- module = __Pyx_patch_abc_module(module);
- Py_XDECREF(module);
- }
- if (!module) {
- PyErr_Clear();
- }
- }
-#else
- if (0) __Pyx_Coroutine_patch_module(NULL, NULL);
-#endif
- return 0;
-}
-
-/* Generator */
- static PyMethodDef __pyx_Generator_methods[] = {
- {"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O,
- (char*) PyDoc_STR("send(arg) -> send 'arg' into generator,\nreturn next yielded value or raise StopIteration.")},
- {"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS,
- (char*) PyDoc_STR("throw(typ[,val[,tb]]) -> raise exception in generator,\nreturn next yielded value or raise StopIteration.")},
- {"close", (PyCFunction) __Pyx_Coroutine_Close, METH_NOARGS,
- (char*) PyDoc_STR("close() -> raise GeneratorExit inside generator.")},
- {0, 0, 0, 0}
-};
-static PyMemberDef __pyx_Generator_memberlist[] = {
- {(char *) "gi_running", T_BOOL, offsetof(__pyx_CoroutineObject, is_running), READONLY, NULL},
- {(char*) "gi_yieldfrom", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY,
- (char*) PyDoc_STR("object being iterated by 'yield from', or None")},
- {0, 0, 0, 0, 0}
-};
static PyGetSetDef __pyx_Generator_getsets[] = {
- {(char *) "__name__", (getter)__Pyx_Coroutine_get_name, (setter)__Pyx_Coroutine_set_name,
+ {(char *) "__name__", (getter)__Pyx_Generator_get_name, (setter)__Pyx_Generator_set_name,
(char*) PyDoc_STR("name of the generator"), 0},
- {(char *) "__qualname__", (getter)__Pyx_Coroutine_get_qualname, (setter)__Pyx_Coroutine_set_qualname,
+ {(char *) "__qualname__", (getter)__Pyx_Generator_get_qualname, (setter)__Pyx_Generator_set_qualname,
(char*) PyDoc_STR("qualified name of the generator"), 0},
{0, 0, 0, 0, 0}
};
+static PyMemberDef __pyx_Generator_memberlist[] = {
+ {(char *) "gi_running", T_BOOL, offsetof(__pyx_GeneratorObject, is_running), READONLY, NULL},
+ {0, 0, 0, 0, 0}
+};
+static PyMethodDef __pyx_Generator_methods[] = {
+ {"send", (PyCFunction) __Pyx_Generator_Send, METH_O, 0},
+ {"throw", (PyCFunction) __Pyx_Generator_Throw, METH_VARARGS, 0},
+ {"close", (PyCFunction) __Pyx_Generator_Close, METH_NOARGS, 0},
+ {0, 0, 0, 0}
+};
static PyTypeObject __pyx_GeneratorType_type = {
PyVarObject_HEAD_INIT(0, 0)
"generator",
- sizeof(__pyx_CoroutineObject),
+ sizeof(__pyx_GeneratorObject),
0,
- (destructor) __Pyx_Coroutine_dealloc,
+ (destructor) __Pyx_Generator_dealloc,
0,
0,
0,
+#if PY_MAJOR_VERSION < 3
0,
+#else
+ 0,
+#endif
0,
0,
0,
@@ -24748,10 +21723,10 @@ static PyTypeObject __pyx_GeneratorType_type = {
0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,
0,
- (traverseproc) __Pyx_Coroutine_traverse,
+ (traverseproc) __Pyx_Generator_traverse,
0,
0,
- offsetof(__pyx_CoroutineObject, gi_weakreflist),
+ offsetof(__pyx_GeneratorObject, gi_weakreflist),
0,
(iternextfunc) __Pyx_Generator_Next,
__pyx_Generator_methods,
@@ -24775,25 +21750,48 @@ static PyTypeObject __pyx_GeneratorType_type = {
#if PY_VERSION_HEX >= 0x030400a1
0,
#else
- __Pyx_Coroutine_del,
+ __Pyx_Generator_del,
#endif
0,
#if PY_VERSION_HEX >= 0x030400a1
- __Pyx_Coroutine_del,
+ __Pyx_Generator_del,
#endif
};
+static __pyx_GeneratorObject *__Pyx_Generator_New(__pyx_generator_body_t body,
+ PyObject *closure, PyObject *name, PyObject *qualname) {
+ __pyx_GeneratorObject *gen =
+ PyObject_GC_New(__pyx_GeneratorObject, &__pyx_GeneratorType_type);
+ if (gen == NULL)
+ return NULL;
+ gen->body = body;
+ gen->closure = closure;
+ Py_XINCREF(closure);
+ gen->is_running = 0;
+ gen->resume_label = 0;
+ gen->classobj = NULL;
+ gen->yieldfrom = NULL;
+ gen->exc_type = NULL;
+ gen->exc_value = NULL;
+ gen->exc_traceback = NULL;
+ gen->gi_weakreflist = NULL;
+ Py_XINCREF(qualname);
+ gen->gi_qualname = qualname;
+ Py_XINCREF(name);
+ gen->gi_name = name;
+ PyObject_GC_Track(gen);
+ return gen;
+}
static int __pyx_Generator_init(void) {
__pyx_GeneratorType_type.tp_getattro = PyObject_GenericGetAttr;
__pyx_GeneratorType_type.tp_iter = PyObject_SelfIter;
__pyx_GeneratorType = __Pyx_FetchCommonType(&__pyx_GeneratorType_type);
- if (unlikely(!__pyx_GeneratorType)) {
+ if (__pyx_GeneratorType == NULL) {
return -1;
}
return 0;
}
-/* CheckBinaryVersion */
- static int __Pyx_check_binary_version(void) {
+static int __Pyx_check_binary_version(void) {
char ctversion[4], rtversion[4];
PyOS_snprintf(ctversion, 4, "%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION);
PyOS_snprintf(rtversion, 4, "%s", Py_GetVersion());
@@ -24808,8 +21806,7 @@ static int __pyx_Generator_init(void) {
return 0;
}
-/* ModuleImport */
- #ifndef __PYX_HAVE_RT_ImportModule
+#ifndef __PYX_HAVE_RT_ImportModule
#define __PYX_HAVE_RT_ImportModule
static PyObject *__Pyx_ImportModule(const char *name) {
PyObject *py_name = 0;
@@ -24826,8 +21823,7 @@ bad:
}
#endif
-/* TypeImport */
- #ifndef __PYX_HAVE_RT_ImportType
+#ifndef __PYX_HAVE_RT_ImportType
#define __PYX_HAVE_RT_ImportType
static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class_name,
size_t size, int strict)
@@ -24873,14 +21869,14 @@ static PyTypeObject *__Pyx_ImportType(const char *module_name, const char *class
#endif
if (!strict && (size_t)basicsize > size) {
PyOS_snprintf(warning, sizeof(warning),
- "%s.%s size changed, may indicate binary incompatibility. Expected %zd, got %zd",
- module_name, class_name, basicsize, size);
+ "%s.%s size changed, may indicate binary incompatibility",
+ module_name, class_name);
if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad;
}
else if ((size_t)basicsize != size) {
PyErr_Format(PyExc_ValueError,
- "%.200s.%.200s has the wrong size, try recompiling. Expected %zd, got %zd",
- module_name, class_name, basicsize, size);
+ "%.200s.%.200s has the wrong size, try recompiling",
+ module_name, class_name);
goto bad;
}
return (PyTypeObject *)result;
@@ -24891,8 +21887,7 @@ bad:
}
#endif
-/* InitStrings */
- static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
+static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
while (t->p) {
#if PY_MAJOR_VERSION < 3
if (t->is_unicode) {
@@ -24930,7 +21925,7 @@ static CYTHON_INLINE char* __Pyx_PyObject_AsString(PyObject* o) {
return __Pyx_PyObject_AsStringAndSize(o, &ignore);
}
static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) {
-#if CYTHON_COMPILING_IN_CPYTHON && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT)
+#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT
if (
#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII
__Pyx_sys_getdefaultencoding_not_ascii &&
@@ -24971,7 +21966,7 @@ static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_
#endif
} else
#endif
-#if (!CYTHON_COMPILING_IN_PYPY) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE))
+#if !CYTHON_COMPILING_IN_PYPY
if (PyByteArray_Check(o)) {
*length = PyByteArray_GET_SIZE(o);
return PyByteArray_AS_STRING(o);
@@ -24992,10 +21987,8 @@ static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
if (is_true | (x == Py_False) | (x == Py_None)) return is_true;
else return PyObject_IsTrue(x);
}
-static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) {
-#if CYTHON_USE_TYPE_SLOTS
+static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) {
PyNumberMethods *m;
-#endif
const char *name = NULL;
PyObject *res = NULL;
#if PY_MAJOR_VERSION < 3
@@ -25003,10 +21996,9 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) {
#else
if (PyLong_Check(x))
#endif
- return __Pyx_NewRef(x);
-#if CYTHON_USE_TYPE_SLOTS
+ return Py_INCREF(x), x;
m = Py_TYPE(x)->tp_as_number;
- #if PY_MAJOR_VERSION < 3
+#if PY_MAJOR_VERSION < 3
if (m && m->nb_int) {
name = "int";
res = PyNumber_Int(x);
@@ -25015,14 +22007,11 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) {
name = "long";
res = PyNumber_Long(x);
}
- #else
+#else
if (m && m->nb_int) {
name = "int";
res = PyNumber_Long(x);
}
- #endif
-#else
- res = PyNumber_Int(x);
#endif
if (res) {
#if PY_MAJOR_VERSION < 3
@@ -25047,55 +22036,18 @@ static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
Py_ssize_t ival;
PyObject *x;
#if PY_MAJOR_VERSION < 3
- if (likely(PyInt_CheckExact(b))) {
- if (sizeof(Py_ssize_t) >= sizeof(long))
- return PyInt_AS_LONG(b);
- else
- return PyInt_AsSsize_t(x);
- }
+ if (likely(PyInt_CheckExact(b)))
+ return PyInt_AS_LONG(b);
#endif
if (likely(PyLong_CheckExact(b))) {
- #if CYTHON_USE_PYLONG_INTERNALS
- const digit* digits = ((PyLongObject*)b)->ob_digit;
- const Py_ssize_t size = Py_SIZE(b);
- if (likely(__Pyx_sst_abs(size) <= 1)) {
- ival = likely(size) ? digits[0] : 0;
- if (size == -1) ival = -ival;
- return ival;
- } else {
- switch (size) {
- case 2:
- if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) {
- return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
- }
- break;
- case -2:
- if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) {
- return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
- }
- break;
- case 3:
- if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) {
- return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
- }
- break;
- case -3:
- if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) {
- return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
- }
- break;
- case 4:
- if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) {
- return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
- }
- break;
- case -4:
- if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) {
- return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));
- }
- break;
- }
- }
+ #if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
+ #if CYTHON_USE_PYLONG_INTERNALS
+ switch (Py_SIZE(b)) {
+ case -1: return -(sdigit)((PyLongObject*)b)->ob_digit[0];
+ case 0: return 0;
+ case 1: return ((PyLongObject*)b)->ob_digit[0];
+ }
+ #endif
#endif
return PyLong_AsSsize_t(b);
}
diff --git a/silx/io/specfile.pyx b/silx/io/specfile.pyx
index 35f425b..39e8816 100644
--- a/silx/io/specfile.pyx
+++ b/silx/io/specfile.pyx
@@ -614,7 +614,7 @@ class Scan(object):
def _string_to_char_star(string_):
"""Convert a string to ASCII encoded bytes when using python3"""
- if sys.version.startswith("3") and not isinstance(string_, bytes):
+ if sys.version_info[0] >= 3 and not isinstance(string_, bytes):
return bytes(string_, "ascii")
return string_
@@ -629,15 +629,14 @@ def is_specfile(filename):
"""
if not os.path.isfile(filename):
return False
- # test for presence of #S or #F in first two lines
- f = open(filename)
- for i, line in enumerate(f):
- if line.startswith("#S ") or line.startswith("#F "):
- f.close()
+ # test for presence of #S or #F in first 10 lines
+ with open(filename, "rb") as f:
+ chunk = f.read(2500)
+ for i, line in enumerate(chunk.split(b"\n")):
+ if line.startswith(b"#S ") or line.startswith(b"#F "):
return True
if i >= 10:
break
- f.close()
return False
@@ -681,10 +680,15 @@ cdef class SpecFile(object):
def __dealloc__(self):
"""Destructor: Calls SfClose(self.handle)"""
+ self.close()
+
+ def close(self):
+ """Close the file descriptor"""
# handle is NULL if SfOpen failed
if self.handle:
if specfile_wrapper.SfClose(self.handle):
_logger.warning("Error while closing SpecFile")
+ self.handle = NULL
def __len__(self):
"""Return the number of scans in the SpecFile
diff --git a/silx/io/specfile/src/locale_management.c b/silx/io/specfile/src/locale_management.c
index 163ed75..62111cc 100644
--- a/silx/io/specfile/src/locale_management.c
+++ b/silx/io/specfile/src/locale_management.c
@@ -24,15 +24,23 @@
#include <stdlib.h>
#ifdef _GNU_SOURCE
-#include <xlocale.h>
-#include <locale.h>
+# include <locale.h>
+# ifdef __GLIBC__
+# include <features.h>
+# if !((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ > 25)))
+# /* strtod_l has been moved to stdlib.h since glibc 2.26 */
+# include <xlocale.h>
+# endif
+# else
+# include <xlocale.h>
+# endif
#else
-#ifdef PYMCA_POSIX
-#else
-#ifdef SPECFILE_POSIX
-#include <locale.h>
-#endif
-#endif
+# ifdef PYMCA_POSIX
+# else
+# ifdef SPECFILE_POSIX
+# include <locale.h>
+# endif
+# endif
#endif
#include <string.h>
diff --git a/silx/io/specfilewrapper.py b/silx/io/specfilewrapper.py
index 005e54e..01e185c 100644
--- a/silx/io/specfilewrapper.py
+++ b/silx/io/specfilewrapper.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*#########################################################################
-# Copyright (C) 2016 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -332,7 +332,7 @@ class scandata(Scan): # noqa
lines.
If ``key`` does not match any header line, return empty list.
:return: List of scan header lines
- :rtype: list[str]
+ :rtype: List[str]
"""
if key.strip() == "":
return self.scan_header
diff --git a/silx/io/spech5.py b/silx/io/spech5.py
index 81a7a7e..a112fe0 100644
--- a/silx/io/spech5.py
+++ b/silx/io/spech5.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -157,20 +157,30 @@ You can test for existence of data or groups::
>>> "spam" in sfh5["1.1"]
False
-Strings are stored encoded as ``numpy.string_``, as recommended by
-`the h5py documentation <http://docs.h5py.org/en/latest/strings.html>`_.
-This ensures maximum compatibility with third party software libraries,
-when saving a :class:`SpecH5` to a HDF5 file using :mod:`silx.io.spectoh5`.
+.. note::
-The type ``numpy.string_`` is a byte-string format. The consequence of this
-is that you should decode strings before using them in **Python 3**::
+ Text used to be stored with a dtype ``numpy.string_`` in silx versions
+ prior to *0.7.0*. The type ``numpy.string_`` is a byte-string format.
+ The consequence of this is that you had to decode strings before using
+ them in **Python 3**::
- >>> from silx.io.spech5 import SpecH5
- >>> sfh5 = SpecH5("31oct98.dat")
- >>> sfh5["/68.1/title"]
- b'68 ascan tx3 -28.5 -24.5 20 0.5'
- >>> sfh5["/68.1/title"].decode()
- '68 ascan tx3 -28.5 -24.5 20 0.5'
+ >>> from silx.io.spech5 import SpecH5
+ >>> sfh5 = SpecH5("31oct98.dat")
+ >>> sfh5["/68.1/title"]
+ b'68 ascan tx3 -28.5 -24.5 20 0.5'
+ >>> sfh5["/68.1/title"].decode()
+ '68 ascan tx3 -28.5 -24.5 20 0.5'
+
+ From silx version *0.7.0* onwards, text is now stored as unicode. This
+ corresponds to the default text type in python 3, and to the *unicode*
+ type in Python 2.
+
+ To be on the safe side, you can test for the presence of a *decode*
+ attribute, to ensure that you always work with unicode text::
+
+ >>> title = sfh5["/68.1/title"]
+ >>> if hasattr(title, "decode"):
+ ... title = title.decode()
"""
@@ -178,28 +188,32 @@ import datetime
import logging
import numpy
import re
-import sys
import io
+import h5py
from silx import version as silx_version
from .specfile import SpecFile
from . import commonh5
+from silx.third_party import six
__authors__ = ["P. Knobel", "D. Naudet"]
__license__ = "MIT"
-__date__ = "23/08/2017"
+__date__ = "01/03/2018"
logger1 = logging.getLogger(__name__)
-try:
- import h5py
-except ImportError:
- h5py = None
- logger1.debug("Module h5py optional.", exc_info=True)
+
+text_dtype = h5py.special_dtype(vlen=six.text_type)
-string_types = (basestring,) if sys.version_info[0] == 2 else (str,) # noqa
-integer_types = (int, long,) if sys.version_info[0] == 2 else (int,) # noqa
+def to_h5py_utf8(str_list):
+ """Convert a string or a list of strings to a numpy array of
+ unicode strings that can be written to HDF5 as utf-8.
+
+ This ensures that the type will be consistent between python 2 and
+ python 3, if attributes or datasets are saved to an HDF5 file.
+ """
+ return numpy.array(str_list, dtype=text_dtype)
def _get_number_of_mca_analysers(scan):
@@ -457,10 +471,9 @@ class SpecH5NodeDataset(commonh5.Dataset, SpecH5Dataset):
def __init__(self, name, data, parent=None, attrs=None):
# get proper value types, to inherit from numpy
# attributes (dtype, shape, size)
- if isinstance(data, string_types):
- # use bytes for maximum compatibility
- # (see http://docs.h5py.org/en/latest/strings.html)
- value = numpy.string_(data)
+ if isinstance(data, six.string_types):
+ # use unicode (utf-8 when saved to HDF5 output)
+ value = to_h5py_utf8(data)
elif isinstance(data, float):
# use 32 bits for float scalars
value = numpy.float32(data)
@@ -472,7 +485,8 @@ class SpecH5NodeDataset(commonh5.Dataset, SpecH5Dataset):
data_kind = array.dtype.kind
if data_kind in ["S", "U"]:
- value = numpy.asarray(array, dtype=numpy.string_)
+ value = numpy.asarray(array,
+ dtype=text_dtype)
elif data_kind in ["f"]:
value = numpy.asarray(array, dtype=numpy.float32)
else:
@@ -547,12 +561,12 @@ class SpecH5(commonh5.File, SpecH5Group):
self._sf = SpecFile(filename)
- attrs = {"NX_class": "NXroot",
- "file_time": datetime.datetime.now().isoformat(),
- "file_name": filename,
- "creator": "silx %s" % silx_version}
+ attrs = {"NX_class": to_h5py_utf8("NXroot"),
+ "file_time": to_h5py_utf8(
+ datetime.datetime.now().isoformat()),
+ "file_name": to_h5py_utf8(filename),
+ "creator": to_h5py_utf8("silx spech5 %s" % silx_version)}
commonh5.File.__init__(self, filename, attrs=attrs)
- assert self.attrs["NX_class"] == "NXroot"
for scan_key in self._sf.keys():
scan = self._sf[scan_key]
@@ -560,7 +574,7 @@ class SpecH5(commonh5.File, SpecH5Group):
self.add_node(scan_group)
def close(self):
- # or del self._sf?
+ self._sf.close()
self._sf = None
@@ -573,10 +587,13 @@ class ScanGroup(commonh5.Group, SpecH5Group):
:param scan: specfile.Scan object
"""
commonh5.Group.__init__(self, scan_key, parent=parent,
- attrs={"NX_class": "NXentry"})
+ attrs={"NX_class": to_h5py_utf8("NXentry")})
+ # take title in #S after stripping away scan number and spaces
+ s_hdr_line = scan.scan_header_dict["S"]
+ title = s_hdr_line.lstrip("0123456789").lstrip()
self.add_node(SpecH5NodeDataset(name="title",
- data=scan.scan_header_dict["S"],
+ data=to_h5py_utf8(title),
parent=self))
if "D" in scan.scan_header_dict:
@@ -603,7 +620,7 @@ class ScanGroup(commonh5.Group, SpecH5Group):
scan_key)
start_time_str = ""
self.add_node(SpecH5NodeDataset(name="start_time",
- data=start_time_str,
+ data=to_h5py_utf8(start_time_str),
parent=self))
self.add_node(InstrumentGroup(parent=self, scan=scan))
@@ -620,7 +637,7 @@ class InstrumentGroup(commonh5.Group, SpecH5Group):
:param scan: specfile.Scan object
"""
commonh5.Group.__init__(self, name="instrument", parent=parent,
- attrs={"NX_class": "NXinstrument"})
+ attrs={"NX_class": to_h5py_utf8("NXinstrument")})
self.add_node(InstrumentSpecfileGroup(parent=self, scan=scan))
self.add_node(PositionersGroup(parent=self, scan=scan))
@@ -635,21 +652,23 @@ class InstrumentGroup(commonh5.Group, SpecH5Group):
class InstrumentSpecfileGroup(commonh5.Group, SpecH5Group):
def __init__(self, parent, scan):
commonh5.Group.__init__(self, name="specfile", parent=parent,
- attrs={"NX_class": "NXcollection"})
- self.add_node(SpecH5NodeDataset(name="file_header",
- data="\n".join(scan.file_header),
- parent=self,
- attrs={}))
- self.add_node(SpecH5NodeDataset(name="scan_header",
- data="\n".join(scan.scan_header),
- parent=self,
- attrs={}))
+ attrs={"NX_class": to_h5py_utf8("NXcollection")})
+ self.add_node(SpecH5NodeDataset(
+ name="file_header",
+ data=to_h5py_utf8(scan.file_header),
+ parent=self,
+ attrs={}))
+ self.add_node(SpecH5NodeDataset(
+ name="scan_header",
+ data=to_h5py_utf8(scan.scan_header),
+ parent=self,
+ attrs={}))
class PositionersGroup(commonh5.Group, SpecH5Group):
def __init__(self, parent, scan):
commonh5.Group.__init__(self, name="positioners", parent=parent,
- attrs={"NX_class": "NXcollection"})
+ attrs={"NX_class": to_h5py_utf8("NXcollection")})
for motor_name in scan.motor_names:
safe_motor_name = motor_name.replace("/", "%")
if motor_name in scan.labels and scan.data.shape[0] > 0:
@@ -668,11 +687,14 @@ class InstrumentMcaGroup(commonh5.Group, SpecH5Group):
def __init__(self, parent, analyser_index, scan):
name = "mca_%d" % analyser_index
commonh5.Group.__init__(self, name=name, parent=parent,
- attrs={"NX_class": "NXdetector"})
+ attrs={"NX_class": to_h5py_utf8("NXdetector")})
- self.add_node(McaDataDataset(parent=self,
+ mcaDataDataset = McaDataDataset(parent=self,
analyser_index=analyser_index,
- scan=scan))
+ scan=scan)
+ self.add_node(mcaDataDataset)
+ spectrum_length = mcaDataDataset.shape[-1]
+ mcaDataDataset = None
if len(scan.mca.channels) == 1:
# single @CALIB line applying to multiple devices
@@ -681,6 +703,21 @@ class InstrumentMcaGroup(commonh5.Group, SpecH5Group):
else:
calibration_dataset = scan.mca.calibration[analyser_index]
channels_dataset = scan.mca.channels[analyser_index]
+
+ channels_length = len(channels_dataset)
+ if (channels_length > 1) and (spectrum_length > 0):
+ logger1.info("Spectrum and channels length mismatch")
+ # this should always be the case
+ if channels_length > spectrum_length:
+ channels_dataset = channels_dataset[:spectrum_length]
+ elif channels_length < spectrum_length:
+ # only trust first channel and increment
+ channel0 = channels_dataset[0]
+ increment = channels_dataset[1] - channels_dataset[0]
+ channels_dataset = numpy.linspace(channel0,
+ channel0 + increment * spectrum_length,
+ spectrum_length, endpoint=False)
+
self.add_node(SpecH5NodeDataset(name="calibration",
data=calibration_dataset,
parent=self))
@@ -707,7 +744,7 @@ class McaDataDataset(SpecH5LazyNodeDataset):
def __init__(self, parent, analyser_index, scan):
commonh5.LazyLoadableDataset.__init__(
self, name="data", parent=parent,
- attrs={"interpretation": "spectrum", })
+ attrs={"interpretation": to_h5py_utf8("spectrum"),})
self._scan = scan
self._analyser_index = analyser_index
self._shape = None
@@ -741,7 +778,7 @@ class McaDataDataset(SpecH5LazyNodeDataset):
def __getitem__(self, item):
# optimization for fetching a single spectrum if data not already loaded
if not self._is_initialized:
- if isinstance(item, integer_types):
+ if isinstance(item, six.integer_types):
if item < 0:
# negative indexing
item += len(self)
@@ -750,7 +787,7 @@ class McaDataDataset(SpecH5LazyNodeDataset):
# accessing a slice or element of a single spectrum [i, j:k]
try:
spectrum_idx, channel_idx_or_slice = item
- assert isinstance(spectrum_idx, integer_types)
+ assert isinstance(spectrum_idx, six.integer_types)
except (ValueError, TypeError, AssertionError):
pass
else:
@@ -770,7 +807,7 @@ class MeasurementGroup(commonh5.Group, SpecH5Group):
:param scan: specfile.Scan object
"""
commonh5.Group.__init__(self, name="measurement", parent=parent,
- attrs={"NX_class": "NXcollection", })
+ attrs={"NX_class": to_h5py_utf8("NXcollection"),})
for label in scan.labels:
safe_label = label.replace("/", "%")
self.add_node(SpecH5NodeDataset(name=safe_label,
@@ -805,23 +842,23 @@ class SampleGroup(commonh5.Group, SpecH5Group):
:param scan: specfile.Scan object
"""
commonh5.Group.__init__(self, name="sample", parent=parent,
- attrs={"NX_class": "NXsample", })
+ attrs={"NX_class": to_h5py_utf8("NXsample"),})
if _unit_cell_in_scan(scan):
self.add_node(SpecH5NodeDataset(name="unit_cell",
data=_parse_unit_cell(scan.scan_header_dict["G1"]),
parent=self,
- attrs={"interpretation": "scalar"}))
+ attrs={"interpretation": to_h5py_utf8("scalar")}))
self.add_node(SpecH5NodeDataset(name="unit_cell_abc",
data=_parse_unit_cell(scan.scan_header_dict["G1"])[0, 0:3],
parent=self,
- attrs={"interpretation": "scalar"}))
+ attrs={"interpretation": to_h5py_utf8("scalar")}))
self.add_node(SpecH5NodeDataset(name="unit_cell_alphabetagamma",
data=_parse_unit_cell(scan.scan_header_dict["G1"])[0, 3:6],
parent=self,
- attrs={"interpretation": "scalar"}))
+ attrs={"interpretation": to_h5py_utf8("scalar")}))
if _ub_matrix_in_scan(scan):
self.add_node(SpecH5NodeDataset(name="ub_matrix",
data=_parse_UB_matrix(scan.scan_header_dict["G3"]),
parent=self,
- attrs={"interpretation": "scalar"}))
+ attrs={"interpretation": to_h5py_utf8("scalar")}))
diff --git a/silx/io/test/__init__.py b/silx/io/test/__init__.py
index 2510ae2..a309ee9 100644
--- a/silx/io/test/__init__.py
+++ b/silx/io/test/__init__.py
@@ -24,7 +24,7 @@
__authors__ = ["T. Vincent", "P. Knobel"]
__license__ = "MIT"
-__date__ = "20/09/2017"
+__date__ = "08/12/2017"
import unittest
@@ -39,6 +39,7 @@ from .test_utils import suite as test_utils_suite
from .test_nxdata import suite as test_nxdata_suite
from .test_commonh5 import suite as test_commonh5_suite
from .test_rawh5 import suite as test_rawh5_suite
+from .test_url import suite as test_url_suite
def suite():
@@ -54,4 +55,5 @@ def suite():
test_suite.addTest(test_nxdata_suite())
test_suite.addTest(test_commonh5_suite())
test_suite.addTest(test_rawh5_suite())
+ test_suite.addTest(test_url_suite())
return test_suite
diff --git a/silx/io/test/test_dictdump.py b/silx/io/test/test_dictdump.py
index 15d5fdc..9cd054c 100644
--- a/silx/io/test/test_dictdump.py
+++ b/silx/io/test/test_dictdump.py
@@ -25,7 +25,7 @@
__authors__ = ["P. Knobel"]
__license__ = "MIT"
-__date__ = "10/02/2017"
+__date__ = "17/01/2018"
from collections import OrderedDict
import numpy
@@ -41,9 +41,12 @@ except ImportError:
from collections import defaultdict
+from silx.utils.testutils import TestLogging
+
from ..configdict import ConfigDict
-from ..dictdump import dicttoh5, dicttojson, dicttoini, dump
+from ..dictdump import dicttoh5, dicttojson, dump
from ..dictdump import h5todict, load
+from ..dictdump import logger as dictdump_logger
def tree():
@@ -93,6 +96,24 @@ class TestDictToH5(unittest.TestCase):
min(ddict["city attributes"]["Europe"]["France"]["Grenoble"]["coordinates"]),
5.7196)
+ def testH5Overwrite(self):
+ dd = ConfigDict({'t': True})
+
+ dicttoh5(h5file=self.h5_fname, treedict=dd, mode='a')
+ dd = ConfigDict({'t': False})
+ with TestLogging(dictdump_logger, warning=1):
+ dicttoh5(h5file=self.h5_fname, treedict=dd, mode='a',
+ overwrite_data=False)
+
+ res = h5todict(self.h5_fname)
+ assert(res['t'] == True)
+
+ dicttoh5(h5file=self.h5_fname, treedict=dd, mode='a',
+ overwrite_data=True)
+
+ res = h5todict(self.h5_fname)
+ assert(res['t'] == False)
+
@unittest.skipIf(h5py_missing, "Could not import h5py")
class TestH5ToDict(unittest.TestCase):
diff --git a/silx/io/test/test_fabioh5.py b/silx/io/test/test_fabioh5.py
index d9459ae..5fbf0d0 100644
--- a/silx/io/test/test_fabioh5.py
+++ b/silx/io/test/test_fabioh5.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -25,10 +25,9 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "04/10/2017"
+__date__ = "24/02/2018"
import os
-import sys
import logging
import numpy
import unittest
@@ -289,6 +288,28 @@ class TestFabioH5(unittest.TestCase):
self.assertIn(d.dtype.char, ['d', 'f'])
numpy.testing.assert_array_almost_equal(d[...], expected)
+ def test_interpretation_mca_edf(self):
+ """EDF files with two or more headers starting with "MCA"
+ must have @interpretation = "spectrum" an the data."""
+ header = {
+ "Title": "zapimage samy -4.975 -5.095 80 500 samz -4.091 -4.171 70 0",
+ "MCA a": -23.812,
+ "MCA b": 2.7107,
+ "MCA c": 8.1164e-06}
+
+ data = numpy.array([[0, 0], [0, 0]], dtype=numpy.int8)
+ fabio_image = fabio.edfimage.EdfImage(data=data, header=header)
+ h5_image = fabioh5.File(fabio_image=fabio_image)
+
+ data_dataset = h5_image["/scan_0/measurement/image_0/data"]
+ self.assertEquals(data_dataset.attrs["interpretation"], "spectrum")
+
+ data_dataset = h5_image["/scan_0/instrument/detector_0/data"]
+ self.assertEquals(data_dataset.attrs["interpretation"], "spectrum")
+
+ data_dataset = h5_image["/scan_0/measurement/image_0/info/data"]
+ self.assertEquals(data_dataset.attrs["interpretation"], "spectrum")
+
def test_get_api(self):
result = self.h5_image.get("scan_0", getclass=True, getlink=True)
self.assertIs(result, h5py.HardLink)
@@ -356,6 +377,95 @@ class TestFabioH5(unittest.TestCase):
self.assertIsInstance(data[...], numpy.ndarray)
+class TestFabioH5MultiFrames(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ if fabio is None:
+ raise unittest.SkipTest("fabio is needed")
+ if h5py is None:
+ raise unittest.SkipTest("h5py is needed")
+
+ names = ["A", "B", "C", "D"]
+ values = [["32000", "-10", "5.0", "1"],
+ ["-32000", "-10", "5.0", "1"]]
+
+ fabio_file = None
+
+ for i in range(10):
+ header = {
+ "image_id": "%d" % i,
+ "integer": "-100",
+ "float": "1.0",
+ "string": "hi!",
+ "list_integer": "100 50 0",
+ "list_float": "1.0 2.0 3.5",
+ "string_looks_like_list": "2000 hi!",
+ "motor_mne": " ".join(names),
+ "motor_pos": " ".join(values[i % len(values)]),
+ "counter_mne": " ".join(names),
+ "counter_pos": " ".join(values[i % len(values)])
+ }
+ for iname, name in enumerate(names):
+ header[name] = values[i % len(values)][iname]
+
+ data = numpy.array([[i, 11], [12, 13], [14, 15]], dtype=numpy.int64)
+ if fabio_file is None:
+ fabio_file = fabio.edfimage.EdfImage(data=data, header=header)
+ else:
+ fabio_file.appendFrame(data=data, header=header)
+
+ cls.fabio_file = fabio_file
+ cls.fabioh5 = fabioh5.File(fabio_image=fabio_file)
+
+ def test_others(self):
+ others = self.fabioh5["/scan_0/instrument/detector_0/others"]
+ dataset = others["A"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 1)
+ self.assertEqual(dataset.dtype.kind, "i")
+ dataset = others["B"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 1)
+ self.assertEqual(dataset.dtype.kind, "i")
+ dataset = others["C"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 1)
+ self.assertEqual(dataset.dtype.kind, "f")
+ dataset = others["D"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 1)
+ self.assertEqual(dataset.dtype.kind, "u")
+
+ def test_positioners(self):
+ counters = self.fabioh5["/scan_0/instrument/positioners"]
+ # At least 32 bits, no unsigned values
+ dataset = counters["A"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 4)
+ self.assertEqual(dataset.dtype.kind, "i")
+ dataset = counters["B"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 4)
+ self.assertEqual(dataset.dtype.kind, "i")
+ dataset = counters["C"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 4)
+ self.assertEqual(dataset.dtype.kind, "f")
+ dataset = counters["D"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 4)
+ self.assertEqual(dataset.dtype.kind, "i")
+
+ def test_counters(self):
+ counters = self.fabioh5["/scan_0/measurement"]
+ # At least 32 bits, no unsigned values
+ dataset = counters["A"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 4)
+ self.assertEqual(dataset.dtype.kind, "i")
+ dataset = counters["B"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 4)
+ self.assertEqual(dataset.dtype.kind, "i")
+ dataset = counters["C"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 4)
+ self.assertEqual(dataset.dtype.kind, "f")
+ dataset = counters["D"]
+ self.assertGreaterEqual(dataset.dtype.itemsize, 4)
+ self.assertEqual(dataset.dtype.kind, "i")
+
+
class TestFabioH5WithEdf(unittest.TestCase):
@classmethod
@@ -388,12 +498,6 @@ class TestFabioH5WithEdf(unittest.TestCase):
def tearDownClass(cls):
cls.fabio_image = None
cls.h5_image = None
- if sys.platform == "win32" and fabio is not None:
- # gc collect is needed to close a file descriptor
- # opened by fabio and not released.
- # https://github.com/silx-kit/fabio/issues/167
- import gc
- gc.collect()
shutil.rmtree(cls.tmp_directory)
def test_reserved_format_metadata(self):
@@ -406,11 +510,70 @@ class TestFabioH5WithEdf(unittest.TestCase):
self.assertNotIn("/scan_0/instrument/detector_0/others/HeaderID", self.h5_image)
+class TestFabioH5WithFileSeries(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ if fabio is None:
+ raise unittest.SkipTest("fabio is needed")
+ if h5py is None:
+ raise unittest.SkipTest("h5py is needed")
+
+ cls.tmp_directory = tempfile.mkdtemp()
+
+ cls.edf_filenames = []
+
+ for i in range(10):
+ filename = os.path.join(cls.tmp_directory, "test_%04d.edf" % i)
+ cls.edf_filenames.append(filename)
+
+ header = {
+ "image_id": "%d" % i,
+ "integer": "-100",
+ "float": "1.0",
+ "string": "hi!",
+ "list_integer": "100 50 0",
+ "list_float": "1.0 2.0 3.5",
+ "string_looks_like_list": "2000 hi!",
+ }
+ data = numpy.array([[i, 11], [12, 13], [14, 15]], dtype=numpy.int64)
+ fabio_image = fabio.edfimage.edfimage(data, header)
+ fabio_image.write(filename)
+
+ @classmethod
+ def tearDownClass(cls):
+ shutil.rmtree(cls.tmp_directory)
+
+ def _testH5Image(self, h5_image):
+ # test data
+ dataset = h5_image["/scan_0/instrument/detector_0/data"]
+ self.assertEquals(dataset.h5py_class, h5py.Dataset)
+ self.assertTrue(isinstance(dataset[()], numpy.ndarray))
+ self.assertEquals(dataset.dtype.kind, "i")
+ self.assertEquals(dataset.shape, (10, 3, 2))
+ self.assertEquals(list(dataset[:, 0, 0]), list(range(10)))
+ self.assertEquals(dataset.attrs["interpretation"], "image")
+ # test metatdata
+ dataset = h5_image["/scan_0/instrument/detector_0/others/image_id"]
+ self.assertEquals(list(dataset[...]), list(range(10)))
+
+ def testFileList(self):
+ h5_image = fabioh5.File(file_series=self.edf_filenames)
+ self._testH5Image(h5_image)
+
+ def testFileSeries(self):
+ file_series = fabioh5._FileSeries(self.edf_filenames)
+ h5_image = fabioh5.File(file_series=file_series)
+ self._testH5Image(h5_image)
+
+
def suite():
loadTests = unittest.defaultTestLoader.loadTestsFromTestCase
test_suite = unittest.TestSuite()
test_suite.addTest(loadTests(TestFabioH5))
+ test_suite.addTest(loadTests(TestFabioH5MultiFrames))
test_suite.addTest(loadTests(TestFabioH5WithEdf))
+ test_suite.addTest(loadTests(TestFabioH5WithFileSeries))
return test_suite
diff --git a/silx/io/test/test_nxdata.py b/silx/io/test/test_nxdata.py
index f891db9..f7ea8a4 100644
--- a/silx/io/test/test_nxdata.py
+++ b/silx/io/test/test_nxdata.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +25,7 @@
__authors__ = ["P. Knobel"]
__license__ = "MIT"
-__date__ = "27/09/2016"
+__date__ = "27/01/2018"
try:
import h5py
@@ -36,6 +36,10 @@ import tempfile
import unittest
from .. import nxdata
+from silx.third_party import six
+
+text_dtype = h5py.special_dtype(vlen=six.text_type)
+
@unittest.skipIf(h5py is None, "silx.io.nxdata tests depend on h5py")
class TestNXdata(unittest.TestCase):
@@ -71,9 +75,16 @@ class TestNXdata(unittest.TestCase):
g1d0 = g1d.create_group("1D_spectrum")
g1d0.attrs["NX_class"] = "NXdata"
g1d0.attrs["signal"] = "count"
+ g1d0.attrs["auxiliary_signals"] = numpy.array(["count2", "count3"],
+ dtype=text_dtype)
g1d0.attrs["axes"] = "energy_calib"
- g1d0.attrs["uncertainties"] = b"energy_errors",
+ g1d0.attrs["uncertainties"] = numpy.array(["energy_errors", ],
+ dtype=text_dtype)
g1d0.create_dataset("count", data=numpy.arange(10))
+ g1d0.create_dataset("count2", data=0.5 * numpy.arange(10))
+ d = g1d0.create_dataset("count3", data=0.4 * numpy.arange(10))
+ d.attrs["long_name"] = "3rd counter"
+ g1d0.create_dataset("title", data="Title as dataset (like nexpy)")
g1d0.create_dataset("energy_calib", data=(10, 5)) # 10 * idx + 5
g1d0.create_dataset("energy_errors", data=3.14 * numpy.random.rand(10))
@@ -86,7 +97,7 @@ class TestNXdata(unittest.TestCase):
g1d2 = g1d.create_group("4D_spectra")
g1d2.attrs["NX_class"] = "NXdata"
g1d2.attrs["signal"] = "counts"
- g1d2.attrs["axes"] = b"energy",
+ g1d2.attrs["axes"] = numpy.array(["energy", ], dtype=text_dtype)
ds = g1d2.create_dataset("counts", data=numpy.arange(2 * 2 * 3 * 10).reshape((2, 2, 3, 10)))
ds.attrs["interpretation"] = "spectrum"
ds = g1d2.create_dataset("errors", data=4.5 * numpy.random.rand(2, 2, 3, 10))
@@ -103,8 +114,11 @@ class TestNXdata(unittest.TestCase):
g2d0 = g2d.create_group("2D_regular_image")
g2d0.attrs["NX_class"] = "NXdata"
g2d0.attrs["signal"] = "image"
- g2d0.attrs["axes"] = b"rows_calib", b"columns_coordinates"
+ g2d0.attrs["auxiliary_signals"] = "image2"
+ g2d0.attrs["axes"] = numpy.array(["rows_calib", "columns_coordinates"],
+ dtype=text_dtype)
g2d0.create_dataset("image", data=numpy.arange(4 * 6).reshape((4, 6)))
+ g2d0.create_dataset("image2", data=numpy.arange(4 * 6).reshape((4, 6)))
ds = g2d0.create_dataset("rows_calib", data=(10, 5))
ds.attrs["long_name"] = "Calibrated Y"
g2d0.create_dataset("columns_coordinates", data=0.5 + 0.02 * numpy.arange(6))
@@ -112,7 +126,9 @@ class TestNXdata(unittest.TestCase):
g2d1 = g2d.create_group("2D_irregular_data")
g2d1.attrs["NX_class"] = "NXdata"
g2d1.attrs["signal"] = "data"
- g2d1.attrs["axes"] = b"rows_coordinates", b"columns_coordinates"
+ g2d1.attrs["title"] = "Title as group attr"
+ g2d1.attrs["axes"] = numpy.array(["rows_coordinates", "columns_coordinates"],
+ dtype=text_dtype)
g2d1.create_dataset("data", data=numpy.arange(64 * 128).reshape((64, 128)))
g2d1.create_dataset("rows_coordinates", data=numpy.arange(64) + numpy.random.rand(64))
g2d1.create_dataset("columns_coordinates", data=numpy.arange(128) + 2.5 * numpy.random.rand(128))
@@ -126,19 +142,33 @@ class TestNXdata(unittest.TestCase):
g2d3 = g2d.create_group("5D_images")
g2d3.attrs["NX_class"] = "NXdata"
g2d3.attrs["signal"] = "images"
- g2d3.attrs["axes"] = b"rows_coordinates", b"columns_coordinates"
+ g2d3.attrs["axes"] = numpy.array(["rows_coordinates", "columns_coordinates"],
+ dtype=text_dtype)
ds = g2d3.create_dataset("images", data=numpy.arange(2 * 2 * 2 * 4 * 6).reshape((2, 2, 2, 4, 6)))
ds.attrs["interpretation"] = "image"
g2d3.create_dataset("rows_coordinates", data=5 + 10 * numpy.arange(4))
g2d3.create_dataset("columns_coordinates", data=0.5 + 0.02 * numpy.arange(6))
+ g2d4 = g2d.create_group("RGBA_image")
+ g2d4.attrs["NX_class"] = "NXdata"
+ g2d4.attrs["signal"] = "image"
+ g2d4.attrs["axes"] = numpy.array(["rows_calib", "columns_coordinates"],
+ dtype=text_dtype)
+ rgba_image = numpy.linspace(0, 1, num=7*8*3).reshape((7, 8, 3))
+ rgba_image[:, :, 1] = 1 - rgba_image[:, :, 1] # invert G channel to add some color
+ ds = g2d4.create_dataset("image", data=rgba_image)
+ ds.attrs["interpretation"] = "rgba-image"
+ ds = g2d4.create_dataset("rows_calib", data=(10, 5))
+ ds.attrs["long_name"] = "Calibrated Y"
+ g2d4.create_dataset("columns_coordinates", data=0.5+0.02*numpy.arange(8))
+
# SCATTER
g = self.h5f.create_group("scatters")
gd0 = g.create_group("x_y_scatter")
gd0.attrs["NX_class"] = "NXdata"
gd0.attrs["signal"] = "y"
- gd0.attrs["axes"] = b"x",
+ gd0.attrs["axes"] = numpy.array(["x", ], dtype=text_dtype)
gd0.create_dataset("y", data=numpy.random.rand(128) - 0.5)
gd0.create_dataset("x", data=2 * numpy.random.rand(128))
gd0.create_dataset("x_errors", data=0.05 * numpy.random.rand(128))
@@ -147,7 +177,7 @@ class TestNXdata(unittest.TestCase):
gd1 = g.create_group("x_y_value_scatter")
gd1.attrs["NX_class"] = "NXdata"
gd1.attrs["signal"] = "values"
- gd1.attrs["axes"] = b"x", b"y"
+ gd1.attrs["axes"] = numpy.array(["x", "y"], dtype=text_dtype)
gd1.create_dataset("values", data=3.14 * numpy.random.rand(128))
gd1.create_dataset("y", data=numpy.random.rand(128))
gd1.create_dataset("y_errors", data=0.02 * numpy.random.rand(128))
@@ -199,6 +229,7 @@ class TestNXdata(unittest.TestCase):
def testSpectra(self):
nxd = nxdata.NXdata(self.h5f["spectra/1D_spectrum"])
self.assertTrue(nxd.signal_is_1d)
+ self.assertTrue(nxd.is_curve)
self.assertTrue(numpy.array_equal(numpy.array(nxd.signal),
numpy.arange(10)))
self.assertEqual(nxd.axes_names, ["energy_calib"])
@@ -208,9 +239,18 @@ class TestNXdata(unittest.TestCase):
self.assertIsNone(nxd.errors)
self.assertFalse(nxd.is_scatter or nxd.is_x_y_value_scatter)
self.assertIsNone(nxd.interpretation)
+ self.assertEqual(nxd.title, "Title as dataset (like nexpy)")
+
+ self.assertEqual(nxd.auxiliary_signals_dataset_names,
+ ["count2", "count3"])
+ self.assertEqual(nxd.auxiliary_signals_names,
+ ["count2", "3rd counter"])
+ self.assertAlmostEqual(nxd.auxiliary_signals[1][2],
+ 0.8) # numpy.arange(10) * 0.4
nxd = nxdata.NXdata(self.h5f["spectra/2D_spectra"])
self.assertTrue(nxd.signal_is_2d)
+ self.assertTrue(nxd.is_curve)
self.assertEqual(nxd.axes_names, [None, None])
self.assertEqual(nxd.axes_dataset_names, [None, None])
self.assertEqual(nxd.axes, [None, None])
@@ -221,6 +261,7 @@ class TestNXdata(unittest.TestCase):
nxd = nxdata.NXdata(self.h5f["spectra/4D_spectra"])
self.assertFalse(nxd.signal_is_0d or nxd.signal_is_1d or
nxd.signal_is_2d or nxd.signal_is_3d)
+ self.assertTrue(nxd.is_curve)
self.assertEqual(nxd.axes_names,
[None, None, None, "Calibrated energy"])
self.assertEqual(nxd.axes_dataset_names,
@@ -242,15 +283,19 @@ class TestNXdata(unittest.TestCase):
def testImages(self):
nxd = nxdata.NXdata(self.h5f["images/2D_regular_image"])
self.assertTrue(nxd.signal_is_2d)
+ self.assertTrue(nxd.is_image)
self.assertEqual(nxd.axes_names, ["Calibrated Y", "columns_coordinates"])
self.assertEqual(list(nxd.axes_dataset_names),
["rows_calib", "columns_coordinates"])
self.assertIsNone(nxd.errors)
self.assertFalse(nxd.is_scatter or nxd.is_x_y_value_scatter)
self.assertIsNone(nxd.interpretation)
+ self.assertEqual(len(nxd.auxiliary_signals), 1)
+ self.assertEqual(nxd.auxiliary_signals_names, ["image2"])
nxd = nxdata.NXdata(self.h5f["images/2D_irregular_data"])
self.assertTrue(nxd.signal_is_2d)
+ self.assertTrue(nxd.is_image)
self.assertEqual(nxd.axes_dataset_names, nxd.axes_names)
self.assertEqual(list(nxd.axes_dataset_names),
@@ -259,8 +304,10 @@ class TestNXdata(unittest.TestCase):
self.assertIsNone(nxd.errors)
self.assertFalse(nxd.is_scatter or nxd.is_x_y_value_scatter)
self.assertIsNone(nxd.interpretation)
+ self.assertEqual(nxd.title, "Title as group attr")
nxd = nxdata.NXdata(self.h5f["images/5D_images"])
+ self.assertTrue(nxd.is_image)
self.assertFalse(nxd.signal_is_0d or nxd.signal_is_1d or
nxd.signal_is_2d or nxd.signal_is_3d)
self.assertEqual(nxd.axes_names,
@@ -271,6 +318,16 @@ class TestNXdata(unittest.TestCase):
self.assertFalse(nxd.is_scatter or nxd.is_x_y_value_scatter)
self.assertEqual(nxd.interpretation, "image")
+ nxd = nxdata.NXdata(self.h5f["images/RGBA_image"])
+ self.assertTrue(nxd.is_image)
+ self.assertEqual(nxd.interpretation, "rgba-image")
+ self.assertTrue(nxd.signal_is_3d)
+ self.assertEqual(nxd.axes_names, ["Calibrated Y",
+ "columns_coordinates",
+ None])
+ self.assertEqual(list(nxd.axes_dataset_names),
+ ["rows_calib", "columns_coordinates", None])
+
def testScatters(self):
nxd = nxdata.NXdata(self.h5f["scatters/x_y_scatter"])
self.assertTrue(nxd.signal_is_1d)
@@ -301,10 +358,206 @@ class TestNXdata(unittest.TestCase):
self.assertIsNone(nxd.interpretation)
+@unittest.skipIf(h5py is None, "silx.io.nxdata tests depend on h5py")
+class TestLegacyNXdata(unittest.TestCase):
+ def setUp(self):
+ tmp = tempfile.NamedTemporaryFile(prefix="nxdata_legacy_examples_",
+ suffix=".h5", delete=True)
+ tmp.file.close()
+ self.h5fname = tmp.name
+ self.h5f = h5py.File(tmp.name, "w")
+
+ def tearDown(self):
+ self.h5f.close()
+
+ def testSignalAttrOnDataset(self):
+ g = self.h5f.create_group("2D")
+ g.attrs["NX_class"] = "NXdata"
+
+ ds0 = g.create_dataset("image0",
+ data=numpy.arange(4 * 6).reshape((4, 6)))
+ ds0.attrs["signal"] = 1
+ ds0.attrs["long_name"] = "My first image"
+
+ ds1 = g.create_dataset("image1",
+ data=numpy.arange(4 * 6).reshape((4, 6)))
+ ds1.attrs["signal"] = "2"
+ ds1.attrs["long_name"] = "My 2nd image"
+
+ ds2 = g.create_dataset("image2",
+ data=numpy.arange(4 * 6).reshape((4, 6)))
+ ds2.attrs["signal"] = 3
+
+ nxd = nxdata.NXdata(self.h5f["2D"])
+
+ self.assertEqual(nxd.signal_dataset_name, "image0")
+ self.assertEqual(nxd.signal_name, "My first image")
+ self.assertEqual(nxd.signal.shape,
+ (4, 6))
+
+ self.assertEqual(len(nxd.auxiliary_signals), 2)
+ self.assertEqual(nxd.auxiliary_signals[1].shape,
+ (4, 6))
+
+ self.assertEqual(nxd.auxiliary_signals_dataset_names,
+ ["image1", "image2"])
+ self.assertEqual(nxd.auxiliary_signals_names,
+ ["My 2nd image", "image2"])
+
+ def testAxesOnSignalDataset(self):
+ g = self.h5f.create_group("2D")
+ g.attrs["NX_class"] = "NXdata"
+
+ ds0 = g.create_dataset("image0",
+ data=numpy.arange(4 * 6).reshape((4, 6)))
+ ds0.attrs["signal"] = 1
+ ds0.attrs["axes"] = "yaxis:xaxis"
+
+ ds1 = g.create_dataset("yaxis",
+ data=numpy.arange(4))
+ ds2 = g.create_dataset("xaxis",
+ data=numpy.arange(6))
+
+ nxd = nxdata.NXdata(self.h5f["2D"])
+
+ self.assertEqual(nxd.axes_dataset_names,
+ ["yaxis", "xaxis"])
+ self.assertTrue(numpy.array_equal(nxd.axes[0],
+ numpy.arange(4)))
+ self.assertTrue(numpy.array_equal(nxd.axes[1],
+ numpy.arange(6)))
+
+ def testAxesOnAxesDatasets(self):
+ g = self.h5f.create_group("2D")
+ g.attrs["NX_class"] = "NXdata"
+
+ ds0 = g.create_dataset("image0",
+ data=numpy.arange(4 * 6).reshape((4, 6)))
+ ds0.attrs["signal"] = 1
+ ds1 = g.create_dataset("yaxis",
+ data=numpy.arange(4))
+ ds1.attrs["axis"] = 0
+ ds2 = g.create_dataset("xaxis",
+ data=numpy.arange(6))
+ ds2.attrs["axis"] = "1"
+
+ nxd = nxdata.NXdata(self.h5f["2D"])
+ self.assertEqual(nxd.axes_dataset_names,
+ ["yaxis", "xaxis"])
+ self.assertTrue(numpy.array_equal(nxd.axes[0],
+ numpy.arange(4)))
+ self.assertTrue(numpy.array_equal(nxd.axes[1],
+ numpy.arange(6)))
+
+
+class TestSaveNXdata(unittest.TestCase):
+ def setUp(self):
+ tmp = tempfile.NamedTemporaryFile(prefix="nxdata",
+ suffix=".h5", delete=True)
+ tmp.file.close()
+ self.h5fname = tmp.name
+
+ def testSimpleSave(self):
+ sig = numpy.array([0, 1, 2])
+ a0 = numpy.array([2, 3, 4])
+ a1 = numpy.array([3, 4, 5])
+ nxdata.save_NXdata(filename=self.h5fname,
+ signal=sig,
+ axes=[a0, a1],
+ signal_name="sig",
+ axes_names=["a0", "a1"],
+ nxentry_name="a",
+ nxdata_name="mydata")
+
+ h5f = h5py.File(self.h5fname, "r")
+ self.assertTrue(nxdata.is_valid_nxdata(h5f["a/mydata"]))
+
+ nxd = nxdata.NXdata(h5f["/a/mydata"])
+ self.assertTrue(numpy.array_equal(nxd.signal,
+ sig))
+ self.assertTrue(numpy.array_equal(nxd.axes[0],
+ a0))
+
+ h5f.close()
+
+ def testSimplestSave(self):
+ sig = numpy.array([0, 1, 2])
+ nxdata.save_NXdata(filename=self.h5fname,
+ signal=sig)
+
+ h5f = h5py.File(self.h5fname, "r")
+
+ self.assertTrue(nxdata.is_valid_nxdata(h5f["/entry/data0"]))
+
+ nxd = nxdata.NXdata(h5f["/entry/data0"])
+ self.assertTrue(numpy.array_equal(nxd.signal,
+ sig))
+ h5f.close()
+
+ def testSaveDefaultAxesNames(self):
+ sig = numpy.array([0, 1, 2])
+ a0 = numpy.array([2, 3, 4])
+ a1 = numpy.array([3, 4, 5])
+ nxdata.save_NXdata(filename=self.h5fname,
+ signal=sig,
+ axes=[a0, a1],
+ signal_name="sig",
+ axes_names=None,
+ axes_long_names=["a", "b"],
+ nxentry_name="a",
+ nxdata_name="mydata")
+
+ h5f = h5py.File(self.h5fname, "r")
+ self.assertTrue(nxdata.is_valid_nxdata(h5f["a/mydata"]))
+
+ nxd = nxdata.NXdata(h5f["/a/mydata"])
+ self.assertTrue(numpy.array_equal(nxd.signal,
+ sig))
+ self.assertTrue(numpy.array_equal(nxd.axes[0],
+ a0))
+ self.assertEqual(nxd.axes_dataset_names,
+ [u"dim0", u"dim1"])
+ self.assertEqual(nxd.axes_names,
+ [u"a", u"b"])
+
+ h5f.close()
+
+ def testSaveToExistingEntry(self):
+ h5f = h5py.File(self.h5fname, "w")
+ g = h5f.create_group("myentry")
+ g.attrs["NX_class"] = "NXentry"
+ h5f.close()
+
+ sig = numpy.array([0, 1, 2])
+ a0 = numpy.array([2, 3, 4])
+ a1 = numpy.array([3, 4, 5])
+ nxdata.save_NXdata(filename=self.h5fname,
+ signal=sig,
+ axes=[a0, a1],
+ signal_name="sig",
+ axes_names=["a0", "a1"],
+ nxentry_name="myentry",
+ nxdata_name="toto")
+
+ h5f = h5py.File(self.h5fname, "r")
+ self.assertTrue(nxdata.is_valid_nxdata(h5f["myentry/toto"]))
+
+ nxd = nxdata.NXdata(h5f["myentry/toto"])
+ self.assertTrue(numpy.array_equal(nxd.signal,
+ sig))
+ self.assertTrue(numpy.array_equal(nxd.axes[0],
+ a0))
+ h5f.close()
+
+
def suite():
test_suite = unittest.TestSuite()
test_suite.addTest(
unittest.defaultTestLoader.loadTestsFromTestCase(TestNXdata))
+ test_suite.addTest(
+ unittest.defaultTestLoader.loadTestsFromTestCase(TestLegacyNXdata))
+ test_suite.addTest(
+ unittest.defaultTestLoader.loadTestsFromTestCase(TestSaveNXdata))
return test_suite
diff --git a/silx/io/test/test_specfile.py b/silx/io/test/test_specfile.py
index 0aef2e2..9236fee 100644
--- a/silx/io/test/test_specfile.py
+++ b/silx/io/test/test_specfile.py
@@ -25,9 +25,9 @@
__authors__ = ["P. Knobel", "V.A. Sole"]
__license__ = "MIT"
-__date__ = "03/08/2017"
+__date__ = "17/01/2018"
+
-import gc
import locale
import logging
import numpy
@@ -36,7 +36,7 @@ import sys
import tempfile
import unittest
-from silx.test import utils
+from silx.utils import testutils
from ..specfile import SpecFile, Scan
from .. import specfile
@@ -136,14 +136,14 @@ class TestSpecFile(unittest.TestCase):
@classmethod
def setUpClass(cls):
fd, cls.fname1 = tempfile.mkstemp(text=False)
- if sys.version < '3.0':
+ if sys.version_info < (3, ):
os.write(fd, sftext)
else:
os.write(fd, bytes(sftext, 'ascii'))
os.close(fd)
fd2, cls.fname2 = tempfile.mkstemp(text=False)
- if sys.version < '3.0':
+ if sys.version_info < (3, ):
os.write(fd2, sftext[370:923])
else:
os.write(fd2, bytes(sftext[370:923], 'ascii'))
@@ -151,7 +151,7 @@ class TestSpecFile(unittest.TestCase):
fd3, cls.fname3 = tempfile.mkstemp(text=False)
txt = sftext[371:923]
- if sys.version < '3.0':
+ if sys.version_info < (3, ):
os.write(fd3, txt)
else:
os.write(fd3, bytes(txt, 'ascii'))
@@ -177,16 +177,9 @@ class TestSpecFile(unittest.TestCase):
self.scan1_no_fhdr_crash = self.sf_no_fhdr_crash[0]
def tearDown(self):
- del self.sf
- del self.sf_no_fhdr
- del self.scan1
- del self.scan1_2
- del self.scan25
- del self.scan1_no_fhdr
- del self.sf_no_fhdr_crash
- del self.scan1_no_fhdr_crash
- del self.empty_scan
- gc.collect()
+ self.sf.close()
+ self.sf_no_fhdr.close()
+ self.sf_no_fhdr_crash.close()
def test_open(self):
self.assertIsInstance(self.sf, SpecFile)
@@ -376,7 +369,7 @@ class TestSpecFile(unittest.TestCase):
self.assertEqual(self.scan25.mca.channels,
[])
- @utils.test_logging(specfile._logger.name, warning=1)
+ @testutils.test_logging(specfile._logger.name, warning=1)
def test_empty_scan(self):
"""Test reading a scan with no data points"""
self.assertEqual(len(self.empty_scan.labels),
@@ -389,7 +382,7 @@ class TestSFLocale(unittest.TestCase):
@classmethod
def setUpClass(cls):
fd, cls.fname = tempfile.mkstemp(text=False)
- if sys.version < '3.0':
+ if sys.version_info < (3, ):
os.write(fd, sftext)
else:
os.write(fd, bytes(sftext, 'ascii'))
@@ -399,13 +392,12 @@ class TestSFLocale(unittest.TestCase):
def tearDownClass(cls):
os.unlink(cls.fname)
locale.setlocale(locale.LC_NUMERIC, loc) # restore saved locale
- gc.collect()
def crunch_data(self):
self.sf3 = SpecFile(self.fname)
self.assertAlmostEqual(self.sf3[0].data_line(1)[2],
1.56)
- del self.sf3
+ self.sf3.close()
@unittest.skipIf(not try_DE, "de_DE.utf8 locale not installed")
def test_locale_de_DE(self):
diff --git a/silx/io/test/test_specfilewrapper.py b/silx/io/test/test_specfilewrapper.py
index c5b0f39..2f463fa 100644
--- a/silx/io/test/test_specfilewrapper.py
+++ b/silx/io/test/test_specfilewrapper.py
@@ -27,7 +27,6 @@ __authors__ = ["P. Knobel"]
__license__ = "MIT"
__date__ = "15/05/2017"
-import gc
import locale
import logging
import numpy
@@ -114,23 +113,15 @@ class TestSpecfilewrapper(unittest.TestCase):
@classmethod
def setUpClass(cls):
fd, cls.fname1 = tempfile.mkstemp(text=False)
- if sys.version < '3.0':
+ if sys.version_info < (3, ):
os.write(fd, sftext)
else:
os.write(fd, bytes(sftext, 'ascii'))
os.close(fd)
- fd2, cls.fname2 = tempfile.mkstemp(text=False)
- if sys.version < '3.0':
- os.write(fd2, sftext[370:-97])
- else:
- os.write(fd2, bytes(sftext[370:-97], 'ascii'))
- os.close(fd2)
-
@classmethod
def tearDownClass(cls):
os.unlink(cls.fname1)
- os.unlink(cls.fname2)
def setUp(self):
self.sf = Specfile(self.fname1)
@@ -139,11 +130,7 @@ class TestSpecfilewrapper(unittest.TestCase):
self.scan25 = self.sf.select("25.1")
def tearDown(self):
- del self.sf
- del self.scan1
- del self.scan1_2
- del self.scan25
- gc.collect()
+ self.sf.close()
def test_number_of_scans(self):
self.assertEqual(3, len(self.sf))
diff --git a/silx/io/test/test_spech5.py b/silx/io/test/test_spech5.py
index 1d04c6f..b842243 100644
--- a/silx/io/test/test_spech5.py
+++ b/silx/io/test/test_spech5.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,6 @@
#
# ############################################################################*/
"""Tests for spech5"""
-import gc
from numpy import array_equal
import os
import io
@@ -32,11 +31,10 @@ import unittest
import datetime
from functools import partial
-from silx.test import utils
+from silx.utils import testutils
from .. import spech5
-from ..spech5 import (SpecH5, SpecH5Group,
- SpecH5Dataset, spec_date_to_iso8601)
+from ..spech5 import (SpecH5, SpecH5Dataset, spec_date_to_iso8601)
from .. import specfile
try:
@@ -46,7 +44,7 @@ except ImportError:
__authors__ = ["P. Knobel"]
__license__ = "MIT"
-__date__ = "26/07/2017"
+__date__ = "12/02/2018"
sftext = """#F /tmp/sf.dat
#E 1455180875
@@ -216,7 +214,7 @@ class TestSpecH5(unittest.TestCase):
@classmethod
def setUpClass(cls):
fd, cls.fname = tempfile.mkstemp()
- if sys.version < '3.0':
+ if sys.version_info < (3, ):
os.write(fd, sftext)
else:
os.write(fd, bytes(sftext, 'ascii'))
@@ -230,9 +228,7 @@ class TestSpecH5(unittest.TestCase):
self.sfh5 = SpecH5(self.fname)
def tearDown(self):
- # fix Win32 permission error when deleting temp file
- del self.sfh5
- gc.collect()
+ self.sfh5.close()
def testContainsFile(self):
self.assertIn("/1.2/measurement", self.sfh5)
@@ -275,9 +271,9 @@ class TestSpecH5(unittest.TestCase):
def testDate(self):
# start time is in Iso8601 format
self.assertEqual(self.sfh5["/1.1/start_time"],
- b"2016-02-11T09:55:20")
+ u"2016-02-11T09:55:20")
self.assertEqual(self.sfh5["25.1/start_time"],
- b"2015-03-14T03:53:50")
+ u"2015-03-14T03:53:50")
def testDatasetInstanceAttr(self):
"""The SpecH5Dataset objects must implement some dummy attributes
@@ -299,7 +295,7 @@ class TestSpecH5(unittest.TestCase):
-3)
self.assertEqual(self.sfh5.get("/1.1/start_time", default=-3),
- b"2016-02-11T09:55:20")
+ u"2016-02-11T09:55:20")
def testGetClass(self):
"""Test :meth:`SpecH5Group.get`"""
@@ -355,33 +351,22 @@ class TestSpecH5(unittest.TestCase):
def testHeader(self):
file_header = self.sfh5["/1.2/instrument/specfile/file_header"]
scan_header = self.sfh5["/1.2/instrument/specfile/scan_header"]
- # convert ndarray(dtype=numpy.string_) to str
- if sys.version < '3.0':
- file_header = str(file_header[()])
- scan_header = str(scan_header[()])
- else:
- file_header = str(file_header.astype(str))
- scan_header = str(scan_header.astype(str))
# File header has 10 lines
- self.assertEqual(len(file_header.split("\n")), 10)
+ self.assertEqual(len(file_header), 10)
# 1.2 has 9 scan & mca header lines
- self.assertEqual(len(scan_header.split("\n")), 9)
+ self.assertEqual(len(scan_header), 9)
# line 4 of file header
self.assertEqual(
- file_header.split("\n")[3],
- "#C imaging User = opid17")
+ file_header[3],
+ u"#C imaging User = opid17")
# line 4 of scan header
scan_header = self.sfh5["25.1/instrument/specfile/scan_header"]
- if sys.version < '3.0':
- scan_header = str(scan_header[()])
- else:
- scan_header = str(scan_header[()].astype(str))
self.assertEqual(
- scan_header.split("\n")[3],
- "#P1 4.74255 6.197579 2.238283")
+ scan_header[3],
+ u"#P1 4.74255 6.197579 2.238283")
def testLinks(self):
self.assertTrue(
@@ -493,7 +478,7 @@ class TestSpecH5(unittest.TestCase):
def testTitle(self):
self.assertEqual(self.sfh5["/25.1/title"],
- b"25 ascan c3th 1.33245 1.52245 40 0.15")
+ u"ascan c3th 1.33245 1.52245 40 0.15")
def testValues(self):
group = self.sfh5["/25.1"]
@@ -582,9 +567,9 @@ class TestSpecH5(unittest.TestCase):
# All 0 values
self.assertNotIn("sample", self.sfh5["/1001.1"])
with self.assertRaises(KeyError):
- uc = self.sfh5["/1001.1/sample/unit_cell"]
+ self.sfh5["/1001.1/sample/unit_cell"]
- @utils.test_logging(spech5.logger1.name, warning=2)
+ @testutils.test_logging(spech5.logger1.name, warning=2)
def testOpenFileDescriptor(self):
"""Open a SpecH5 file from a file descriptor"""
with io.open(self.sfh5.filename) as f:
@@ -593,6 +578,7 @@ class TestSpecH5(unittest.TestCase):
name_list = []
# check if the object is working
self.sfh5.visit(name_list.append)
+ sfh5.close()
sftext_multi_mca_headers = """
@@ -624,7 +610,7 @@ class TestSpecH5MultiMca(unittest.TestCase):
@classmethod
def setUpClass(cls):
fd, cls.fname = tempfile.mkstemp(text=False)
- if sys.version < '3.0':
+ if sys.version_info < (3, ):
os.write(fd, sftext_multi_mca_headers)
else:
os.write(fd, bytes(sftext_multi_mca_headers, 'ascii'))
@@ -638,9 +624,7 @@ class TestSpecH5MultiMca(unittest.TestCase):
self.sfh5 = SpecH5(self.fname)
def tearDown(self):
- # fix Win32 permission error when deleting temp file
- del self.sfh5
- gc.collect()
+ self.sfh5.close()
def testMcaCalib(self):
mca0_calib = self.sfh5["/1.1/measurement/mca_0/info/calibration"]
@@ -691,7 +675,7 @@ sftext_no_cols = r"""#F C:/DATA\test.mca
#D Thu Jul 7 08:40:19 2016
#C no data cols, one mca analyser, single spectrum
#@MCA %16C
-#@CHANN 151 29 29 1
+#@CHANN 151 0 150 1
#@CALIB 0 2 0
@A 789 784 788 814 847 862 880 904 925 955 987 1015 1031 1070 1111 1139 \
1203 1236 1290 1392 1492 1558 1688 1813 1977 2119 2346 2699 3121 3542 4102 4970 \
@@ -756,7 +740,7 @@ class TestSpecH5NoDataCols(unittest.TestCase):
@classmethod
def setUpClass(cls):
fd, cls.fname = tempfile.mkstemp()
- if sys.version < '3.0':
+ if sys.version_info < (3, ):
os.write(fd, sftext_no_cols)
else:
os.write(fd, bytes(sftext_no_cols, 'ascii'))
@@ -770,9 +754,7 @@ class TestSpecH5NoDataCols(unittest.TestCase):
self.sfh5 = SpecH5(self.fname)
def tearDown(self):
- # fix Win32 permission error when deleting temp file
- del self.sfh5
- gc.collect()
+ self.sfh5.close()
def testScan1(self):
# 1.1: single analyser, single spectrum, 151 channels
@@ -829,7 +811,7 @@ class TestSpecH5SlashInLabels(unittest.TestCase):
@classmethod
def setUpClass(cls):
fd, cls.fname = tempfile.mkstemp()
- if sys.version < '3.0':
+ if sys.version_info < (3, ):
os.write(fd, sf_text_slash)
else:
os.write(fd, bytes(sf_text_slash, 'ascii'))
@@ -843,9 +825,7 @@ class TestSpecH5SlashInLabels(unittest.TestCase):
self.sfh5 = SpecH5(self.fname)
def tearDown(self):
- # fix Win32 permission error when deleting temp file
- del self.sfh5
- gc.collect()
+ self.sfh5.close()
def testLabels(self):
"""Ensure `/` is substituted with `%` and
diff --git a/silx/io/test/test_spectoh5.py b/silx/io/test/test_spectoh5.py
index 421c48b..8020731 100644
--- a/silx/io/test/test_spectoh5.py
+++ b/silx/io/test/test_spectoh5.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,8 +23,7 @@
# ############################################################################*/
"""Tests for SpecFile to HDF5 converter"""
-import gc
-from numpy import array_equal, string_
+from numpy import array_equal
import os
import sys
import tempfile
@@ -41,7 +40,7 @@ else:
__authors__ = ["P. Knobel"]
__license__ = "MIT"
-__date__ = "02/06/2017"
+__date__ = "12/02/2018"
sftext = """#F /tmp/sf.dat
@@ -93,7 +92,7 @@ class TestConvertSpecHDF5(unittest.TestCase):
@classmethod
def setUpClass(cls):
fd, cls.spec_fname = tempfile.mkstemp(text=False)
- if sys.version < '3.0':
+ if sys.version_info < (3, ):
os.write(fd, sftext)
else:
os.write(fd, bytes(sftext, 'ascii'))
@@ -115,11 +114,9 @@ class TestConvertSpecHDF5(unittest.TestCase):
self.h5f = h5py.File(self.h5_fname, "a")
def tearDown(self):
- del self.sfh5
self.h5f.close()
- del self.h5f
+ self.sfh5.close()
os.unlink(self.h5_fname)
- gc.collect()
def testAppendToHDF5(self):
write_to_h5(self.sfh5, self.h5f, h5path="/foo/bar/spam")
@@ -141,24 +138,22 @@ class TestConvertSpecHDF5(unittest.TestCase):
def testTitle(self):
"""Test the value of a dataset"""
title12 = self.h5f["/1.2/title"].value
- if sys.version > '3.0':
- title12 = title12.decode()
self.assertEqual(title12,
- "1 aaaaaa")
+ u"aaaaaa")
def testAttrs(self):
# Test root group (file) attributes
self.assertEqual(self.h5f.attrs["NX_class"],
- string_("NXroot"))
+ u"NXroot")
# Test dataset attributes
ds = self.h5f["/1.2/instrument/mca_1/data"]
self.assertTrue("interpretation" in ds.attrs)
self.assertEqual(list(ds.attrs.values()),
- [string_("spectrum")])
+ [u"spectrum"])
# Test group attributes
grp = self.h5f["1.1"]
self.assertEqual(grp.attrs["NX_class"],
- string_("NXentry"))
+ u"NXentry")
self.assertEqual(len(list(grp.attrs.keys())),
1)
diff --git a/silx/io/test/test_url.py b/silx/io/test/test_url.py
new file mode 100644
index 0000000..5093fc2
--- /dev/null
+++ b/silx/io/test/test_url.py
@@ -0,0 +1,209 @@
+# coding: utf-8
+# /*##########################################################################
+# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ############################################################################*/
+"""Tests for url module"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "29/01/2018"
+
+
+import unittest
+from ..url import DataUrl
+
+
+class TestDataUrl(unittest.TestCase):
+
+ def assertUrl(self, url, expected):
+ self.assertEqual(url.is_valid(), expected[0])
+ self.assertEqual(url.is_absolute(), expected[1])
+ self.assertEqual(url.scheme(), expected[2])
+ self.assertEqual(url.file_path(), expected[3])
+ self.assertEqual(url.data_path(), expected[4])
+ self.assertEqual(url.data_slice(), expected[5])
+
+ def test_fabio_absolute(self):
+ url = DataUrl("fabio:///data/image.edf?slice=2")
+ expected = [True, True, "fabio", "/data/image.edf", None, (2, )]
+ self.assertUrl(url, expected)
+
+ def test_fabio_absolute_windows(self):
+ url = DataUrl("fabio:///C:/data/image.edf?slice=2")
+ expected = [True, True, "fabio", "C:/data/image.edf", None, (2, )]
+ self.assertUrl(url, expected)
+
+ def test_silx_absolute(self):
+ url = DataUrl("silx:///data/image.h5?path=/data/dataset&slice=1,5")
+ expected = [True, True, "silx", "/data/image.h5", "/data/dataset", (1, 5)]
+ self.assertUrl(url, expected)
+
+ def test_commandline_shell_separator(self):
+ url = DataUrl("silx:///data/image.h5::path=/data/dataset&slice=1,5")
+ expected = [True, True, "silx", "/data/image.h5", "/data/dataset", (1, 5)]
+ self.assertUrl(url, expected)
+
+ def test_silx_absolute2(self):
+ url = DataUrl("silx:///data/image.edf?/scan_0/detector/data")
+ expected = [True, True, "silx", "/data/image.edf", "/scan_0/detector/data", None]
+ self.assertUrl(url, expected)
+
+ def test_silx_absolute_windows(self):
+ url = DataUrl("silx:///C:/data/image.h5?/scan_0/detector/data")
+ expected = [True, True, "silx", "C:/data/image.h5", "/scan_0/detector/data", None]
+ self.assertUrl(url, expected)
+
+ def test_silx_relative(self):
+ url = DataUrl("silx:./image.h5")
+ expected = [True, False, "silx", "./image.h5", None, None]
+ self.assertUrl(url, expected)
+
+ def test_fabio_relative(self):
+ url = DataUrl("fabio:./image.edf")
+ expected = [True, False, "fabio", "./image.edf", None, None]
+ self.assertUrl(url, expected)
+
+ def test_silx_relative2(self):
+ url = DataUrl("silx:image.h5")
+ expected = [True, False, "silx", "image.h5", None, None]
+ self.assertUrl(url, expected)
+
+ def test_fabio_relative2(self):
+ url = DataUrl("fabio:image.edf")
+ expected = [True, False, "fabio", "image.edf", None, None]
+ self.assertUrl(url, expected)
+
+ def test_file_relative(self):
+ url = DataUrl("image.edf")
+ expected = [True, False, None, "image.edf", None, None]
+ self.assertUrl(url, expected)
+
+ def test_file_relative2(self):
+ url = DataUrl("./foo/bar/image.edf")
+ expected = [True, False, None, "./foo/bar/image.edf", None, None]
+ self.assertUrl(url, expected)
+
+ def test_file_relative3(self):
+ url = DataUrl("foo/bar/image.edf")
+ expected = [True, False, None, "foo/bar/image.edf", None, None]
+ self.assertUrl(url, expected)
+
+ def test_file_absolute(self):
+ url = DataUrl("/data/image.edf")
+ expected = [True, True, None, "/data/image.edf", None, None]
+ self.assertUrl(url, expected)
+
+ def test_file_absolute_windows(self):
+ url = DataUrl("C:/data/image.edf")
+ expected = [True, True, None, "C:/data/image.edf", None, None]
+ self.assertUrl(url, expected)
+
+ def test_absolute_with_path(self):
+ url = DataUrl("/foo/foobar.h5?/foo/bar")
+ expected = [True, True, None, "/foo/foobar.h5", "/foo/bar", None]
+ self.assertUrl(url, expected)
+
+ def test_windows_file_data_slice(self):
+ url = DataUrl("C:/foo/foobar.h5?path=/foo/bar&slice=5,1")
+ expected = [True, True, None, "C:/foo/foobar.h5", "/foo/bar", (5, 1)]
+ self.assertUrl(url, expected)
+
+ def test_scheme_file_data_slice(self):
+ url = DataUrl("silx:/foo/foobar.h5?path=/foo/bar&slice=5,1")
+ expected = [True, True, "silx", "/foo/foobar.h5", "/foo/bar", (5, 1)]
+ self.assertUrl(url, expected)
+
+ def test_scheme_windows_file_data_slice(self):
+ url = DataUrl("silx:C:/foo/foobar.h5?path=/foo/bar&slice=5,1")
+ expected = [True, True, "silx", "C:/foo/foobar.h5", "/foo/bar", (5, 1)]
+ self.assertUrl(url, expected)
+
+ def test_empty(self):
+ url = DataUrl("")
+ expected = [False, False, None, "", None, None]
+ self.assertUrl(url, expected)
+
+ def test_unknown_scheme(self):
+ url = DataUrl("foo:/foo/foobar.h5?path=/foo/bar&slice=5,1")
+ expected = [False, True, "foo", "/foo/foobar.h5", "/foo/bar", (5, 1)]
+ self.assertUrl(url, expected)
+
+ def test_slice(self):
+ url = DataUrl("/a.h5?path=/b&slice=5,1")
+ expected = [True, True, None, "/a.h5", "/b", (5, 1)]
+ self.assertUrl(url, expected)
+
+ def test_slice_ellipsis(self):
+ url = DataUrl("/a.h5?path=/b&slice=...")
+ expected = [True, True, None, "/a.h5", "/b", (Ellipsis, )]
+ self.assertUrl(url, expected)
+
+ def test_slice_slicing(self):
+ url = DataUrl("/a.h5?path=/b&slice=:")
+ expected = [True, True, None, "/a.h5", "/b", (slice(None), )]
+ self.assertUrl(url, expected)
+
+ def test_slice_missing_element(self):
+ url = DataUrl("/a.h5?path=/b&slice=5,,1")
+ expected = [False, True, None, "/a.h5", "/b", None]
+ self.assertUrl(url, expected)
+
+ def test_slice_no_elements(self):
+ url = DataUrl("/a.h5?path=/b&slice=")
+ expected = [False, True, None, "/a.h5", "/b", None]
+ self.assertUrl(url, expected)
+
+ def test_create_relative_url(self):
+ url = DataUrl(scheme="silx", file_path="./foo.h5", data_path="/", data_slice=(5, 1))
+ self.assertFalse(url.is_absolute())
+ url2 = DataUrl(url.path())
+ self.assertEqual(url, url2)
+
+ def test_create_absolute_url(self):
+ url = DataUrl(scheme="silx", file_path="/foo.h5", data_path="/", data_slice=(5, 1))
+ url2 = DataUrl(url.path())
+ self.assertEqual(url, url2)
+
+ def test_create_absolute_windows_url(self):
+ url = DataUrl(scheme="silx", file_path="C:/foo.h5", data_path="/", data_slice=(5, 1))
+ url2 = DataUrl(url.path())
+ self.assertEqual(url, url2)
+
+ def test_create_slice_url(self):
+ url = DataUrl(scheme="silx", file_path="/foo.h5", data_path="/", data_slice=(5, 1, Ellipsis, slice(None)))
+ url2 = DataUrl(url.path())
+ self.assertEqual(url, url2)
+
+ def test_wrong_url(self):
+ url = DataUrl(scheme="silx", file_path="/foo.h5", data_slice=(5, 1))
+ self.assertFalse(url.is_valid())
+
+
+def suite():
+ test_suite = unittest.TestSuite()
+ loadTests = unittest.defaultTestLoader.loadTestsFromTestCase
+ test_suite.addTest(loadTests(TestDataUrl))
+ return test_suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
diff --git a/silx/io/test/test_utils.py b/silx/io/test/test_utils.py
index 09074bb..53e001c 100644
--- a/silx/io/test/test_utils.py
+++ b/silx/io/test/test_utils.py
@@ -30,9 +30,9 @@ import re
import shutil
import tempfile
import unittest
-import sys
from .. import utils
+import silx.io.url
try:
import h5py
@@ -48,7 +48,7 @@ except ImportError:
__authors__ = ["P. Knobel"]
__license__ = "MIT"
-__date__ = "28/09/2017"
+__date__ = "12/02/2018"
expected_spec1 = r"""#F .*
@@ -110,9 +110,9 @@ class TestSave(unittest.TestCase):
def test_save_csv(self):
utils.save1D(self.csv_fname, self.x, self.y,
- xlabel=self.xlab, ylabels=self.ylabs,
- filetype="csv", fmt=["%d", "%.2f", "%.2e"],
- csvdelim=";", autoheader=True)
+ xlabel=self.xlab, ylabels=self.ylabs,
+ filetype="csv", fmt=["%d", "%.2f", "%.2e"],
+ csvdelim=";", autoheader=True)
csvf = open(self.csv_fname)
actual_csv = csvf.read()
@@ -125,22 +125,20 @@ class TestSave(unittest.TestCase):
and converting it to a named record array"""
npyf = open(self.npy_fname, "wb")
utils.save1D(npyf, self.x, self.y,
- xlabel=self.xlab, ylabels=self.ylabs)
+ xlabel=self.xlab, ylabels=self.ylabs)
npyf.close()
npy_recarray = numpy.load(self.npy_fname)
self.assertEqual(npy_recarray.shape, (3,))
- self.assertTrue(
- numpy.array_equal(
- npy_recarray['Ordinate1'],
- numpy.array((4, 5, 6))))
+ self.assertTrue(numpy.array_equal(npy_recarray['Ordinate1'],
+ numpy.array((4, 5, 6))))
def test_savespec_filename(self):
"""Save SpecFile using savespec()"""
utils.savespec(self.spec_fname, self.x, self.y[0], xlabel=self.xlab,
- ylabel=self.ylabs[0], fmt=["%d", "%.2f"], close_file=True,
- scan_number=1)
+ ylabel=self.ylabs[0], fmt=["%d", "%.2f"],
+ close_file=True, scan_number=1)
specf = open(self.spec_fname)
actual_spec = specf.read()
@@ -152,15 +150,15 @@ class TestSave(unittest.TestCase):
"""Save SpecFile using savespec(), passing a file handle"""
# first savespec: open, write file header, save y[0] as scan 1,
# return file handle
- specf = utils.savespec(self.spec_fname, self.x, self.y[0], xlabel=self.xlab,
- ylabel=self.ylabs[0], fmt=["%d", "%.2f"],
- close_file=False)
+ specf = utils.savespec(self.spec_fname, self.x, self.y[0],
+ xlabel=self.xlab, ylabel=self.ylabs[0],
+ fmt=["%d", "%.2f"], close_file=False)
# second savespec: save y[1] as scan 2, close file
utils.savespec(specf, self.x, self.y[1], xlabel=self.xlab,
- ylabel=self.ylabs[1], fmt=["%d", "%.2f"],
- write_file_header=False, close_file=True,
- scan_number=2)
+ ylabel=self.ylabs[1], fmt=["%d", "%.2f"],
+ write_file_header=False, close_file=True,
+ scan_number=2)
specf = open(self.spec_fname)
actual_spec = specf.read()
@@ -171,7 +169,7 @@ class TestSave(unittest.TestCase):
def test_save_spec(self):
"""Save SpecFile using save()"""
utils.save1D(self.spec_fname, self.x, self.y, xlabel=self.xlab,
- ylabels=self.ylabs, filetype="spec", fmt=["%d", "%.2f"])
+ ylabels=self.ylabs, filetype="spec", fmt=["%d", "%.2f"])
specf = open(self.spec_fname)
actual_spec = specf.read()
@@ -192,7 +190,7 @@ class TestSave(unittest.TestCase):
self.y = [[4, 5, 6], [7, 8, 9]]
self.ylabs = ["Ordinate1", "Ordinate2"]
utils.save1D(self.csv_fname, self.x, self.y,
- autoheader=True, fmt=["%d", "%.2f", "%.2e"])
+ autoheader=True, fmt=["%d", "%.2f", "%.2e"])
csvf = open(self.csv_fname)
actual_csv = csvf.read()
@@ -242,15 +240,12 @@ class TestH5Ls(unittest.TestCase):
self.assertIn("+foo", lines)
self.assertIn("\t+bar", lines)
- self.assertMatchAnyStringInList(
- r'\t\t<HDF5 dataset "tmp": shape \(3,\), type "<i[48]">',
- lines)
- self.assertMatchAnyStringInList(
- r'\t\t<HDF5 dataset "spam": shape \(2, 2\), type "<i[48]">',
- lines)
- self.assertMatchAnyStringInList(
- r'\t<HDF5 dataset "data": shape \(1,\), type "<f[48]">',
- lines)
+ match = r'\t\t<HDF5 dataset "tmp": shape \(3,\), type "<i[48]">'
+ self.assertMatchAnyStringInList(match, lines)
+ match = r'\t\t<HDF5 dataset "spam": shape \(2, 2\), type "<i[48]">'
+ self.assertMatchAnyStringInList(match, lines)
+ match = r'\t<HDF5 dataset "data": shape \(1,\), type "<f[48]">'
+ self.assertMatchAnyStringInList(match, lines)
os.unlink(self.h5_fname)
@@ -325,12 +320,6 @@ class TestOpen(unittest.TestCase):
@classmethod
def tearDownClass(cls):
- if sys.platform == "win32" and fabio is not None:
- # gc collect is needed to close a file descriptor
- # opened by fabio and not released.
- # https://github.com/silx-kit/fabio/issues/167
- import gc
- gc.collect()
shutil.rmtree(cls.tmp_directory)
def testH5(self):
@@ -410,6 +399,30 @@ class TestOpen(unittest.TestCase):
# load it
self.assertRaises(IOError, utils.open, self.missing_filename)
+ def test_silx_scheme(self):
+ if h5py is None:
+ self.skipTest("H5py is missing")
+ url = silx.io.url.DataUrl(scheme="silx", file_path=self.h5_filename, data_path="/")
+ with utils.open(url.path()) as f:
+ self.assertIsNotNone(f)
+ self.assertTrue(silx.io.utils.is_file(f))
+
+ def test_fabio_scheme(self):
+ if h5py is None:
+ self.skipTest("H5py is missing")
+ if fabio is None:
+ self.skipTest("Fabio is missing")
+ url = silx.io.url.DataUrl(scheme="fabio", file_path=self.edf_filename)
+ self.assertRaises(IOError, utils.open, url.path())
+
+ def test_bad_url(self):
+ url = silx.io.url.DataUrl(scheme="sil", file_path=self.h5_filename)
+ self.assertRaises(IOError, utils.open, url.path())
+
+ def test_sliced_url(self):
+ url = silx.io.url.DataUrl(file_path=self.h5_filename, data_slice=(5,))
+ self.assertRaises(IOError, utils.open, url.path())
+
class TestNodes(unittest.TestCase):
"""Test `silx.io.utils.is_` functions."""
@@ -443,7 +456,7 @@ class TestNodes(unittest.TestCase):
class Foo(object):
def __init__(self):
- self.h5py_class = h5py.File
+ self.h5_class = utils.H5Type.FILE
obj = Foo()
self.assertTrue(utils.is_file(obj))
self.assertTrue(utils.is_group(obj))
@@ -455,7 +468,7 @@ class TestNodes(unittest.TestCase):
class Foo(object):
def __init__(self):
- self.h5py_class = h5py.Group
+ self.h5_class = utils.H5Type.GROUP
obj = Foo()
self.assertFalse(utils.is_file(obj))
self.assertTrue(utils.is_group(obj))
@@ -467,7 +480,7 @@ class TestNodes(unittest.TestCase):
class Foo(object):
def __init__(self):
- self.h5py_class = h5py.Dataset
+ self.h5_class = utils.H5Type.DATASET
obj = Foo()
self.assertFalse(utils.is_file(obj))
self.assertFalse(utils.is_group(obj))
@@ -491,13 +504,142 @@ class TestNodes(unittest.TestCase):
class Foo(object):
def __init__(self):
- self.h5py_class = int
+ self.h5_class = int
obj = Foo()
self.assertFalse(utils.is_file(obj))
self.assertFalse(utils.is_group(obj))
self.assertFalse(utils.is_dataset(obj))
+class TestGetData(unittest.TestCase):
+ """Test `silx.io.utils.get_data` function."""
+
+ @classmethod
+ def setUpClass(cls):
+ cls.tmp_directory = tempfile.mkdtemp()
+ cls.createResources(cls.tmp_directory)
+
+ @classmethod
+ def createResources(cls, directory):
+
+ if h5py is not None:
+ cls.h5_filename = os.path.join(directory, "test.h5")
+ h5 = h5py.File(cls.h5_filename, mode="w")
+ h5["group/group/scalar"] = 50
+ h5["group/group/array"] = [1, 2, 3, 4, 5]
+ h5["group/group/array2d"] = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
+ h5.close()
+
+ cls.spec_filename = os.path.join(directory, "test.dat")
+ utils.savespec(cls.spec_filename, [1], [1.1], xlabel="x", ylabel="y",
+ fmt=["%d", "%.2f"], close_file=True, scan_number=1)
+
+ if fabio is not None:
+ cls.edf_filename = os.path.join(directory, "test.edf")
+ cls.edf_multiframe_filename = os.path.join(directory, "test_multi.edf")
+ header = fabio.fabioimage.OrderedDict()
+ header["integer"] = "10"
+ data = numpy.array([[10, 50], [50, 10]])
+ fabiofile = fabio.edfimage.EdfImage(data, header)
+ fabiofile.write(cls.edf_filename)
+ fabiofile.appendFrame(data=data, header=header)
+ fabiofile.write(cls.edf_multiframe_filename)
+
+ cls.txt_filename = os.path.join(directory, "test.txt")
+ f = io.open(cls.txt_filename, "w+t")
+ f.write(u"Kikoo")
+ f.close()
+
+ cls.missing_filename = os.path.join(directory, "test.missing")
+
+ @classmethod
+ def tearDownClass(cls):
+ shutil.rmtree(cls.tmp_directory)
+
+ def test_hdf5_scalar(self):
+ if h5py is None:
+ self.skipTest("H5py is missing")
+ url = "silx:%s?/group/group/scalar" % self.h5_filename
+ data = utils.get_data(url=url)
+ self.assertEqual(data, 50)
+
+ def test_hdf5_array(self):
+ if h5py is None:
+ self.skipTest("H5py is missing")
+ url = "silx:%s?/group/group/array" % self.h5_filename
+ data = utils.get_data(url=url)
+ self.assertEqual(data.shape, (5, ))
+ self.assertEqual(data[0], 1)
+
+ def test_hdf5_array_slice(self):
+ if h5py is None:
+ self.skipTest("H5py is missing")
+ url = "silx:%s?path=/group/group/array2d&slice=1" % self.h5_filename
+ data = utils.get_data(url=url)
+ self.assertEqual(data.shape, (5, ))
+ self.assertEqual(data[0], 6)
+
+ def test_hdf5_array_slice_out_of_range(self):
+ if h5py is None:
+ self.skipTest("H5py is missing")
+ url = "silx:%s?path=/group/group/array2d&slice=5" % self.h5_filename
+ self.assertRaises(ValueError, utils.get_data, url)
+
+ def test_edf_using_silx(self):
+ if h5py is None:
+ self.skipTest("H5py is missing")
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ url = "silx:%s?/scan_0/instrument/detector_0/data" % self.edf_filename
+ data = utils.get_data(url=url)
+ self.assertEqual(data.shape, (2, 2))
+ self.assertEqual(data[0, 0], 10)
+
+ def test_fabio_frame(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ url = "fabio:%s?slice=1" % self.edf_multiframe_filename
+ data = utils.get_data(url=url)
+ self.assertEqual(data.shape, (2, 2))
+ self.assertEqual(data[0, 0], 10)
+
+ def test_fabio_singleframe(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ url = "fabio:%s?slice=0" % self.edf_filename
+ data = utils.get_data(url=url)
+ self.assertEqual(data.shape, (2, 2))
+ self.assertEqual(data[0, 0], 10)
+
+ def test_fabio_too_much_frames(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ url = "fabio:%s?slice=..." % self.edf_multiframe_filename
+ self.assertRaises(ValueError, utils.get_data, url)
+
+ def test_fabio_no_frame(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ url = "fabio:%s" % self.edf_filename
+ data = utils.get_data(url=url)
+ self.assertEqual(data.shape, (2, 2))
+ self.assertEqual(data[0, 0], 10)
+
+ def test_unsupported_scheme(self):
+ url = "foo:/foo/bar"
+ self.assertRaises(ValueError, utils.get_data, url)
+
+ def test_no_scheme(self):
+ if fabio is None:
+ self.skipTest("fabio is missing")
+ url = "%s?path=/group/group/array2d&slice=5" % self.h5_filename
+ self.assertRaises((ValueError, IOError), utils.get_data, url)
+
+ def test_file_not_exists(self):
+ url = "silx:/foo/bar"
+ self.assertRaises(IOError, utils.get_data, url)
+
+
def suite():
loadTests = unittest.defaultTestLoader.loadTestsFromTestCase
test_suite = unittest.TestSuite()
@@ -505,6 +647,7 @@ def suite():
test_suite.addTest(loadTests(TestH5Ls))
test_suite.addTest(loadTests(TestOpen))
test_suite.addTest(loadTests(TestNodes))
+ test_suite.addTest(loadTests(TestGetData))
return test_suite
diff --git a/silx/io/url.py b/silx/io/url.py
new file mode 100644
index 0000000..ba62a81
--- /dev/null
+++ b/silx/io/url.py
@@ -0,0 +1,366 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""URL module"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "29/01/2018"
+
+import logging
+from silx.third_party import six
+parse = six.moves.urllib.parse
+
+
+_logger = logging.getLogger(__name__)
+
+
+class DataUrl(object):
+ """Non-mutable object to parse a string representing a resource data
+ locator.
+
+ It supports:
+
+ - path to file and path inside file to the data
+ - data slicing
+ - fabio or silx access to the data
+ - absolute and relative file access
+
+ >>> # fabio access using absolute path
+ >>> DataUrl("fabio:///data/image.edf?slice=2")
+ >>> DataUrl("fabio:///C:/data/image.edf?slice=2")
+
+ >>> # silx access using absolute path
+ >>> DataUrl("silx:///data/image.h5?path=/data/dataset&slice=1,5")
+ >>> DataUrl("silx:///data/image.edf?path=/scan_0/detector/data")
+ >>> DataUrl("silx:///C:/data/image.edf?path=/scan_0/detector/data")
+
+ >>> # `path=` can be omited if there is no other query keys
+ >>> DataUrl("silx:///data/image.h5?/data/dataset")
+ >>> # is the same as
+ >>> DataUrl("silx:///data/image.h5?path=/data/dataset")
+
+ >>> # `::` can be used instead of `?` which can be useful with shell in
+ >>> # command lines
+ >>> DataUrl("silx:///data/image.h5::/data/dataset")
+ >>> # is the same as
+ >>> DataUrl("silx:///data/image.h5?/data/dataset")
+
+ >>> # Relative path access
+ >>> DataUrl("silx:./image.h5")
+ >>> DataUrl("fabio:./image.edf")
+ >>> DataUrl("silx:image.h5")
+ >>> DataUrl("fabio:image.edf")
+
+ >>> # Is also support parsing of file access for convenience
+ >>> DataUrl("./foo/bar/image.edf")
+ >>> DataUrl("C:/data/")
+
+ :param str path: Path representing a link to a data. If specified, other
+ arguments are not used.
+ :param str file_path: Link to the file containing the the data.
+ None if there is no data selection.
+ :param str data_path: Data selection applyed to the data file selected.
+ None if there is no data selection.
+ :param Tuple[int,slice,Ellipse] data_slice: Slicing applyed of the selected
+ data. None if no slicing applyed.
+ :param Union[str,None] scheme: Scheme of the URL. "silx", "fabio"
+ is supported. Other strings can be provided, but :meth:`is_valid` will
+ be false.
+ """
+ def __init__(self, path=None, file_path=None, data_path=None, data_slice=None, scheme=None):
+ self.__is_valid = False
+ if path is not None:
+ assert(file_path is None)
+ assert(data_path is None)
+ assert(data_slice is None)
+ assert(scheme is None)
+ self.__parse_from_path(path)
+ else:
+ self.__file_path = file_path
+ self.__data_path = data_path
+ self.__data_slice = data_slice
+ self.__scheme = scheme
+ self.__path = None
+ self.__check_validity()
+
+ def __eq__(self, other):
+ if self.is_valid() != other.is_valid():
+ return False
+ if self.is_valid():
+ if self.__scheme != other.scheme():
+ return False
+ if self.__file_path != other.file_path():
+ return False
+ if self.__data_path != other.data_path():
+ return False
+ if self.__data_slice != other.data_slice():
+ return False
+ return True
+ else:
+ return self.__path == other.path()
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __repr__(self):
+ return str(self)
+
+ def __str__(self):
+ if self.is_valid() or self.__path is None:
+ def quote_string(string):
+ if isinstance(string, six.string_types):
+ return "'%s'" % string
+ else:
+ return string
+
+ template = "DataUrl(valid=%s, scheme=%s, file_path=%s, data_path=%s, data_slice=%s)"
+ return template % (self.__is_valid,
+ quote_string(self.__scheme),
+ quote_string(self.__file_path),
+ quote_string(self.__data_path),
+ self.__data_slice)
+ else:
+ template = "DataUrl(valid=%s, string=%s)"
+ return template % (self.__is_valid, self.__path)
+
+ def __check_validity(self):
+ """Check the validity of the attributes."""
+ if self.__file_path in [None, ""]:
+ self.__is_valid = False
+ return
+
+ if self.__scheme is None:
+ self.__is_valid = True
+ elif self.__scheme == "fabio":
+ self.__is_valid = self.__data_path is None
+ elif self.__scheme == "silx":
+ # If there is a slice you must have a data path
+ # But you can have a data path without slice
+ slice_implies_data = (self.__data_path is None and self.__data_slice is None) or self.__data_path is not None
+ self.__is_valid = slice_implies_data
+ else:
+ self.__is_valid = False
+
+ @staticmethod
+ def _parse_slice(slice_string):
+ """Parse a slicing sequence and return an associated tuple.
+
+ It supports a sequence of `...`, `:`, and integers separated by a coma.
+
+ :rtype: tuple
+ """
+ def str_to_slice(string):
+ if string == "...":
+ return Ellipsis
+ elif string == ":":
+ return slice(None)
+ else:
+ return int(string)
+
+ if slice_string == "":
+ raise ValueError("An empty slice is not valid")
+
+ tokens = slice_string.split(",")
+ data_slice = []
+ for t in tokens:
+ try:
+ data_slice.append(str_to_slice(t))
+ except ValueError:
+ raise ValueError("'%s' is not a valid slicing" % t)
+ return tuple(data_slice)
+
+ def __parse_from_path(self, path):
+ """Parse the path and initialize attributes.
+
+ :param str path: Path representing the URL.
+ """
+ self.__path = path
+ path = path.replace("::", "?", 1)
+ url = parse.urlparse(path)
+
+ is_valid = True
+
+ if len(url.scheme) <= 2:
+ # Windows driver
+ scheme = None
+ pos = self.__path.index(url.path)
+ file_path = self.__path[0:pos] + url.path
+ else:
+ scheme = url.scheme if url.scheme is not "" else None
+ file_path = url.path
+
+ # Check absolute windows path
+ if len(file_path) > 2 and file_path[0] == '/':
+ if file_path[1] == ":" or file_path[2] == ":":
+ file_path = file_path[1:]
+
+ self.__scheme = scheme
+ self.__file_path = file_path
+
+ query = parse.parse_qsl(url.query, keep_blank_values=True)
+ if len(query) == 1 and query[0][1] == "":
+ # there is no query keys
+ data_path = query[0][0]
+ data_slice = None
+ else:
+ merged_query = {}
+ for name, value in query:
+ if name in query:
+ merged_query[name].append(value)
+ else:
+ merged_query[name] = [value]
+
+ def pop_single_value(merged_query, name):
+ if name in merged_query:
+ values = merged_query.pop(name)
+ if len(values) > 1:
+ _logger.warning("More than one query key named '%s'. The last one is used.", name)
+ value = values[-1]
+ else:
+ value = None
+ return value
+
+ data_path = pop_single_value(merged_query, "path")
+ data_slice = pop_single_value(merged_query, "slice")
+ if data_slice is not None:
+ try:
+ data_slice = self._parse_slice(data_slice)
+ except ValueError:
+ is_valid = False
+ data_slice = None
+
+ for key in merged_query.keys():
+ _logger.warning("Query key %s unsupported. Key skipped.", key)
+
+ self.__data_path = data_path
+ self.__data_slice = data_slice
+
+ if is_valid:
+ self.__check_validity()
+ else:
+ self.__is_valid = False
+
+ def is_valid(self):
+ """Returns true if the URL is valid. Else attributes can be None.
+
+ :rtype: bool
+ """
+ return self.__is_valid
+
+ def path(self):
+ """Returns the string representing the URL.
+
+ :rtype: str
+ """
+ if self.__path is not None:
+ return self.__path
+
+ def slice_to_string(data_slice):
+ if data_slice == Ellipsis:
+ return "..."
+ elif data_slice == slice(None):
+ return ":"
+ elif isinstance(data_slice, int):
+ return str(data_slice)
+ else:
+ raise TypeError("Unexpected slicing type. Found %s" % type(data_slice))
+
+ if self.__data_path is not None and self.__data_slice is None:
+ query = self.__data_path
+ else:
+ queries = []
+ if self.__data_path is not None:
+ queries.append("path=" + self.__data_path)
+ if self.__data_slice is not None:
+ data_slice = ",".join([slice_to_string(s) for s in self.__data_slice])
+ queries.append("slice=" + data_slice)
+ query = "&".join(queries)
+
+ path = ""
+ if self.__file_path is not None:
+ path += self.__file_path
+
+ if query != "":
+ path = path + "?" + query
+
+ if self.__scheme is not None:
+ if self.is_absolute():
+ if path.startswith("/"):
+ path = self.__scheme + "://" + path
+ else:
+ path = self.__scheme + ":///" + path
+ else:
+ path = self.__scheme + ":" + path
+
+ return path
+
+ def is_absolute(self):
+ """Returns true if the file path is an absolute path.
+
+ :rtype: bool
+ """
+ file_path = self.file_path()
+ if len(file_path) > 0:
+ if file_path[0] == "/":
+ return True
+ if len(file_path) > 2:
+ # Windows
+ if file_path[1] == ":" or file_path[2] == ":":
+ return True
+ elif len(file_path) > 1:
+ # Windows
+ if file_path[1] == ":":
+ return True
+ return False
+
+ def file_path(self):
+ """Returns the path to the file containing the data.
+
+ :rtype: str
+ """
+ return self.__file_path
+
+ def data_path(self):
+ """Returns the path inside the file to the data.
+
+ :rtype: str
+ """
+ return self.__data_path
+
+ def data_slice(self):
+ """Returns the slicing applyed to the data.
+
+ It is a tuple containing numbers, slice or ellipses.
+
+ :rtype: Tuple[int, slice, Ellipse]
+ """
+ return self.__data_slice
+
+ def scheme(self):
+ """Returns the scheme. It can be None if no scheme is specified.
+
+ :rtype: Union[str, None]
+ """
+ return self.__scheme
diff --git a/silx/io/utils.py b/silx/io/utils.py
index 361a28b..be19fdb 100644
--- a/silx/io/utils.py
+++ b/silx/io/utils.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,36 +23,88 @@
# ############################################################################*/
""" I/O utility functions"""
+__authors__ = ["P. Knobel", "V. Valls"]
+__license__ = "MIT"
+__date__ = "14/02/2018"
+
import numpy
import os.path
import sys
import time
import logging
+import collections
-from silx.utils.deprecation import deprecated
from silx.utils.proxy import Proxy
+from silx.third_party import six
+from silx.third_party import enum
+import silx.io.url
try:
import h5py
except ImportError as e:
- h5py_missing = True
+ h5py = None
h5py_import_error = e
-else:
- h5py_missing = False
-
-__authors__ = ["P. Knobel", "V. Valls"]
-__license__ = "MIT"
-__date__ = "28/09/2017"
+try:
+ import h5pyd
+except ImportError as e:
+ h5pyd = None
+ h5py_import_error = e
logger = logging.getLogger(__name__)
+
+class H5Type(enum.Enum):
+ """Identify a set of HDF5 concepts"""
+ DATASET = 1
+ GROUP = 2
+ FILE = 3
+ SOFT_LINK = 4
+ EXTERNAL_LINK = 5
+ HARD_LINK = 6
+
+
+_CLASSES_TYPE = None
+"""Store mapping between classes and types"""
+
string_types = (basestring,) if sys.version_info[0] == 2 else (str,) # noqa
builtin_open = open
+def supported_extensions(flat_formats=True):
+ """Returns the list file extensions supported by `silx.open`.
+
+ The result filter out formats when the expected module is not available.
+
+ :param bool flat_formats: If true, also include flat formats like npy or
+ edf (while the expected module is available)
+ :returns: A dictionary indexed by file description and containing a set of
+ extensions (an extension is a string like "\*.ext").
+ :rtype: Dict[str, Set[str]]
+ """
+ formats = {}
+ if h5py is not None:
+ formats["HDF5 files"] = set(["*.h5", "*.hdf"])
+ formats["NeXus files"] = set(["*.nx", "*.nxs", "*.h5", "*.hdf"])
+ formats["NeXus layout from spec files"] = set(["*.dat", "*.spec", "*.mca"])
+ if flat_formats:
+ try:
+ from silx.io import fabioh5
+ except ImportError:
+ fabioh5 = None
+ if fabioh5 is not None:
+ formats["NeXus layout from fabio files"] = set(fabioh5.supported_extensions())
+
+ extensions = ["*.npz"]
+ if flat_formats:
+ extensions.append("*.npy")
+
+ formats["Numpy binary files"] = set(extensions)
+ return formats
+
+
def save1D(fname, x, y, xlabel=None, ylabels=None, filetype=None,
fmt="%.7g", csvdelim=";", newline="\n", header="",
footer="", comments="#", autoheader=False):
@@ -349,7 +401,7 @@ def h5ls(h5group, lvl=0):
.. note:: This function requires `h5py <http://www.h5py.org/>`_ to be
installed.
"""
- if h5py_missing:
+ if h5py is None:
logger.error("h5ls requires h5py")
raise h5py_import_error
@@ -379,7 +431,7 @@ def h5ls(h5group, lvl=0):
return h5repr
-def _open(filename):
+def _open_local_file(filename):
"""
Load a file as an `h5py.File`-like object.
@@ -399,42 +451,43 @@ def _open(filename):
raise IOError("Filename '%s' must be a file path" % filename)
debugging_info = []
+ try:
+ _, extension = os.path.splitext(filename)
- _, extension = os.path.splitext(filename)
+ if extension in [".npz", ".npy"]:
+ try:
+ from . import rawh5
+ return rawh5.NumpyFile(filename)
+ except (IOError, ValueError) as e:
+ debugging_info.append((sys.exc_info(),
+ "File '%s' can't be read as a numpy file." % filename))
- if not h5py_missing:
- if h5py.is_hdf5(filename):
- return h5py.File(filename, "r")
+ if h5py is not None:
+ if h5py.is_hdf5(filename):
+ return h5py.File(filename, "r")
- if extension in [".npz", ".npy"]:
try:
- from . import rawh5
- return rawh5.NumpyFile(filename)
- except (IOError, ValueError) as e:
+ from . import fabioh5
+ return fabioh5.File(filename)
+ except ImportError:
+ debugging_info.append((sys.exc_info(), "fabioh5 can't be loaded."))
+ except Exception:
debugging_info.append((sys.exc_info(),
- "File '%s' can't be read as a numpy file." % filename))
+ "File '%s' can't be read as fabio file." % filename))
- try:
- from . import fabioh5
- return fabioh5.File(filename)
- except ImportError:
- debugging_info.append((sys.exc_info(), "fabioh5 can't be loaded."))
- except Exception:
- debugging_info.append((sys.exc_info(),
- "File '%s' can't be read as fabio file." % filename))
+ try:
+ from . import spech5
+ return spech5.SpecH5(filename)
+ except ImportError:
+ debugging_info.append((sys.exc_info(),
+ "spech5 can't be loaded."))
+ except IOError:
+ debugging_info.append((sys.exc_info(),
+ "File '%s' can't be read as spec file." % filename))
+ finally:
+ for exc_info, message in debugging_info:
+ logger.debug(message, exc_info=exc_info)
- try:
- from . import spech5
- return spech5.SpecH5(filename)
- except ImportError:
- debugging_info.append((sys.exc_info(),
- "spech5 can't be loaded."))
- except IOError:
- debugging_info.append((sys.exc_info(),
- "File '%s' can't be read as spec file." % filename))
-
- for exc_info, message in debugging_info:
- logger.debug(message, exc_info=exc_info)
raise IOError("File '%s' can't be read as HDF5" % filename)
@@ -452,16 +505,24 @@ class _MainNode(Proxy):
def __init__(self, h5_node, h5_file):
super(_MainNode, self).__init__(h5_node)
self.__file = h5_file
- self.__class = get_h5py_class(h5_node)
+ self.__class = get_h5_class(h5_node)
+
+ @property
+ def h5_class(self):
+ """Returns the HDF5 class which is mimicked by this class.
+
+ :rtype: H5Type
+ """
+ return self.__class
@property
def h5py_class(self):
"""Returns the h5py classes which is mimicked by this class. It can be
one of `h5py.File, h5py.Group` or `h5py.Dataset`.
- :rtype: Class
+ :rtype: h5py class
"""
- return self.__class
+ return h5type_to_h5py_class(self.__class)
def __enter__(self):
return self
@@ -496,44 +557,129 @@ def open(filename): # pylint:disable=redefined-builtin
:raises: IOError if the file can't be loaded or path can't be found
:rtype: h5py-like node
"""
- if "::" in filename:
- filename, h5_path = filename.split("::")
+ url = silx.io.url.DataUrl(filename)
+
+ if url.scheme() in [None, "file", "silx"]:
+ # That's a local file
+ if not url.is_valid():
+ raise IOError("URL '%s' is not valid" % filename)
+ h5_file = _open_local_file(url.file_path())
+ elif url.scheme() in ["fabio"]:
+ raise IOError("URL '%s' containing fabio scheme is not supported" % filename)
else:
- filename, h5_path = filename, "/"
+ # That's maybe an URL supported by h5pyd
+ uri = six.moves.urllib.parse.urlparse(filename)
+ if h5pyd is None:
+ raise IOError("URL '%s' unsupported. Try to install h5pyd." % filename)
+ path = uri.path
+ endpoint = "%s://%s" % (uri.scheme, uri.netloc)
+ if path.startswith("/"):
+ path = path[1:]
+ return h5pyd.File(path, 'r', endpoint=endpoint)
+
+ if url.data_slice():
+ raise IOError("URL '%s' containing slicing is not supported" % filename)
+
+ if url.data_path() in [None, "/", ""]:
+ # The full file is requested
+ return h5_file
+ else:
+ # Only a children is requested
+ if url.data_path() not in h5_file:
+ msg = "File '%s' does not contain path '%s'." % (filename, url.data_path())
+ raise IOError(msg)
+ node = h5_file[url.data_path()]
+ proxy = _MainNode(node, h5_file)
+ return proxy
- h5_file = _open(filename)
- if h5_path in ["/", ""]:
- # Short cut
- return h5_file
+def _get_classes_type():
+ """Returns a mapping between Python classes and HDF5 concepts.
+
+ This function allow an lazy initialization to avoid recurssive import
+ of modules.
+ """
+ global _CLASSES_TYPE
+ from . import commonh5
+
+ if _CLASSES_TYPE is not None:
+ return _CLASSES_TYPE
- if h5_path not in h5_file:
- msg = "File '%s' do not contains path '%s'." % (filename, h5_path)
- raise IOError(msg)
+ _CLASSES_TYPE = collections.OrderedDict()
- node = h5_file[h5_path]
- proxy = _MainNode(node, h5_file)
- return proxy
+ _CLASSES_TYPE[commonh5.Dataset] = H5Type.DATASET
+ _CLASSES_TYPE[commonh5.File] = H5Type.FILE
+ _CLASSES_TYPE[commonh5.Group] = H5Type.GROUP
+ _CLASSES_TYPE[commonh5.SoftLink] = H5Type.SOFT_LINK
+ if h5py is not None:
+ _CLASSES_TYPE[h5py.Dataset] = H5Type.DATASET
+ _CLASSES_TYPE[h5py.File] = H5Type.FILE
+ _CLASSES_TYPE[h5py.Group] = H5Type.GROUP
+ _CLASSES_TYPE[h5py.SoftLink] = H5Type.SOFT_LINK
+ _CLASSES_TYPE[h5py.HardLink] = H5Type.HARD_LINK
+ _CLASSES_TYPE[h5py.ExternalLink] = H5Type.EXTERNAL_LINK
-@deprecated
-def load(filename):
+ if h5pyd is not None:
+ _CLASSES_TYPE[h5pyd.Dataset] = H5Type.DATASET
+ _CLASSES_TYPE[h5pyd.File] = H5Type.FILE
+ _CLASSES_TYPE[h5pyd.Group] = H5Type.GROUP
+ _CLASSES_TYPE[h5pyd.SoftLink] = H5Type.SOFT_LINK
+ _CLASSES_TYPE[h5pyd.HardLink] = H5Type.HARD_LINK
+ _CLASSES_TYPE[h5pyd.ExternalLink] = H5Type.EXTERNAL_LINK
+
+ return _CLASSES_TYPE
+
+
+def get_h5_class(obj=None, class_=None):
"""
- Load a file as an `h5py.File`-like object.
+ Returns the HDF5 type relative to the object or to the class.
- Format supported:
- - h5 files, if `h5py` module is installed
- - Spec files if `SpecFile` module is installed
+ :param obj: Instance of an object
+ :param class_: A class
+ :rtype: H5Type
+ """
+ if class_ is None:
+ class_ = obj.__class__
- .. deprecated:: 0.4
- Use :meth:`open`, or :meth:`silx.io.open`. Will be removed in
- Silx 0.5.
+ classes = _get_classes_type()
+ t = classes.get(class_, None)
+ if t is not None:
+ return t
- :param str filename: A filename
- :raises: IOError if the file can't be loaded as an h5py.File like object
- :rtype: h5py.File
+ if obj is not None:
+ if hasattr(obj, "h5_class"):
+ return obj.h5_class
+
+ for referencedClass_, type_ in classes.items():
+ if issubclass(class_, referencedClass_):
+ classes[class_] = type_
+ return type_
+
+ classes[class_] = None
+ return None
+
+
+def h5type_to_h5py_class(type_):
+ """
+ Returns an h5py class from an H5Type. None if nothing found.
+
+ :param H5Type type_:
+ :rtype: H5py class
"""
- return open(filename)
+ if type_ == H5Type.FILE:
+ return h5py.File
+ if type_ == H5Type.GROUP:
+ return h5py.Group
+ if type_ == H5Type.DATASET:
+ return h5py.Dataset
+ if type_ == H5Type.SOFT_LINK:
+ return h5py.SoftLink
+ if type_ == H5Type.HARD_LINK:
+ return h5py.HardLink
+ if type_ == H5Type.EXTERNAL_LINK:
+ return h5py.ExternalLink
+ return None
def get_h5py_class(obj):
@@ -545,12 +691,13 @@ def get_h5py_class(obj):
:param obj: An object
:return: An h5py object
"""
+ if h5py is None:
+ logger.error("get_h5py_class/is_file/is_group/is_dataset requires h5py")
+ raise h5py_import_error
if hasattr(obj, "h5py_class"):
return obj.h5py_class
- elif isinstance(obj, (h5py.File, h5py.Group, h5py.Dataset, h5py.SoftLink)):
- return obj.__class__
- else:
- return None
+ type_ = get_h5_class(obj)
+ return h5type_to_h5py_class(type_)
def is_file(obj):
@@ -559,22 +706,18 @@ def is_file(obj):
:param obj: An object
"""
- class_ = get_h5py_class(obj)
- if class_ is None:
- return False
- return issubclass(class_, h5py.File)
+ t = get_h5_class(obj)
+ return t == H5Type.FILE
def is_group(obj):
"""
- True if the object is a h5py.Group-like object.
+ True if the object is a h5py.Group-like object. A file is a group.
:param obj: An object
"""
- class_ = get_h5py_class(obj)
- if class_ is None:
- return False
- return issubclass(class_, h5py.Group)
+ t = get_h5_class(obj)
+ return t in [H5Type.GROUP, H5Type.FILE]
def is_dataset(obj):
@@ -583,10 +726,8 @@ def is_dataset(obj):
:param obj: An object
"""
- class_ = get_h5py_class(obj)
- if class_ is None:
- return False
- return issubclass(class_, h5py.Dataset)
+ t = get_h5_class(obj)
+ return t == H5Type.DATASET
def is_softlink(obj):
@@ -595,19 +736,99 @@ def is_softlink(obj):
:param obj: An object
"""
- class_ = get_h5py_class(obj)
- if class_ is None:
- return False
- return issubclass(class_, h5py.SoftLink)
+ t = get_h5_class(obj)
+ return t == H5Type.SOFT_LINK
-if h5py_missing:
- def raise_h5py_missing(obj):
- logger.error("get_h5py_class/is_file/is_group/is_dataset requires h5py")
- raise h5py_import_error
+def get_data(url):
+ """Returns a numpy data from an URL.
+
+ Examples:
+
+ >>> # 1st frame from an EDF using silx.io.open
+ >>> data = silx.io.get_data("silx:/users/foo/image.edf::/scan_0/instrument/detector_0/data[0]")
+
+ >>> # 1st frame from an EDF using fabio
+ >>> data = silx.io.get_data("fabio:/users/foo/image.edf::[0]")
+
+ Yet 2 schemes are supported by the function.
+
+ - If `silx` scheme is used, the file is opened using
+ :meth:`silx.io.open`
+ and the data is reach using usually NeXus paths.
+ - If `fabio` scheme is used, the file is opened using :meth:`fabio.open`
+ from the FabIO library.
+ No data path have to be specified, but each frames can be accessed
+ using the data slicing.
+ This shortcut of :meth:`silx.io.open` allow to have a faster access to
+ the data.
+
+ .. seealso:: :class:`silx.io.url.DataUrl`
+
+ :param Union[str,silx.io.url.DataUrl]: A data URL
+ :rtype: Union[numpy.ndarray, numpy.generic]
+ :raises ImportError: If the mandatory library to read the file is not
+ available.
+ :raises ValueError: If the URL is not valid or do not match the data
+ :raises IOError: If the file is not found or in case of internal error of
+ :meth:`fabio.open` or :meth:`silx.io.open`. In this last case more
+ informations are displayed in debug mode.
+ """
+ if not isinstance(url, silx.io.url.DataUrl):
+ url = silx.io.url.DataUrl(url)
+
+ if not url.is_valid():
+ raise ValueError("URL '%s' is not valid" % url.path())
+
+ if not os.path.exists(url.file_path()):
+ raise IOError("File '%s' not found" % url.file_path())
+
+ if url.scheme() == "silx":
+ data_path = url.data_path()
+ data_slice = url.data_slice()
+
+ with open(url.file_path()) as h5:
+ if data_path not in h5:
+ raise ValueError("Data path from URL '%s' not found" % url.path())
+ data = h5[data_path]
+
+ if not silx.io.is_dataset(data):
+ raise ValueError("Data path from URL '%s' is not a dataset" % url.path())
+
+ if data_slice is not None:
+ data = data[data_slice]
+ else:
+ # works for scalar and array
+ data = data[()]
+
+ elif url.scheme() == "fabio":
+ import fabio
+ data_slice = url.data_slice()
+ if data_slice is None:
+ data_slice = (0, )
+ if data_slice is None or len(data_slice) != 1:
+ raise ValueError("Fabio slice expect a single frame, but %s found" % data_slice)
+ index = data_slice[0]
+ if not isinstance(index, int):
+ raise ValueError("Fabio slice expect a single integer, but %s found" % data_slice)
+
+ try:
+ fabio_file = fabio.open(url.file_path())
+ except Exception:
+ logger.debug("Error while opening %s with fabio", url.file_path(), exc_info=True)
+ raise IOError("Error while opening %s with fabio (use debug for more information)" % url.path())
+
+ if fabio_file.nframes == 1:
+ if index != 0:
+ raise ValueError("Only a single frame availalbe. Slice %s out of range" % index)
+ data = fabio_file.data
+ else:
+ data = fabio_file.getframe(index).data
+
+ # There is no explicit close
+ fabio_file = None
+
+ else:
+ raise ValueError("Scheme '%s' not supported" % url.scheme())
- get_h5py_class = raise_h5py_missing
- is_file = raise_h5py_missing
- is_group = raise_h5py_missing
- is_dataset = raise_h5py_missing
- is_softlink = raise_h5py_missing
+ return data
diff --git a/silx/math/fit/fitmanager.py b/silx/math/fit/fitmanager.py
index 4a12a24..f62dedb 100644
--- a/silx/math/fit/fitmanager.py
+++ b/silx/math/fit/fitmanager.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*#########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -240,15 +240,15 @@ class FitManager(object):
If this parameter is provided, all other parameters, except for
``name``, are ignored.
:type theory: :class:`silx.math.fit.fittheory.FitTheory`
- :param function function: Mandatory argument if ``theory`` is not provided.
+ :param callable function: Mandatory argument if ``theory`` is not provided.
See documentation for :attr:`silx.math.fit.fittheory.FitTheory.function`.
- :param list[str] parameters: Mandatory argument if ``theory`` is not provided.
+ :param List[str] parameters: Mandatory argument if ``theory`` is not provided.
See documentation for :attr:`silx.math.fit.fittheory.FitTheory.parameters`.
- :param function estimate: See documentation for
+ :param callable estimate: See documentation for
:attr:`silx.math.fit.fittheory.FitTheory.estimate`
- :param function configure: See documentation for
+ :param callable configure: See documentation for
:attr:`silx.math.fit.fittheory.FitTheory.configure`
- :param function derivative: See documentation for
+ :param callable derivative: See documentation for
:attr:`silx.math.fit.fittheory.FitTheory.derivative`
:param str description: See documentation for
:attr:`silx.math.fit.fittheory.FitTheory.description`
diff --git a/silx/math/fit/test/test_fit.py b/silx/math/fit/test/test_fit.py
index 11b53cd..372d6cb 100644
--- a/silx/math/fit/test/test_fit.py
+++ b/silx/math/fit/test/test_fit.py
@@ -30,7 +30,7 @@ import unittest
import numpy
import sys
-from silx.test import utils
+from silx.utils import testutils
from silx.math.fit.leastsq import _logger as fitlogger
@@ -241,7 +241,7 @@ class Test_leastsq(unittest.TestCase):
fittedpar[i])
self.assertTrue(test_condition, msg)
- @utils.test_logging(fitlogger.name, warning=2)
+ @testutils.test_logging(fitlogger.name, warning=2)
def testBadlyShapedData(self):
parameters_actual = [10.5, 2, 1000.0, 20., 15]
x = numpy.arange(10000.).reshape(1000, 10)
@@ -263,7 +263,7 @@ class Test_leastsq(unittest.TestCase):
fittedpar[i])
self.assertTrue(test_condition, msg)
- @utils.test_logging(fitlogger.name, warning=3)
+ @testutils.test_logging(fitlogger.name, warning=3)
def testDataWithNaN(self):
parameters_actual = [10.5, 2, 1000.0, 20., 15]
x = numpy.arange(10000.).reshape(1000, 10)
diff --git a/silx/math/medianfilter/test/test_medianfilter.py b/silx/math/medianfilter/test/test_medianfilter.py
index a4c55b2..1171e23 100644
--- a/silx/math/medianfilter/test/test_medianfilter.py
+++ b/silx/math/medianfilter/test/test_medianfilter.py
@@ -25,14 +25,14 @@
__authors__ = ["H. Payno"]
__license__ = "MIT"
-__date__ = "02/05/2017"
+__date__ = "17/01/2018"
import unittest
import numpy
from silx.math.medianfilter import medfilt2d
from silx.math.medianfilter.medianfilter import reflect, mirror
from silx.math.medianfilter.medianfilter import MODES as silx_mf_modes
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
try:
import scipy
import scipy.misc
diff --git a/silx/math/test/benchmark_combo.py b/silx/math/test/benchmark_combo.py
index ad5ae41..e179f76 100644
--- a/silx/math/test/benchmark_combo.py
+++ b/silx/math/test/benchmark_combo.py
@@ -27,7 +27,7 @@ from __future__ import division
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "15/05/2017"
+__date__ = "17/01/2018"
import logging
@@ -37,7 +37,8 @@ import unittest
import numpy
-from silx.test.utils import ParametricTestCase, temp_dir
+from silx.test.utils import temp_dir
+from silx.utils.testutils import ParametricTestCase
from silx.math import combo
diff --git a/silx/math/test/test_combo.py b/silx/math/test/test_combo.py
index 7698e78..2e142f3 100644
--- a/silx/math/test/test_combo.py
+++ b/silx/math/test/test_combo.py
@@ -27,14 +27,14 @@ from __future__ import division
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "19/10/2017"
+__date__ = "17/01/2018"
import unittest
import numpy
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
from silx.math.combo import min_max
diff --git a/silx/math/test/test_marchingcubes.py b/silx/math/test/test_marchingcubes.py
index d6aa8e9..41f7e30 100644
--- a/silx/math/test/test_marchingcubes.py
+++ b/silx/math/test/test_marchingcubes.py
@@ -27,13 +27,13 @@ from __future__ import division
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "05/12/2016"
+__date__ = "17/01/2018"
import unittest
import numpy
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
from silx.math import marchingcubes
diff --git a/silx/opencl/backprojection.py b/silx/opencl/backprojection.py
index 15a03b9..ca7244e 100644
--- a/silx/opencl/backprojection.py
+++ b/silx/opencl/backprojection.py
@@ -29,7 +29,7 @@ from __future__ import absolute_import, print_function, with_statement, division
__authors__ = ["A. Mirone, P. Paleo"]
__license__ = "MIT"
-__date__ = "05/10/2017"
+__date__ = "19/01/2018"
import logging
import numpy
@@ -196,7 +196,7 @@ class Backprojection(OpenclProcessing):
self.local_mem = 256 * 3 * _sizeof(numpy.float32) # constant for all image sizes
OpenclProcessing.compile_kernels(self, self.kernel_files)
# check that workgroup can actually be (16, 16)
- self.check_workgroup_size("backproj_cpu_kernel")
+ self.compiletime_workgroup_size = self.kernels.max_workgroup_size("backproj_cpu_kernel")
# Workgroup and ndrange sizes are always the same
self.wg = (16, 16)
self.ndrange = (
diff --git a/silx/opencl/codec/__init__.py b/silx/opencl/codec/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/silx/opencl/codec/__init__.py
diff --git a/silx/opencl/codec/byte_offset.py b/silx/opencl/codec/byte_offset.py
new file mode 100644
index 0000000..565b0c5
--- /dev/null
+++ b/silx/opencl/codec/byte_offset.py
@@ -0,0 +1,439 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Project: Sift implementation in Python + OpenCL
+# https://github.com/silx-kit/silx
+#
+# Copyright (C) 2013-2018 European Synchrotron Radiation Facility, Grenoble, France
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+This module provides a class for CBF byte offset compression/decompression.
+"""
+
+from __future__ import division, print_function, with_statement
+
+__authors__ = ["Jérôme Kieffer"]
+__contact__ = "jerome.kieffer@esrf.eu"
+__license__ = "MIT"
+__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+__date__ = "24/10/2017"
+__status__ = "production"
+
+
+import functools
+import os
+import numpy
+from ..common import ocl, pyopencl
+from ..processing import BufferDescription, EventDescription, OpenclProcessing
+
+import logging
+logger = logging.getLogger(__name__)
+
+if pyopencl:
+ import pyopencl.version
+ if pyopencl.version.VERSION < (2016, 0):
+ from pyopencl.scan import GenericScanKernel, GenericDebugScanKernel
+ else:
+ from pyopencl.algorithm import GenericScanKernel
+ from pyopencl.scan import GenericDebugScanKernel
+else:
+ logger.warning("No PyOpenCL, no byte-offset, please see fabio")
+
+
+class ByteOffset(OpenclProcessing):
+ """Perform the byte offset compression/decompression on the GPU
+
+ See :class:`OpenclProcessing` for optional arguments description.
+
+ :param int raw_size:
+ Size of the raw stream for decompression.
+ It can be (slightly) larger than the array.
+ :param int dec_size:
+ Size of the decompression output array
+ (mandatory for decompression)
+ """
+
+ def __init__(self, raw_size=None, dec_size=None,
+ ctx=None, devicetype="all",
+ platformid=None, deviceid=None,
+ block_size=None, profile=False):
+ OpenclProcessing.__init__(self, ctx=ctx, devicetype=devicetype,
+ platformid=platformid, deviceid=deviceid,
+ block_size=block_size, profile=profile)
+ if self.block_size is None:
+ self.block_size = self.device.max_work_group_size
+ wg = self.block_size
+
+ buffers = [BufferDescription("counter", 1, numpy.int32, None)]
+
+ if raw_size is None:
+ self.raw_size = -1
+ self.padded_raw_size = -1
+ else:
+ self.raw_size = int(raw_size)
+ self.padded_raw_size = int((self.raw_size + wg - 1) & ~(wg - 1))
+ buffers += [
+ BufferDescription("raw", self.padded_raw_size, numpy.int8, None),
+ BufferDescription("mask", self.padded_raw_size, numpy.int32, None),
+ BufferDescription("values", self.padded_raw_size, numpy.int32, None),
+ BufferDescription("exceptions", self.padded_raw_size, numpy.int32, None)
+ ]
+
+ if dec_size is None:
+ self.dec_size = None
+ else:
+ self.dec_size = numpy.int32(dec_size)
+ buffers += [
+ BufferDescription("data_float", self.dec_size, numpy.float32, None),
+ BufferDescription("data_int", self.dec_size, numpy.int32, None)
+ ]
+
+ self.allocate_buffers(buffers, use_array=True)
+
+ self.compile_kernels([os.path.join("codec", "byte_offset")])
+ self.kernels.__setattr__("scan", self._init_double_scan())
+ self.kernels.__setattr__("compression_scan",
+ self._init_compression_scan())
+
+ def _init_double_scan(self):
+ """"generates a double scan on indexes and values in one operation"""
+ arguments = "__global int *value", "__global int *index"
+ int2 = pyopencl.tools.get_or_register_dtype("int2")
+ input_expr = "index[i]>0 ? (int2)(0, 0) : (int2)(value[i], 1)"
+ scan_expr = "a+b"
+ neutral = "(int2)(0,0)"
+ output_statement = "value[i] = item.s0; index[i+1] = item.s1;"
+
+ if self.block_size > 256:
+ knl = GenericScanKernel(self.ctx,
+ dtype=int2,
+ arguments=arguments,
+ input_expr=input_expr,
+ scan_expr=scan_expr,
+ neutral=neutral,
+ output_statement=output_statement)
+ else: # MacOS on CPU
+ knl = GenericDebugScanKernel(self.ctx,
+ dtype=int2,
+ arguments=arguments,
+ input_expr=input_expr,
+ scan_expr=scan_expr,
+ neutral=neutral,
+ output_statement=output_statement)
+ return knl
+
+ def decode(self, raw, as_float=False, out=None):
+ """This function actually performs the decompression by calling the kernels
+
+ :param numpy.ndarray raw: The compressed data as a 1D numpy array of char.
+ :param bool as_float: True to decompress as float32,
+ False (default) to decompress as int32
+ :param pyopencl.array out: pyopencl array in which to place the result.
+ :return: The decompressed image as an pyopencl array.
+ :rtype: pyopencl.array
+ """
+ assert self.dec_size is not None, \
+ "dec_size is a mandatory ByteOffset init argument for decompression"
+
+ events = []
+ with self.sem:
+ len_raw = numpy.int32(len(raw))
+ if len_raw > self.padded_raw_size:
+ wg = self.block_size
+ self.raw_size = int(len(raw))
+ self.padded_raw_size = (self.raw_size + wg - 1) & ~(wg - 1)
+ logger.info("increase raw buffer size to %s", self.padded_raw_size)
+ buffers = {
+ "raw": pyopencl.array.empty(self.queue, self.padded_raw_size, dtype=numpy.int8),
+ "mask": pyopencl.array.empty(self.queue, self.padded_raw_size, dtype=numpy.int32),
+ "exceptions": pyopencl.array.empty(self.queue, self.padded_raw_size, dtype=numpy.int32),
+ "values": pyopencl.array.empty(self.queue, self.padded_raw_size, dtype=numpy.int32),
+ }
+ self.cl_mem.update(buffers)
+ else:
+ wg = self.block_size
+
+ evt = pyopencl.enqueue_copy(self.queue, self.cl_mem["raw"].data,
+ raw,
+ is_blocking=False)
+ events.append(EventDescription("copy raw H -> D", evt))
+ evt = self.kernels.fill_int_mem(self.queue, (self.padded_raw_size,), (wg,),
+ self.cl_mem["mask"].data,
+ numpy.int32(self.padded_raw_size),
+ numpy.int32(0),
+ numpy.int32(0))
+ events.append(EventDescription("memset mask", evt))
+ evt = self.kernels.fill_int_mem(self.queue, (1,), (1,),
+ self.cl_mem["counter"].data,
+ numpy.int32(1),
+ numpy.int32(0),
+ numpy.int32(0))
+ events.append(EventDescription("memset counter", evt))
+ evt = self.kernels.mark_exceptions(self.queue, (self.padded_raw_size,), (wg,),
+ self.cl_mem["raw"].data,
+ len_raw,
+ numpy.int32(self.raw_size),
+ self.cl_mem["mask"].data,
+ self.cl_mem["values"].data,
+ self.cl_mem["counter"].data,
+ self.cl_mem["exceptions"].data)
+ events.append(EventDescription("mark exceptions", evt))
+ nb_exceptions = numpy.empty(1, dtype=numpy.int32)
+ evt = pyopencl.enqueue_copy(self.queue, nb_exceptions, self.cl_mem["counter"].data,
+ is_blocking=False)
+ events.append(EventDescription("copy counter D -> H", evt))
+ evt.wait()
+ nbexc = int(nb_exceptions[0])
+ if nbexc == 0:
+ logger.info("nbexc %i", nbexc)
+ else:
+ evt = self.kernels.treat_exceptions(self.queue, (nbexc,), (1,),
+ self.cl_mem["raw"].data,
+ len_raw,
+ self.cl_mem["mask"].data,
+ self.cl_mem["exceptions"].data,
+ self.cl_mem["values"].data
+ )
+ events.append(EventDescription("treat_exceptions", evt))
+
+ #self.cl_mem["copy_values"] = self.cl_mem["values"].copy()
+ #self.cl_mem["copy_mask"] = self.cl_mem["mask"].copy()
+ evt = self.kernels.scan(self.cl_mem["values"],
+ self.cl_mem["mask"],
+ queue=self.queue,
+ size=int(len_raw),
+ wait_for=(evt,))
+ events.append(EventDescription("double scan", evt))
+ #evt.wait()
+ if out is not None:
+ if out.dtype == numpy.float32:
+ copy_results = self.kernels.copy_result_float
+ else:
+ copy_results = self.kernels.copy_result_int
+ else:
+ if as_float:
+ out = self.cl_mem["data_float"]
+ copy_results = self.kernels.copy_result_float
+ else:
+ out = self.cl_mem["data_int"]
+ copy_results = self.kernels.copy_result_int
+ evt = copy_results(self.queue, (self.padded_raw_size,), (wg,),
+ self.cl_mem["values"].data,
+ self.cl_mem["mask"].data,
+ len_raw,
+ self.dec_size,
+ out.data
+ )
+ events.append(EventDescription("copy_results", evt))
+ #evt.wait()
+ if self.profile:
+ self.events += events
+ return out
+
+ __call__ = decode
+
+ def _init_compression_scan(self):
+ """Initialize CBF compression scan kernels"""
+ preamble = """
+ int compressed_size(int diff) {
+ int abs_diff = abs(diff);
+
+ if (abs_diff < 128) {
+ return 1;
+ }
+ else if (abs_diff < 32768) {
+ return 3;
+ }
+ else {
+ return 7;
+ }
+ }
+
+ void write(const int index,
+ const int diff,
+ global char *output) {
+ int abs_diff = abs(diff);
+
+ if (abs_diff < 128) {
+ output[index] = (char) diff;
+ }
+ else if (abs_diff < 32768) {
+ output[index] = -128;
+ output[index + 1] = (char) (diff >> 0);
+ output[index + 2] = (char) (diff >> 8);
+ }
+ else {
+ output[index] = -128;
+ output[index + 1] = 0;
+ output[index + 2] = -128;
+ output[index + 3] = (char) (diff >> 0);
+ output[index + 4] = (char) (diff >> 8);
+ output[index + 5] = (char) (diff >> 16);
+ output[index + 6] = (char) (diff >> 24);
+ }
+ }
+ """
+ arguments = "__global const int *data, __global char *compressed, __global int *size"
+ input_expr = "compressed_size((i == 0) ? data[0] : (data[i] - data[i - 1]))"
+ scan_expr = "a+b"
+ neutral = "0"
+ output_statement = """
+ if (prev_item == 0) { // 1st thread store compressed data size
+ size[0] = last_item;
+ }
+ write(prev_item, (i == 0) ? data[0] : (data[i] - data[i - 1]), compressed);
+ """
+
+ if self.block_size >= 64:
+ knl = GenericScanKernel(self.ctx,
+ dtype=numpy.int32,
+ preamble=preamble,
+ arguments=arguments,
+ input_expr=input_expr,
+ scan_expr=scan_expr,
+ neutral=neutral,
+ output_statement=output_statement)
+ else: # MacOS on CPU
+ knl = GenericDebugScanKernel(self.ctx,
+ dtype=numpy.int32,
+ preamble=preamble,
+ arguments=arguments,
+ input_expr=input_expr,
+ scan_expr=scan_expr,
+ neutral=neutral,
+ output_statement=output_statement)
+ return knl
+
+ def encode(self, data, out=None):
+ """Compress data to CBF.
+
+ :param data: The data to compress as a numpy array
+ (or a pyopencl Array) of int32.
+ :type data: Union[numpy.ndarray, pyopencl.array.Array]
+ :param pyopencl.array out:
+ pyopencl array of int8 in which to store the result.
+ The array should be large enough to store the compressed data.
+ :return: The compressed data as a pyopencl array.
+ If out is provided, this array shares the backing buffer,
+ but has the exact size of the compressed data and the queue
+ of the ByteOffset instance.
+ :rtype: pyopencl.array
+ :raises ValueError: if out array is not large enough
+ """
+
+ events = []
+ with self.sem:
+ if isinstance(data, pyopencl.array.Array):
+ d_data = data # Uses provided array
+
+ else: # Copy data to device
+ data = numpy.ascontiguousarray(data, dtype=numpy.int32).ravel()
+
+ # Make sure data array exists and is large enough
+ if ("data_input" not in self.cl_mem or
+ self.cl_mem["data_input"].size < data.size):
+ logger.info("increase data input buffer size to %s", data.size)
+ self.cl_mem.update({
+ "data_input": pyopencl.array.empty(self.queue,
+ data.size,
+ dtype=numpy.int32)})
+ d_data = self.cl_mem["data_input"]
+
+ evt = pyopencl.enqueue_copy(
+ self.queue, d_data.data, data, is_blocking=False)
+ events.append(EventDescription("copy data H -> D", evt))
+
+ # Make sure compressed array exists and is large enough
+ compressed_size = d_data.size * 7
+ if ("compressed" not in self.cl_mem or
+ self.cl_mem["compressed"].size < compressed_size):
+ logger.info("increase compressed buffer size to %s", compressed_size)
+ self.cl_mem.update({
+ "compressed": pyopencl.array.empty(self.queue,
+ compressed_size,
+ dtype=numpy.int8)})
+ d_compressed = self.cl_mem["compressed"]
+ d_size = self.cl_mem["counter"] # Shared with decompression
+
+ evt = self.kernels.compression_scan(d_data, d_compressed, d_size)
+ events.append(EventDescription("compression scan", evt))
+ byte_count = int(d_size.get()[0])
+
+ if out is None:
+ # Create out array from a sub-region of the compressed buffer
+ out = pyopencl.array.Array(
+ self.queue,
+ shape=(byte_count,),
+ dtype=numpy.int8,
+ allocator=functools.partial(
+ d_compressed.base_data.get_sub_region,
+ d_compressed.offset))
+
+ elif out.size < byte_count:
+ raise ValueError(
+ "Provided output buffer is not large enough: "
+ "requires %d bytes, got %d" % (byte_count, out.size))
+
+ else: # out.size >= byte_count
+ # Create an array with a sub-region of out and this class queue
+ out = pyopencl.array.Array(
+ self.queue,
+ shape=(byte_count,),
+ dtype=numpy.int8,
+ allocator=functools.partial(out.base_data.get_sub_region,
+ out.offset))
+
+ evt = pyopencl.enqueue_copy_buffer(
+ self.queue, d_compressed.data, out.data, byte_count=byte_count)
+ events.append(
+ EventDescription("copy D -> D: internal -> out", evt))
+
+ if self.profile:
+ self.events += events
+
+ return out
+
+ def encode_to_bytes(self, data):
+ """Compresses data to CBF and returns compressed data as bytes.
+
+ Usage:
+
+ Provided an image (`image`) stored as a numpy array of int32,
+ first, create a byte offset compression/decompression object:
+
+ >>> from silx.opencl.codec.byte_offset import ByteOffset
+ >>> byte_offset_codec = ByteOffset()
+
+ Then, compress an image into bytes:
+
+ >>> compressed = byte_offset_codec.encode_to_bytes(image)
+
+ :param data: The data to compress as a numpy array
+ (or a pyopencl Array) of int32.
+ :type data: Union[numpy.ndarray, pyopencl.array.Array]
+ :return: The compressed data as bytes.
+ :rtype: bytes
+ """
+ compressed_array = self.encode(data)
+ return compressed_array.get().tostring()
diff --git a/silx/opencl/codec/setup.py b/silx/opencl/codec/setup.py
new file mode 100644
index 0000000..4a5c1e5
--- /dev/null
+++ b/silx/opencl/codec/setup.py
@@ -0,0 +1,43 @@
+# coding: utf-8
+#
+# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+from __future__ import division
+
+__contact__ = "jerome.kieffer@esrf.eu"
+__license__ = "MIT"
+__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+__authors__ = ["J. Kieffer"]
+__date__ = "13/10/2017"
+
+from numpy.distutils.misc_util import Configuration
+
+
+def configuration(parent_package='', top_path=None):
+ config = Configuration('codec', parent_package, top_path)
+ config.add_subpackage('test')
+ return config
+
+
+if __name__ == "__main__":
+ from numpy.distutils.core import setup
+ setup(configuration=configuration)
diff --git a/silx/opencl/codec/test/__init__.py b/silx/opencl/codec/test/__init__.py
new file mode 100644
index 0000000..ec76dd3
--- /dev/null
+++ b/silx/opencl/codec/test/__init__.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+#
+# Project: silx
+# https://github.com/silx-kit/silx
+#
+# Copyright (C) 2013-2017 European Synchrotron Radiation Facility, Grenoble, France
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+__authors__ = ["J. Kieffer"]
+__license__ = "MIT"
+__date__ = "13/10/2017"
+
+import unittest
+from . import test_byte_offset
+
+
+def suite():
+ testSuite = unittest.TestSuite()
+ testSuite.addTest(test_byte_offset.suite())
+
+ return testSuite
diff --git a/silx/opencl/codec/test/test_byte_offset.py b/silx/opencl/codec/test/test_byte_offset.py
new file mode 100644
index 0000000..2bfa1d3
--- /dev/null
+++ b/silx/opencl/codec/test/test_byte_offset.py
@@ -0,0 +1,317 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Project: Byte-offset decompression in OpenCL
+# https://github.com/silx-kit/silx
+#
+# Copyright (C) 2013-2018 European Synchrotron Radiation Facility,
+# Grenoble, France
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Test suite for byte-offset decompression
+"""
+
+from __future__ import division, print_function
+
+__authors__ = ["Jérôme Kieffer"]
+__contact__ = "jerome.kieffer@esrf.eu"
+__license__ = "MIT"
+__copyright__ = "2013 European Synchrotron Radiation Facility, Grenoble, France"
+__date__ = "10/11/2017"
+
+import sys
+import time
+import logging
+import numpy
+from silx.opencl.common import ocl, pyopencl
+from silx.opencl.codec import byte_offset
+try:
+ import fabio
+except ImportError:
+ fabio = None
+import unittest
+logger = logging.getLogger(__name__)
+
+
+@unittest.skipUnless(ocl and fabio and pyopencl,
+ "PyOpenCl or fabio is missing")
+class TestByteOffset(unittest.TestCase):
+
+ @staticmethod
+ def _create_test_data(shape, nexcept, lam=200):
+ """Create test (image, compressed stream) pair.
+
+ :param shape: Shape of test image
+ :param int nexcept: Number of exceptions in the image
+ :param lam: Expectation of interval argument for numpy.random.poisson
+ :return: (reference image array, compressed stream)
+ """
+ size = numpy.prod(shape)
+ ref = numpy.random.poisson(lam, numpy.prod(shape))
+ exception_loc = numpy.random.randint(0, size, size=nexcept)
+ exception_value = numpy.random.randint(0, 1000000, size=nexcept)
+ ref[exception_loc] = exception_value
+ ref.shape = shape
+
+ raw = fabio.compression.compByteOffset(ref)
+ return ref, raw
+
+ def test_decompress(self):
+ """
+ tests the byte offset decompression on GPU
+ """
+ ref, raw = self._create_test_data(shape=(91, 97), nexcept=229)
+ #ref, raw = self._create_test_data(shape=(7, 9), nexcept=0)
+
+ size = numpy.prod(ref.shape)
+
+ try:
+ bo = byte_offset.ByteOffset(raw_size=len(raw), dec_size=size, profile=True)
+ except (RuntimeError, pyopencl.RuntimeError) as err:
+ logger.warning(err)
+ if sys.platform == "darwin":
+ raise unittest.SkipTest("Byte-offset decompression is known to be buggy on MacOS-CPU")
+ else:
+ raise err
+ print(bo.block_size)
+
+ t0 = time.time()
+ res_cy = fabio.compression.decByteOffset(raw)
+ t1 = time.time()
+ res_cl = bo.decode(raw)
+ t2 = time.time()
+ delta_cy = abs(ref.ravel() - res_cy).max()
+ delta_cl = abs(ref.ravel() - res_cl.get()).max()
+
+ logger.debug("Global execution time: fabio %.3fms, OpenCL: %.3fms.",
+ 1000.0 * (t1 - t0),
+ 1000.0 * (t2 - t1))
+ bo.log_profile()
+ #print(ref)
+ #print(res_cl.get())
+ self.assertEqual(delta_cy, 0, "Checks fabio works")
+ self.assertEqual(delta_cl, 0, "Checks opencl works")
+
+ def test_many_decompress(self, ntest=10):
+ """
+ tests the byte offset decompression on GPU, many images to ensure there
+ is not leaking in memory
+ """
+ shape = (991, 997)
+ size = numpy.prod(shape)
+ ref, raw = self._create_test_data(shape=shape, nexcept=0, lam=100)
+
+ try:
+ bo = byte_offset.ByteOffset(len(raw), size, profile=False)
+ except (RuntimeError, pyopencl.RuntimeError) as err:
+ logger.warning(err)
+ if sys.platform == "darwin":
+ raise unittest.SkipTest("Byte-offset decompression is known to be buggy on MacOS-CPU")
+ else:
+ raise err
+ t0 = time.time()
+ res_cy = fabio.compression.decByteOffset(raw)
+ t1 = time.time()
+ res_cl = bo(raw)
+ t2 = time.time()
+ delta_cy = abs(ref.ravel() - res_cy).max()
+ delta_cl = abs(ref.ravel() - res_cl.get()).max()
+ self.assertEqual(delta_cy, 0, "Checks fabio works")
+ self.assertEqual(delta_cl, 0, "Checks opencl works")
+ logger.debug("Global execution time: fabio %.3fms, OpenCL: %.3fms.",
+ 1000.0 * (t1 - t0),
+ 1000.0 * (t2 - t1))
+
+ for i in range(ntest):
+ ref, raw = self._create_test_data(shape=shape, nexcept=2729, lam=200)
+
+ t0 = time.time()
+ res_cy = fabio.compression.decByteOffset(raw)
+ t1 = time.time()
+ res_cl = bo(raw)
+ t2 = time.time()
+ delta_cy = abs(ref.ravel() - res_cy).max()
+ delta_cl = abs(ref.ravel() - res_cl.get()).max()
+ self.assertEqual(delta_cy, 0, "Checks fabio works #%i" % i)
+ self.assertEqual(delta_cl, 0, "Checks opencl works #%i" % i)
+
+ logger.debug("Global execution time: fabio %.3fms, OpenCL: %.3fms.",
+ 1000.0 * (t1 - t0),
+ 1000.0 * (t2 - t1))
+
+ def test_encode(self):
+ """Test byte offset compression"""
+ ref, raw = self._create_test_data(shape=(2713, 2719), nexcept=2729)
+
+ try:
+ bo = byte_offset.ByteOffset(len(raw), ref.size, profile=True)
+ except (RuntimeError, pyopencl.RuntimeError) as err:
+ logger.warning(err)
+ raise err
+
+ t0 = time.time()
+ compressed_array = bo.encode(ref)
+ t1 = time.time()
+
+ compressed_stream = compressed_array.get().tostring()
+ self.assertEqual(raw, compressed_stream)
+
+ logger.debug("Global execution time: OpenCL: %.3fms.",
+ 1000.0 * (t1 - t0))
+ bo.log_profile()
+
+ def test_encode_to_array(self):
+ """Test byte offset compression while providing an out array"""
+
+ ref, raw = self._create_test_data(shape=(2713, 2719), nexcept=2729)
+
+ try:
+ bo = byte_offset.ByteOffset(profile=True)
+ except (RuntimeError, pyopencl.RuntimeError) as err:
+ logger.warning(err)
+ raise err
+ # Test with out buffer too small
+ out = pyopencl.array.empty(bo.queue, (10,), numpy.int8)
+ with self.assertRaises(ValueError):
+ bo.encode(ref, out)
+
+ # Test with out buffer too big
+ out = pyopencl.array.empty(bo.queue, (len(raw) + 10,), numpy.int8)
+
+ compressed_array = bo.encode(ref, out)
+
+ # Get size from returned array
+ compressed_size = compressed_array.size
+ self.assertEqual(compressed_size, len(raw))
+
+ # Get data from out array, read it from bo object queue
+ out_bo_queue = out.with_queue(bo.queue)
+ compressed_stream = out_bo_queue.get().tostring()[:compressed_size]
+ self.assertEqual(raw, compressed_stream)
+
+ def test_encode_to_bytes(self):
+ """Test byte offset compression to bytes"""
+ ref, raw = self._create_test_data(shape=(2713, 2719), nexcept=2729)
+
+ try:
+ bo = byte_offset.ByteOffset(profile=True)
+ except (RuntimeError, pyopencl.RuntimeError) as err:
+ logger.warning(err)
+ raise err
+
+ t0 = time.time()
+ res_fabio = fabio.compression.compByteOffset(ref)
+ t1 = time.time()
+ compressed_stream = bo.encode_to_bytes(ref)
+ t2 = time.time()
+
+ self.assertEqual(raw, compressed_stream)
+
+ logger.debug("Global execution time: fabio %.3fms, OpenCL: %.3fms.",
+ 1000.0 * (t1 - t0),
+ 1000.0 * (t2 - t1))
+ bo.log_profile()
+
+ def test_encode_to_bytes_from_array(self):
+ """Test byte offset compression to bytes from a pyopencl array.
+ """
+ ref, raw = self._create_test_data(shape=(2713, 2719), nexcept=2729)
+
+ try:
+ bo = byte_offset.ByteOffset(profile=True)
+ except (RuntimeError, pyopencl.RuntimeError) as err:
+ logger.warning(err)
+ raise err
+
+ d_ref = pyopencl.array.to_device(
+ bo.queue, ref.astype(numpy.int32).ravel())
+
+ t0 = time.time()
+ res_fabio = fabio.compression.compByteOffset(ref)
+ t1 = time.time()
+ compressed_stream = bo.encode_to_bytes(d_ref)
+ t2 = time.time()
+
+ self.assertEqual(raw, compressed_stream)
+
+ logger.debug("Global execution time: fabio %.3fms, OpenCL: %.3fms.",
+ 1000.0 * (t1 - t0),
+ 1000.0 * (t2 - t1))
+ bo.log_profile()
+
+ def test_many_encode(self, ntest=10):
+ """Test byte offset compression with many image"""
+ shape = (991, 997)
+ ref, raw = self._create_test_data(shape=shape, nexcept=0, lam=100)
+
+ try:
+ bo = byte_offset.ByteOffset(profile=False)
+ except (RuntimeError, pyopencl.RuntimeError) as err:
+ logger.warning(err)
+ raise err
+
+ bo_durations = []
+
+ t0 = time.time()
+ res_fabio = fabio.compression.compByteOffset(ref)
+ t1 = time.time()
+ compressed_stream = bo.encode_to_bytes(ref)
+ t2 = time.time()
+ bo_durations.append(1000.0 * (t2 - t1))
+
+ self.assertEqual(raw, compressed_stream)
+ logger.debug("Global execution time: fabio %.3fms, OpenCL: %.3fms.",
+ 1000.0 * (t1 - t0),
+ 1000.0 * (t2 - t1))
+
+ for i in range(ntest):
+ ref, raw = self._create_test_data(shape=shape, nexcept=2729, lam=200)
+
+ t0 = time.time()
+ res_fabio = fabio.compression.compByteOffset(ref)
+ t1 = time.time()
+ compressed_stream = bo.encode_to_bytes(ref)
+ t2 = time.time()
+ bo_durations.append(1000.0 * (t2 - t1))
+
+ self.assertEqual(raw, compressed_stream)
+ logger.debug("Global execution time: fabio %.3fms, OpenCL: %.3fms.",
+ 1000.0 * (t1 - t0),
+ 1000.0 * (t2 - t1))
+
+ logger.debug("OpenCL execution time: Mean: %fms, Min: %fms, Max: %fms",
+ numpy.mean(bo_durations),
+ numpy.min(bo_durations),
+ numpy.max(bo_durations))
+
+
+def suite():
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(TestByteOffset("test_decompress"))
+ test_suite.addTest(TestByteOffset("test_many_decompress"))
+ test_suite.addTest(TestByteOffset("test_encode"))
+ test_suite.addTest(TestByteOffset("test_encode_to_array"))
+ test_suite.addTest(TestByteOffset("test_encode_to_bytes"))
+ test_suite.addTest(TestByteOffset("test_encode_to_bytes_from_array"))
+ test_suite.addTest(TestByteOffset("test_many_encode"))
+ return test_suite
diff --git a/silx/opencl/common.py b/silx/opencl/common.py
index ebf50c7..e955f46 100644
--- a/silx/opencl/common.py
+++ b/silx/opencl/common.py
@@ -34,7 +34,7 @@ __author__ = "Jerome Kieffer"
__contact__ = "Jerome.Kieffer@ESRF.eu"
__license__ = "MIT"
__copyright__ = "2012-2017 European Synchrotron Radiation Facility, Grenoble, France"
-__date__ = "05/10/2017"
+__date__ = "16/10/2017"
__status__ = "stable"
__all__ = ["ocl", "pyopencl", "mf", "release_cl_buffers", "allocate_cl_buffers",
"measure_workgroup_size", "kernel_workgroup_size"]
@@ -400,7 +400,7 @@ class OpenCL(object):
return None
def create_context(self, devicetype="ALL", useFp64=False, platformid=None,
- deviceid=None, cached=True):
+ deviceid=None, cached=True, memory=None):
"""
Choose a device and initiate a context.
@@ -414,6 +414,7 @@ class OpenCL(object):
:param platformid: integer
:param deviceid: integer
:param cached: True if we want to cache the context
+ :param memory: minimum amount of memory of the device
:return: OpenCL context on the selected device
"""
if (platformid is not None) and (deviceid is not None):
diff --git a/silx/opencl/image.py b/silx/opencl/image.py
new file mode 100644
index 0000000..65e2d5e
--- /dev/null
+++ b/silx/opencl/image.py
@@ -0,0 +1,387 @@
+# -*- coding: utf-8 -*-
+#
+# Project: silx
+# https://github.com/silx-kit/silx
+#
+# Copyright (C) 2012-2017 European Synchrotron Radiation Facility, Grenoble, France
+#
+# Principal author: Jérôme Kieffer (Jerome.Kieffer@ESRF.eu)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# .
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# .
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+"""A general purpose library for manipulating 2D images in 1 or 3 colors
+
+"""
+from __future__ import absolute_import, print_function, with_statement, division
+
+
+__author__ = "Jerome Kieffer"
+__license__ = "MIT"
+__date__ = "12/02/2018"
+__copyright__ = "2012-2017, ESRF, Grenoble"
+__contact__ = "jerome.kieffer@esrf.fr"
+
+import os
+import logging
+import numpy
+from collections import OrderedDict
+from math import floor, ceil, sqrt, log
+
+from .common import pyopencl, kernel_workgroup_size
+from .processing import EventDescription, OpenclProcessing, BufferDescription
+
+if pyopencl:
+ mf = pyopencl.mem_flags
+logger = logging.getLogger(__name__)
+
+
+class ImageProcessing(OpenclProcessing):
+
+ kernel_files = ["cast", "map", "max_min", "histogram"]
+
+ converter = {numpy.dtype(numpy.uint8): "u8_to_float",
+ numpy.dtype(numpy.int8): "s8_to_float",
+ numpy.dtype(numpy.uint16): "u16_to_float",
+ numpy.dtype(numpy.int16): "s16_to_float",
+ numpy.dtype(numpy.uint32): "u32_to_float",
+ numpy.dtype(numpy.int32): "s32_to_float",
+ }
+
+ def __init__(self, shape=None, ncolors=1, template=None,
+ ctx=None, devicetype="all", platformid=None, deviceid=None,
+ block_size=None, memory=None, profile=False):
+ """Constructor of the ImageProcessing class
+
+ :param ctx: actual working context, left to None for automatic
+ initialization from device type or platformid/deviceid
+ :param devicetype: type of device, can be "CPU", "GPU", "ACC" or "ALL"
+ :param platformid: integer with the platform_identifier, as given by clinfo
+ :param deviceid: Integer with the device identifier, as given by clinfo
+ :param block_size: preferred workgroup size, may vary depending on the
+ out come of the compilation
+ :param memory: minimum memory available on device
+ :param profile: switch on profiling to be able to profile at the kernel
+ level, store profiling elements (makes code slightly slower)
+ """
+ OpenclProcessing.__init__(self, ctx=ctx, devicetype=devicetype,
+ platformid=platformid, deviceid=deviceid,
+ block_size=block_size, memory=memory, profile=profile)
+ if template is not None:
+ shape = template.shape
+ if len(shape) > 2:
+ self.ncolors = shape[2]
+ self.shape = shape[:2]
+ else:
+ self.ncolors = 1
+ self.shape = shape
+ else:
+ self.ncolors = ncolors
+ self.shape = shape
+ assert shape is not None
+ self.buffer_shape = self.shape if self.ncolors == 1 else self.shape + (self.ncolors,)
+ kernel_files = [os.path.join("image", i) for i in self.kernel_files]
+ self.compile_kernels(kernel_files,
+ compile_options="-DNB_COLOR=%i" % self.ncolors)
+ if self.ncolors == 1:
+ img_shape = self.shape
+ else:
+ img_shape = self.shape + (self.ncolors,)
+
+ buffers = [BufferDescription("image0_d", img_shape, numpy.float32, None),
+ BufferDescription("image1_d", img_shape, numpy.float32, None),
+ BufferDescription("image2_d", img_shape, numpy.float32, None),
+ BufferDescription("max_min_d", 2, numpy.float32, None),
+ BufferDescription("cnt_d", 1, numpy.int32, None), ]
+ # Temporary buffer for max-min reduction
+ self.wg_red = kernel_workgroup_size(self.program, self.kernels.max_min_reduction_stage1)
+ if self.wg_red > 1:
+ self.wg_red = min(self.wg_red,
+ numpy.int32(1 << int(floor(log(sqrt(numpy.prod(self.shape)), 2)))))
+ tmp = BufferDescription("tmp_max_min_d", 2 * self.wg_red, numpy.float32, None)
+ buffers.append(tmp)
+ self.allocate_buffers(buffers, use_array=True)
+ self.cl_mem["cnt_d"].fill(0)
+
+ def __repr__(self):
+ return "ImageProcessing for shape=%s, %i colors initalized on %s" % \
+ (self.shape, self.ncolors, self.ctx.devices[0].name)
+
+ def _get_in_out_buffers(self, img=None, copy=True, out=None,
+ out_dtype=None, out_size=None):
+ """Internal method used to select the proper buffers before processing.
+
+ :param img: expects a numpy array or a pyopencl.array of dim 2 or 3
+ :param copy: set to False to directly re-use a pyopencl array
+ :param out: provide an output buffer to store the result
+ :param out_dtype: enforce the type of the output buffer (optional)
+ :param out_size: enforce the size of the output buffer (optional)
+ :return: input_buffer, output_buffer
+
+ Nota: this is not locked.
+ """
+ events = []
+ if out is not None and isinstance(out, pyopencl.array.Array):
+ if (out_size or out_dtype) is not None:
+ if out_size is not None:
+ assert out.size > out_size
+ if out_dtype is not None:
+ assert out_dtype == out.dtype
+ else: # assume it is same size and type as weoking buffer
+ assert out.shape == self.buffer_shape
+ assert out.dtype == numpy.float32
+ out.finish()
+ output_array = out
+ else:
+ if out_dtype != numpy.float32 and out_size:
+ name = "%s_%s_d" % (numpy.dtype(out_dtype), out_size)
+ if name not in self.cl_mem:
+ output_array = self.cl_mem[name] = pyopencl.array.empty(self.queue, (out_size,), out_dtype)
+ else:
+ output_array = self.cl_mem[name]
+ else:
+ output_array = self.cl_mem["image2_d"]
+
+ if img is None:
+ input_array = self.cl_mem["image1_d"]
+ if isinstance(img, pyopencl.array.Array):
+ if copy:
+ evt = pyopencl.enqueue_copy(self.queue, self.cl_mem["image1_d"].data, img.data)
+ input_array = self.cl_mem["image1_d"]
+ events.append(EventDescription("copy D->D", evt))
+ else:
+ img.finish()
+ input_array = img
+ evt = None
+ else:
+ # assume this is numpy
+ if img.dtype.itemsize > 4:
+ logger.warning("Casting to float32 on CPU")
+ evt = pyopencl.enqueue_copy(self.queue, self.cl_mem["image1_d"].data, numpy.ascontiguousarray(img, numpy.float32))
+ input_array = self.cl_mem["image1_d"]
+ events.append(EventDescription("cast+copy H->D", evt))
+ else:
+ evt = pyopencl.enqueue_copy(self.queue, self.cl_mem["image1_d"].data, numpy.ascontiguousarray(img))
+ input_array = self.cl_mem["image1_d"]
+ events.append(EventDescription("copy H->D", evt))
+ if self.profile:
+ self.events += events
+ return input_array, output_array
+
+ def to_float(self, img, copy=True, out=None):
+ """ Takes any array and convert it to a float array for ease of processing.
+
+ :param img: expects a numpy array or a pyopencl.array of dim 2 or 3
+ :param copy: set to False to directly re-use a pyopencl array
+ :param out: provide an output buffer to store the result
+ """
+ assert img.shape == self.buffer_shape
+
+ events = []
+ with self.sem:
+ input_array, output_array = self._get_in_out_buffers(img, copy, out)
+ if (img.dtype.itemsize > 4) or (img.dtype == numpy.float32):
+ # copy device -> device, already there as float32
+ ev = pyopencl.enqueue_copy(self.queue, output_array.data, input_array.data)
+ events.append(EventDescription("copy D->D", ev))
+ else:
+ # Cast to float:
+ name = self.converter[img.dtype]
+ kernel = self.kernels.get_kernel(name)
+ ev = kernel(self.queue, (self.shape[1], self.shape[0]), None,
+ input_array.data, output_array.data,
+ numpy.int32(self.shape[1]), numpy.int32(self.shape[0])
+ )
+ events.append(EventDescription("cast %s" % name, ev))
+
+ if self.profile:
+ self.events += events
+ if out is None:
+ res = output_array.get()
+ return res
+ else:
+ output_array.finish()
+ return output_array
+
+ def normalize(self, img, mini=0.0, maxi=1.0, copy=True, out=None):
+ """Scale the intensity of the image so that the minimum is 0 and the
+ maximum is 1.0 (or any value suggested).
+
+ :param img: numpy array or pyopencl array of dim 2 or 3 and of type float
+ :param mini: Expected minimum value
+ :param maxi: expected maxiumum value
+ :param copy: set to False to use directly the input buffer
+ :param out: provides an output buffer. prevents a copy D->H
+
+ This uses a min/max reduction in two stages plus a map operation
+ """
+ assert img.shape == self.buffer_shape
+ events = []
+ with self.sem:
+ input_array, output_array = self._get_in_out_buffers(img, copy, out)
+ size = numpy.int32(numpy.prod(self.shape))
+ if self.wg_red == 1:
+ # Probably on MacOS CPU WG==1 --> serial code.
+ kernel = self.kernels.get_kernel("max_min_serial")
+ evt = kernel(self.queue, (1,), (1,),
+ input_array.data,
+ size,
+ self.cl_mem["max_min_d"].data)
+ ed = EventDescription("max_min_serial", evt)
+ events.append(ed)
+ else:
+ stage1 = self.kernels.max_min_reduction_stage1
+ stage2 = self.kernels.max_min_reduction_stage2
+ local_mem = pyopencl.LocalMemory(int(self.wg_red * 8))
+ k1 = stage1(self.queue, (int(self.wg_red ** 2),), (int(self.wg_red),),
+ input_array.data,
+ self.cl_mem["tmp_max_min_d"].data,
+ size,
+ local_mem)
+ k2 = stage2(self.queue, (int(self.wg_red),), (int(self.wg_red),),
+ self.cl_mem["tmp_max_min_d"].data,
+ self.cl_mem["max_min_d"].data,
+ local_mem)
+
+ events += [EventDescription("max_min_stage1", k1),
+ EventDescription("max_min_stage2", k2)]
+
+ evt = self.kernels.normalize_image(self.queue, (self.shape[1], self.shape[0]), None,
+ input_array.data, output_array.data,
+ numpy.int32(self.shape[1]), numpy.int32(self.shape[0]),
+ self.cl_mem["max_min_d"].data,
+ numpy.float32(mini), numpy.float32(maxi))
+ events.append(EventDescription("normalize", evt))
+ if self.profile:
+ self.events += events
+
+ if out is None:
+ res = output_array.get()
+ return res
+ else:
+ output_array.finish()
+ return output_array
+
+ def histogram(self, img=None, nbins=255, range=None,
+ log_scale=False, copy=True, out=None):
+ """Compute the histogram of a set of data.
+
+ :param img: input image. If None, use the one already on the device
+ :param nbins: number of bins
+ :param range: the lower and upper range of the bins. If not provided,
+ range is simply ``(a.min(), a.max())``. Values outside the
+ range are ignored. The first element of the range must be
+ less than or equal to the second.
+ :param log_scale: perform the binning in lograrithmic scale.
+ Open to extension
+ :param copy: unset to directly use the input buffer without copy
+ :param out: use a provided array for offering the result
+ :return: histogram (size=nbins), edges (size=nbins+1)
+ API similar to numpy
+ """
+ assert img.shape == self.buffer_shape
+
+ input_array = self.to_float(img, copy=copy, out=self.cl_mem["image0_d"])
+ events = []
+ with self.sem:
+ input_array, output_array = self._get_in_out_buffers(input_array, copy=False,
+ out=out,
+ out_dtype=numpy.int32,
+ out_size=nbins)
+
+ if range is None:
+ # measure actually the bounds
+ size = numpy.int32(numpy.prod(self.shape))
+ if self.wg_red == 1:
+ # Probably on MacOS CPU WG==1 --> serial code.
+ kernel = self.kernels.get_kernel("max_min_serial")
+
+ evt = kernel(self.queue, (1,), (1,),
+ input_array.data,
+ size,
+ self.cl_mem["max_min_d"].data)
+ events.append(EventDescription("max_min_serial", evt))
+ else:
+ stage1 = self.kernels.max_min_reduction_stage1
+ stage2 = self.kernels.max_min_reduction_stage2
+ local_mem = pyopencl.LocalMemory(int(self.wg_red * 2 * numpy.dtype("float32").itemsize))
+ k1 = stage1(self.queue, (int(self.wg_red ** 2),), (int(self.wg_red),),
+ input_array.data,
+ self.cl_mem["tmp_max_min_d"].data,
+ size,
+ local_mem)
+ k2 = stage2(self.queue, (int(self.wg_red),), (int(self.wg_red),),
+ self.cl_mem["tmp_max_min_d"].data,
+ self.cl_mem["max_min_d"].data,
+ local_mem)
+
+ events += [EventDescription("max_min_stage1", k1),
+ EventDescription("max_min_stage2", k2)]
+ maxi, mini = self.cl_mem["max_min_d"].get()
+ else:
+ mini = numpy.float32(min(range))
+ maxi = numpy.float32(max(range))
+ device = self.ctx.devices[0]
+ nb_engines = device.max_compute_units
+ tmp_size = nb_engines * nbins
+ name = "tmp_int32_%s_d" % (tmp_size)
+ if name not in self.cl_mem:
+ tmp_array = self.cl_mem[name] = pyopencl.array.empty(self.queue, (tmp_size,), numpy.int32)
+ else:
+ tmp_array = self.cl_mem[name]
+
+ edge_name = "tmp_float32_%s_d" % (nbins + 1)
+ if edge_name not in self.cl_mem:
+ edges_array = self.cl_mem[edge_name] = pyopencl.array.empty(self.queue, (nbins + 1,), numpy.float32)
+ else:
+ edges_array = self.cl_mem[edge_name]
+
+ shared = pyopencl.LocalMemory(numpy.dtype(numpy.int32).itemsize * nbins)
+
+ # Handle log-scale
+ if log_scale:
+ map_operation = numpy.int32(1)
+ else:
+ map_operation = numpy.int32(0)
+ kernel = self.kernels.get_kernel("histogram")
+ wg = min(device.max_work_group_size,
+ 1 << (int(ceil(log(nbins, 2)))),
+ self.kernels.max_workgroup_size(kernel))
+ evt = kernel(self.queue, (wg * nb_engines,), (wg,),
+ input_array.data,
+ numpy.int32(input_array.size),
+ mini,
+ maxi,
+ map_operation,
+ output_array.data,
+ edges_array.data,
+ numpy.int32(nbins),
+ tmp_array.data,
+ self.cl_mem["cnt_d"].data,
+ shared)
+ events.append(EventDescription("histogram", evt))
+
+ if self.profile:
+ self.events += events
+
+ if out is None:
+ res = output_array.get()
+ return res, edges_array.get()
+ else:
+ output_array.finish()
+ return output_array, edges_array
diff --git a/silx/opencl/processing.py b/silx/opencl/processing.py
index 1997a55..250582d 100644
--- a/silx/opencl/processing.py
+++ b/silx/opencl/processing.py
@@ -4,7 +4,7 @@
# Project: S I L X project
# https://github.com/silx-kit/silx
#
-# Copyright (C) 2012-2017 European Synchrotron Radiation Facility, Grenoble, France
+# Copyright (C) 2012-2018 European Synchrotron Radiation Facility, Grenoble, France
#
# Principal author: Jérôme Kieffer (Jerome.Kieffer@ESRF.eu)
#
@@ -31,7 +31,7 @@
#
"""
-Common OpenCL abstract base classes for different processing
+Common OpenCL abstract base classe for different processing
"""
from __future__ import absolute_import, print_function, division
@@ -41,7 +41,7 @@ __author__ = "Jerome Kieffer"
__contact__ = "Jerome.Kieffer@ESRF.eu"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-__date__ = "03/10/2017"
+__date__ = "27/02/2018"
__status__ = "stable"
@@ -69,17 +69,29 @@ class KernelContainer(object):
:param program: the OpenCL program as generated by PyOpenCL
"""
+ self._program = program
for kernel in program.all_kernels():
self.__setattr__(kernel.function_name, kernel)
def get_kernels(self):
"return the dictionary with all kernels"
- return self.__dict__.copy()
+ return dict(item for item in self.__dict__.items()
+ if not item[0].startswith("_"))
def get_kernel(self, name):
"get a kernel from its name"
+ logger.debug("KernelContainer.get_kernel(%s)", name)
return self.__dict__.get(name)
+ def max_workgroup_size(self, kernel_name):
+ "Retrieve the compile time max_workgroup_size for a given kernel"
+ if isinstance(kernel_name, pyopencl.Kernel):
+ kernel = kernel_name
+ else:
+ kernel = self.get_kernel(kernel_name)
+
+ return kernel_workgroup_size(self._program, kernel)
+
class OpenclProcessing(object):
"""Abstract class for different types of OpenCL processing.
@@ -97,7 +109,7 @@ class OpenclProcessing(object):
kernel_files = []
def __init__(self, ctx=None, devicetype="all", platformid=None, deviceid=None,
- block_size=None, profile=False):
+ block_size=None, memory=None, profile=False):
"""Constructor of the abstract OpenCL processing class
:param ctx: actual working context, left to None for automatic
@@ -107,6 +119,7 @@ class OpenclProcessing(object):
:param deviceid: Integer with the device identifier, as given by clinfo
:param block_size: preferred workgroup size, may vary depending on the
out come of the compilation
+ :param memory: minimum memory available on device
:param profile: switch on profiling to be able to profile at the kernel
level, store profiling elements (makes code slightly slower)
"""
@@ -116,10 +129,13 @@ class OpenclProcessing(object):
self.cl_mem = {} # dict with all buffer allocated
self.cl_program = None # The actual OpenCL program
self.cl_kernel_args = {} # dict with all kernel arguments
+ self.queue = None
if ctx:
self.ctx = ctx
else:
- self.ctx = ocl.create_context(devicetype=devicetype, platformid=platformid, deviceid=deviceid)
+ self.ctx = ocl.create_context(devicetype=devicetype,
+ platformid=platformid, deviceid=deviceid,
+ memory=memory)
device_name = self.ctx.devices[0].name.strip()
platform_name = self.ctx.devices[0].platform.name.strip()
platform = ocl.get_platform(platform_name)
@@ -134,19 +150,23 @@ class OpenclProcessing(object):
def __del__(self):
"""Destructor: release all buffers and programs
"""
+ self.reset_log()
self.free_kernels()
self.free_buffers()
self.queue = None
+ self.device = None
self.ctx = None
gc.collect()
- def allocate_buffers(self, buffers=None):
+ def allocate_buffers(self, buffers=None, use_array=False):
"""
Allocate OpenCL buffers required for a specific configuration
:param buffers: a list of BufferDescriptions, leave to None for
paramatrized buffers.
-
+ :param use_array: allocate memory as pyopencl.array.Array
+ instead of pyopencl.Buffer
+
Note that an OpenCL context also requires some memory, as well
as Event and other OpenCL functionalities which cannot and are
not taken into account here. The memory required by a context
@@ -166,7 +186,7 @@ class OpenclProcessing(object):
# check if enough memory is available on the device
ualloc = 0
for buf in buffers:
- ualloc += numpy.dtype(buf.dtype).itemsize * buf.size
+ ualloc += numpy.dtype(buf.dtype).itemsize * numpy.prod(buf.size)
logger.info("%.3fMB are needed on device: %s, which has %.3fMB",
ualloc / 1.0e6, self.device, self.device.memory / 1.0e6)
@@ -177,9 +197,13 @@ class OpenclProcessing(object):
# do the allocation
try:
- for buf in buffers:
- size = numpy.dtype(buf.dtype).itemsize * buf.size
- mem[buf.name] = pyopencl.Buffer(self.ctx, buf.flags, int(size))
+ if use_array:
+ for buf in buffers:
+ mem[buf.name] = pyopencl.array.empty(self.queue, buf.size, buf.dtype)
+ else:
+ for buf in buffers:
+ size = numpy.dtype(buf.dtype).itemsize * numpy.prod(buf.size)
+ mem[buf.name] = pyopencl.Buffer(self.ctx, buf.flags, int(size))
except pyopencl.MemoryError as error:
release_cl_buffers(mem)
raise MemoryError(error)
@@ -199,8 +223,8 @@ class OpenclProcessing(object):
self.cl_mem.update(mem)
def check_workgroup_size(self, kernel_name):
- kernel = self.kernels.get_kernel(kernel_name)
- self.compiletime_workgroup_size = kernel_workgroup_size(self.program, kernel)
+ "Calculate the maximum workgroup size from given kernel after compilation"
+ return self.kernels.max_workgroup_size(kernel_name)
def free_buffers(self):
"""free all device.memory allocated on the device
@@ -282,6 +306,13 @@ class OpenclProcessing(object):
logger.info(os.linesep.join(out))
return out
+ def reset_log(self):
+ """
+ Resets the profiling timers
+ """
+ with self.sem:
+ self.events = []
+
# This should be implemented by concrete class
# def __copy__(self):
# """Shallow copy of the object
diff --git a/silx/opencl/projection.py b/silx/opencl/projection.py
index 0ebe9bc..0505d80 100644
--- a/silx/opencl/projection.py
+++ b/silx/opencl/projection.py
@@ -29,7 +29,7 @@ from __future__ import absolute_import, print_function, with_statement, division
__authors__ = ["A. Mirone, P. Paleo"]
__license__ = "MIT"
-__date__ = "26/06/2017"
+__date__ = "28/02/2018"
import logging
import numpy as np
@@ -52,6 +52,7 @@ class Projection(OpenclProcessing):
OpenCL
"""
kernel_files = ["proj.cl", "array_utils.cl"]
+ logger.warning("Forward Projecter is untested and unsuported for now")
def __init__(self, slice_shape, angles, axis_position=None,
detector_width=None, normalize=False, ctx=None,
@@ -111,10 +112,10 @@ class Projection(OpenclProcessing):
endpoint=False).astype(dtype=np.float32)
else:
self.nprojs = len(self.angles)
- self.offset_x = -np.float32((self.shape[1]-1)/2. - self.axis_pos) # TODO: custom
- self.offset_y = -np.float32((self.shape[0]-1)/2. - self.axis_pos) # TODO: custom
+ self.offset_x = -np.float32((self.shape[1] - 1) / 2. - self.axis_pos) # TODO: custom
+ self.offset_y = -np.float32((self.shape[0] - 1) / 2. - self.axis_pos) # TODO: custom
# Reset axis_pos once offset are computed
- self.axis_pos0 = np.float((self.shape[1]-1)/2.)
+ self.axis_pos0 = np.float((self.shape[1] - 1) / 2.)
# Workgroup, ndrange and shared size
self.dimgrid_x = _idivup(self.dwidth, 16)
@@ -125,7 +126,7 @@ class Projection(OpenclProcessing):
self.wg = (16, 16)
self.ndrange = (
int(self.dimgrid_x) * self.wg[0], # int(): pyopencl <= 2015.1
- int(self.dimgrid_y) * self.wg[1] # int(): pyopencl <= 2015.1
+ int(self.dimgrid_y) * self.wg[1] # int(): pyopencl <= 2015.1
)
self.is_cpu = False
@@ -146,7 +147,7 @@ class Projection(OpenclProcessing):
self.nprojs, np.float32)
}
)
- self._tmp_extended_img = np.zeros((self.shape[0]+2, self.shape[1]+2),
+ self._tmp_extended_img = np.zeros((self.shape[0] + 2, self.shape[1] + 2),
dtype=np.float32)
if self.is_cpu:
self.allocate_slice()
@@ -158,41 +159,41 @@ class Projection(OpenclProcessing):
if self.is_cpu:
self.cl_mem["d_slice"].fill(0.)
# enqueue_fill_buffer has issues if opencl 1.2 is not present
- #~ pyopencl.enqueue_fill_buffer(
- #~ self.queue,
- #~ self.cl_mem["d_slice"],
- #~ np.float32(0),
- #~ 0,
- #~ self._tmp_extended_img.size * _sizeof(np.float32)
- #~ )
+ # ~ pyopencl.enqueue_fill_buffer(
+ # ~ self.queue,
+ # ~ self.cl_mem["d_slice"],
+ # ~ np.float32(0),
+ # ~ 0,
+ # ~ self._tmp_extended_img.size * _sizeof(np.float32)
+ # ~ )
# Precomputations
self.compute_angles()
self.proj_precomputations()
self.cl_mem["d_axis_corrections"].fill(0.)
# enqueue_fill_buffer has issues if opencl 1.2 is not present
- #~ pyopencl.enqueue_fill_buffer(
- #~ self.queue,
- #~ self.cl_mem["d_axis_corrections"],
- #~ np.float32(0),
- #~ 0,
- #~ self.nprojs*_sizeof(np.float32)
- #~ )
+ # ~ pyopencl.enqueue_fill_buffer(
+ # ~ self.queue,
+ # ~ self.cl_mem["d_axis_corrections"],
+ # ~ np.float32(0),
+ # ~ 0,
+ # ~ self.nprojs*_sizeof(np.float32)
+ # ~ )
# Shorthands
self._d_sino = self.cl_mem["_d_sino"]
OpenclProcessing.compile_kernels(self, self.kernel_files)
# check that workgroup can actually be (16, 16)
- self.check_workgroup_size("forward_kernel_cpu")
+ self.compiletime_workgroup_size = self.kernels.max_workgroup_size("forward_kernel_cpu")
def compute_angles(self):
- angles2 = np.zeros(self._dimrecy, dtype=np.float32) # dimrecy != num_projs
+ angles2 = np.zeros(self._dimrecy, dtype=np.float32) # dimrecy != num_projs
angles2[:self.nprojs] = np.copy(self.angles)
- angles2[self.nprojs:] = angles2[self.nprojs-1]
+ angles2[self.nprojs:] = angles2[self.nprojs - 1]
self.angles2 = angles2
pyopencl.enqueue_copy(self.queue, self.cl_mem["d_angles"], angles2)
def allocate_slice(self):
- self.add_to_cl_mem({"d_slice": parray.zeros(self.queue, (self.shape[1]+2, self.shape[1]+2), np.float32)})
+ self.add_to_cl_mem({"d_slice": parray.zeros(self.queue, (self.shape[1] + 2, self.shape[1] + 2), np.float32)})
def allocate_textures(self):
self.d_image_tex = pyopencl.Image(
@@ -211,13 +212,13 @@ class Projection(OpenclProcessing):
if self.is_cpu:
# TODO: create NoneEvent
return self.transfer_to_slice(image2)
- #~ return pyopencl.enqueue_copy(
- #~ self.queue,
- #~ self.cl_mem["d_slice"].data,
- #~ image2,
- #~ origin=(1, 1),
- #~ region=image.shape[::-1]
- #~ )
+ # ~ return pyopencl.enqueue_copy(
+ # ~ self.queue,
+ # ~ self.cl_mem["d_slice"].data,
+ # ~ image2,
+ # ~ origin=(1, 1),
+ # ~ region=image.shape[::-1]
+ # ~ )
else:
return pyopencl.enqueue_copy(
self.queue,
@@ -238,11 +239,11 @@ class Projection(OpenclProcessing):
d_image,
offset=0,
origin=(1, 1),
- region=(int(self.shape[1]), int(self.shape[0]))#self.shape[::-1] # pyopencl <= 2015.2
+ region=(int(self.shape[1]), int(self.shape[0])) # self.shape[::-1] # pyopencl <= 2015.2
)
def transfer_to_slice(self, image):
- image2 = np.zeros((image.shape[0]+2, image.shape[1]+2), dtype=np.float32)
+ image2 = np.zeros((image.shape[0] + 2, image.shape[1] + 2), dtype=np.float32)
image2[1:-1, 1:-1] = image.astype(np.float32)
self.cl_mem["d_slice"].set(image2)
@@ -272,14 +273,14 @@ class Projection(OpenclProcessing):
strideLine[0][case1] = 0
strideLine[1][case1] = 1
- beginPos[0][case2] = dimslice-1
- beginPos[1][case2] = dimslice-1
+ beginPos[0][case2] = dimslice - 1
+ beginPos[1][case2] = dimslice - 1
strideJoseph[0][case2] = -1
strideJoseph[1][case2] = 0
strideLine[0][case2] = 0
strideLine[1][case2] = -1
- beginPos[0][case3] = dimslice-1
+ beginPos[0][case3] = dimslice - 1
beginPos[1][case3] = 0
strideJoseph[0][case3] = 0
strideJoseph[1][case3] = 1
@@ -287,16 +288,16 @@ class Projection(OpenclProcessing):
strideLine[1][case3] = 0
beginPos[0][case4] = 0
- beginPos[1][case4] = dimslice-1
+ beginPos[1][case4] = dimslice - 1
strideJoseph[0][case4] = 0
strideJoseph[1][case4] = -1
strideLine[0][case4] = 1
strideLine[1][case4] = 0
# For debug purpose
- #~ self.beginPos = beginPos
- #~ self.strideJoseph = strideJoseph
- #~ self.strideLine = strideLine
+ # ~ self.beginPos = beginPos
+ # ~ self.strideJoseph = strideJoseph
+ # ~ self.strideLine = strideLine
#
pyopencl.enqueue_copy(self.queue, self.cl_mem["d_beginPos"], beginPos)
@@ -307,7 +308,7 @@ class Projection(OpenclProcessing):
return pyopencl.LocalMemory(self.local_mem) # constant for all image sizes
def cpy2d_to_sino(self, dst):
- ndrange = (int(self.dwidth), int(self.nprojs)) # pyopencl < 2015.2
+ ndrange = (int(self.dwidth), int(self.nprojs)) # pyopencl < 2015.2
sino_shape_ocl = np.int32(ndrange)
wg = None
kernel_args = (
@@ -325,13 +326,13 @@ class Projection(OpenclProcessing):
"""
copy a Nx * Ny slice to self.d_slice which is (Nx+2)*(Ny+2)
"""
- ndrange = (int(self.shape[1]), int(self.shape[0])) #self.shape[::-1] # pyopencl < 2015.2
+ ndrange = (int(self.shape[1]), int(self.shape[0])) # self.shape[::-1] # pyopencl < 2015.2
wg = None
slice_shape_ocl = np.int32(ndrange)
kernel_args = (
self.cl_mem["d_slice"].data,
src,
- np.int32(self.shape[1]+2),
+ np.int32(self.shape[1] + 2),
np.int32(self.shape[1]),
np.int32((1, 1)),
np.int32((0, 0)),
@@ -413,7 +414,7 @@ class Projection(OpenclProcessing):
# /with self.sem
if self.profile:
self.events += events
- #~ res = self._ex_sino
+ # ~ res = self._ex_sino
return res
__call__ = projection
diff --git a/silx/opencl/setup.py b/silx/opencl/setup.py
index a2ae244..10fb1be 100644
--- a/silx/opencl/setup.py
+++ b/silx/opencl/setup.py
@@ -27,7 +27,7 @@ __contact__ = "jerome.kieffer@esrf.eu"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__authors__ = ["J. Kieffer"]
-__date__ = "16/08/2017"
+__date__ = "16/10/2017"
import os.path
from numpy.distutils.misc_util import Configuration
@@ -38,6 +38,7 @@ def configuration(parent_package='', top_path=None):
path = os.path.dirname(os.path.abspath(__file__))
if os.path.exists(os.path.join(path, 'sift')):
config.add_subpackage('sift')
+ config.add_subpackage('codec')
config.add_subpackage('test')
return config
diff --git a/silx/opencl/test/__init__.py b/silx/opencl/test/__init__.py
index f6aadcd..2fe88ea 100644
--- a/silx/opencl/test/__init__.py
+++ b/silx/opencl/test/__init__.py
@@ -24,7 +24,7 @@
__authors__ = ["J. Kieffer"]
__license__ = "MIT"
-__date__ = "01/09/2017"
+__date__ = "17/10/2017"
import os
import unittest
@@ -34,6 +34,8 @@ from . import test_backprojection
from . import test_projection
from . import test_linalg
from . import test_array_utils
+from ..codec import test as test_codec
+from . import test_image
def suite():
test_suite = unittest.TestSuite()
@@ -43,7 +45,8 @@ def suite():
test_suite.addTests(test_projection.suite())
test_suite.addTests(test_linalg.suite())
test_suite.addTests(test_array_utils.suite())
-
+ test_suite.addTests(test_codec.suite())
+ test_suite.addTests(test_image.suite())
# Allow to remove sift from the project
test_base_dir = os.path.dirname(__file__)
sift_dir = os.path.join(test_base_dir, "..", "sift")
diff --git a/silx/opencl/test/test_addition.py b/silx/opencl/test/test_addition.py
index 89e49be..cde86e2 100644
--- a/silx/opencl/test/test_addition.py
+++ b/silx/opencl/test/test_addition.py
@@ -35,7 +35,7 @@ __authors__ = ["Henri Payno, Jérôme Kieffer"]
__contact__ = "jerome.kieffer@esrf.eu"
__license__ = "MIT"
__copyright__ = "2013 European Synchrotron Radiation Facility, Grenoble, France"
-__date__ = "15/03/2017"
+__date__ = "12/02/2018"
import logging
import numpy
@@ -108,7 +108,7 @@ class TestAddition(unittest.TestCase):
else:
res = d_array_result.get()
good = numpy.allclose(res, self.data - 5)
- if good and wg>self.max_valid_wg:
+ if good and wg > self.max_valid_wg:
self.__class__.max_valid_wg = wg
self.assert_(good, "calculation is correct for WG=%s" % wg)
@@ -127,7 +127,7 @@ class TestAddition(unittest.TestCase):
def suite():
testSuite = unittest.TestSuite()
testSuite.addTest(TestAddition("test_add"))
- testSuite.addTest(TestAddition("test_measurement"))
+ # testSuite.addTest(TestAddition("test_measurement"))
return testSuite
diff --git a/silx/opencl/test/test_backprojection.py b/silx/opencl/test/test_backprojection.py
index 342bd2f..70ce2ae 100644
--- a/silx/opencl/test/test_backprojection.py
+++ b/silx/opencl/test/test_backprojection.py
@@ -30,7 +30,7 @@ from __future__ import division, print_function
__authors__ = ["Pierre paleo"]
__license__ = "MIT"
__copyright__ = "2013-2017 European Synchrotron Radiation Facility, Grenoble, France"
-__date__ = "05/10/2017"
+__date__ = "19/01/2018"
import time
@@ -89,7 +89,7 @@ class TestFBP(unittest.TestCase):
# ~ self.skipTest("Backprojection is not implemented on CPU for OS X yet")
self.getfiles()
self.fbp = backprojection.Backprojection(self.sino.shape, profile=True)
- if self.fbp.compiletime_workgroup_size < 16:
+ if self.fbp.compiletime_workgroup_size < 16 * 16:
self.skipTest("Current implementation of OpenCL backprojection is not supported on this platform yet")
def tearDown(self):
diff --git a/silx/opencl/test/test_image.py b/silx/opencl/test/test_image.py
new file mode 100644
index 0000000..d73a854
--- /dev/null
+++ b/silx/opencl/test/test_image.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Project: image manipulation in OpenCL
+# https://github.com/silx-kit/silx
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Simple test of image manipulation
+"""
+
+from __future__ import division, print_function
+
+__authors__ = ["Jérôme Kieffer"]
+__contact__ = "jerome.kieffer@esrf.eu"
+__license__ = "MIT"
+__copyright__ = "2017 European Synchrotron Radiation Facility, Grenoble, France"
+__date__ = "13/02/2018"
+
+import logging
+import numpy
+
+import unittest
+from ..common import ocl, _measure_workgroup_size
+if ocl:
+ import pyopencl
+ import pyopencl.array
+from ...test.utils import utilstest
+from ..image import ImageProcessing
+logger = logging.getLogger(__name__)
+try:
+ from PIL import Image
+except ImportError:
+ Image = None
+
+
+@unittest.skipUnless(ocl and Image, "PyOpenCl/Image is missing")
+class TestImage(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestImage, cls).setUpClass()
+ if ocl:
+ cls.ctx = ocl.create_context()
+ cls.lena = utilstest.getfile("lena.png")
+ cls.data = numpy.asarray(Image.open(cls.lena))
+ cls.ip = ImageProcessing(ctx=cls.ctx, template=cls.data, profile=True)
+
+ @classmethod
+ def tearDownClass(cls):
+ super(TestImage, cls).tearDownClass()
+ cls.ctx = None
+ cls.lena = None
+ cls.data = None
+ if logger.level <= logging.INFO:
+ logger.warning("\n".join(cls.ip.log_profile()))
+ cls.ip = None
+
+ def setUp(self):
+ if ocl is None:
+ return
+ self.data = numpy.asarray(Image.open(self.lena))
+
+ def tearDown(self):
+ self.img = self.data = None
+
+ @unittest.skipUnless(ocl, "pyopencl is missing")
+ def test_cast(self):
+ """
+ tests the cast kernel
+ """
+ res = self.ip.to_float(self.data)
+ self.assertEqual(res.shape, self.data.shape, "shape")
+ self.assertEqual(res.dtype, numpy.float32, "dtype")
+ self.assertEqual(abs(res - self.data).max(), 0, "content")
+
+ @unittest.skipUnless(ocl, "pyopencl is missing")
+ def test_normalize(self):
+ """
+ tests that all devices are working properly ...
+ """
+ tmp = pyopencl.array.empty(self.ip.ctx, self.data.shape, "float32")
+ res = self.ip.to_float(self.data, out=tmp)
+ res2 = self.ip.normalize(tmp, -100, 100, copy=False)
+ norm = (self.data.astype(numpy.float32) - self.data.min()) / (self.data.max() - self.data.min())
+ ref2 = 200 * norm - 100
+ self.assertLess(abs(res2 - ref2).max(), 3e-5, "content")
+
+ @unittest.skipUnless(ocl, "pyopencl is missing")
+ def test_histogram(self):
+ """
+ Test on a greyscaled image ... of Lena :)
+ """
+ lena_bw = (0.2126 * self.data[:, :, 0] +
+ 0.7152 * self.data[:, :, 1] +
+ 0.0722 * self.data[:, :, 2]).astype("int32")
+ ref = numpy.histogram(lena_bw, 255)
+ ip = ImageProcessing(ctx=self.ctx, template=lena_bw, profile=True)
+ res = ip.histogram(lena_bw, 255)
+ ip.log_profile()
+ delta = (ref[0] - res[0])
+ deltap = (ref[1] - res[1])
+ self.assertEqual(delta.sum(), 0, "errors are self-compensated")
+ self.assertLessEqual(abs(delta).max(), 1, "errors are small")
+ self.assertLessEqual(abs(deltap).max(), 3e-5, "errors on position are small: %s" % (abs(deltap).max()))
+
+
+def suite():
+ testSuite = unittest.TestSuite()
+ testSuite.addTest(TestImage("test_cast"))
+ testSuite.addTest(TestImage("test_normalize"))
+ testSuite.addTest(TestImage("test_histogram"))
+ return testSuite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest="suite")
diff --git a/silx/opencl/test/test_projection.py b/silx/opencl/test/test_projection.py
index c9a3a1c..7631128 100644
--- a/silx/opencl/test/test_projection.py
+++ b/silx/opencl/test/test_projection.py
@@ -30,7 +30,7 @@ from __future__ import division, print_function
__authors__ = ["Pierre paleo"]
__license__ = "MIT"
__copyright__ = "2013-2017 European Synchrotron Radiation Facility, Grenoble, France"
-__date__ = "14/06/2017"
+__date__ = "19/01/2018"
import time
@@ -49,35 +49,31 @@ from silx.test.utils import utilstest
logger = logging.getLogger(__name__)
-
@unittest.skipUnless(ocl and mako, "PyOpenCl is missing")
class TestProj(unittest.TestCase):
def setUp(self):
if ocl is None:
return
- #~ if sys.platform.startswith('darwin'):
- #~ self.skipTest("Projection is not implemented on CPU for OS X yet")
+ # ~ if sys.platform.startswith('darwin'):
+ # ~ self.skipTest("Projection is not implemented on CPU for OS X yet")
self.getfiles()
n_angles = self.sino.shape[0]
self.proj = projection.Projection(self.phantom.shape, n_angles)
- if self.proj.compiletime_workgroup_size < 16:
+ if self.proj.compiletime_workgroup_size < 16 * 16:
self.skipTest("Current implementation of OpenCL projection is not supported on this platform yet")
-
def tearDown(self):
self.phantom = None
self.sino = None
self.proj = None
-
def getfiles(self):
# load 512x512 MRI phantom
self.phantom = np.load(utilstest.getfile("Brain512.npz"))["data"]
# load sinogram computed with PyHST
self.sino = np.load(utilstest.getfile("sino500_pyhst.npz"))["data"]
-
def measure(self):
"Common measurement of timings"
t1 = time.time()
@@ -89,7 +85,6 @@ class TestProj(unittest.TestCase):
t2 = time.time()
return t2 - t1, result
-
def compare(self, res):
"""
Compare a result with the reference reconstruction.
@@ -100,7 +95,6 @@ class TestProj(unittest.TestCase):
ref = self.sino
return np.max(np.abs(res - ref))
-
@unittest.skipUnless(ocl and mako, "pyopencl is missing")
def test_proj(self):
"""
@@ -127,13 +121,11 @@ class TestProj(unittest.TestCase):
self.assertTrue(errmax < 1.e-6, "Max error is too high")
-
def suite():
testSuite = unittest.TestSuite()
testSuite.addTest(TestProj("test_proj"))
return testSuite
-
if __name__ == '__main__':
unittest.main(defaultTest="suite")
diff --git a/silx/resources/__init__.py b/silx/resources/__init__.py
index 250aed1..a45457a 100644
--- a/silx/resources/__init__.py
+++ b/silx/resources/__init__.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -56,7 +56,7 @@ of this modules to ensure access across different distribution schemes:
__authors__ = ["V.A. Sole", "Thomas Vincent", "J. Kieffer"]
__license__ = "MIT"
-__date__ = "06/09/2017"
+__date__ = "15/02/2018"
import os
@@ -162,7 +162,7 @@ def list_dir(resource):
:param str resource: Name of the resource directory to list
:return: list of name contained in the directory
- :rtype: list
+ :rtype: List
"""
resource_directory, resource_name = _get_package_and_resource(resource)
@@ -194,6 +194,16 @@ def is_dir(resource):
return os.path.isdir(path)
+def exists(resource):
+ """True is the resource exists.
+
+ :param str resource: Name of the resource
+ :rtype: bool
+ """
+ path = resource_filename(resource)
+ return os.path.exists(path)
+
+
def _get_package_and_resource(resource, default_directory=None):
"""
Return the resource directory class and a cleaned resource name without
@@ -301,7 +311,6 @@ class ExternalResources(object):
"""
self.project = project
self._initialized = False
- self._tempdir = None
self.sem = threading.Semaphore()
self.env_key = env_key or (self.project.upper() + "_DATA")
self.url_base = url_base
@@ -309,14 +318,6 @@ class ExternalResources(object):
self.timeout = timeout
self.data_home = None
- def _initialize_tmpdir(self):
- """Initialize the temporary directory"""
- if not self._tempdir:
- with self.sem:
- if not self._tempdir:
- self._tempdir = tempfile.mkdtemp("_" + getpass.getuser(),
- self.project + "_")
-
def _initialize_data(self):
"""Initialize for downloading test data"""
if not self._initialized:
@@ -335,26 +336,8 @@ class ExternalResources(object):
self.all_data = set(json.load(f))
self._initialized = True
- @property
- def tempdir(self):
- if not self._tempdir:
- self._initialize_tmpdir()
- return self._tempdir
-
def clean_up(self):
- """Removes the temporary directory (and all its content !)"""
- with self.sem:
- if not self._tempdir:
- return
- if not os.path.isdir(self._tempdir):
- return
- for root, dirs, files in os.walk(self._tempdir, topdown=False):
- for name in files:
- os.remove(os.path.join(root, name))
- for name in dirs:
- os.rmdir(os.path.join(root, name))
- os.rmdir(self._tempdir)
- self._tempdir = None
+ pass
def getfile(self, filename):
"""Downloads the requested file from web-server available
diff --git a/silx/resources/gui/icons/colormap-histogram.png b/silx/resources/gui/icons/colormap-histogram.png
new file mode 100644
index 0000000..a199adb
--- /dev/null
+++ b/silx/resources/gui/icons/colormap-histogram.png
Binary files differ
diff --git a/silx/resources/gui/icons/colormap-histogram.svg b/silx/resources/gui/icons/colormap-histogram.svg
new file mode 100644
index 0000000..951dee6
--- /dev/null
+++ b/silx/resources/gui/icons/colormap-histogram.svg
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="100%"
+ height="100%"
+ viewBox="0 0 32 32"
+ id="svg2">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <path
+ d="m 28.857399,28.857399 -26.0259991,0 C 12.191411,28.847797 6.2161112,2.8599459 15.844399,2.8313999 c 9.628288,-0.028546 3.521475,26.0156951 13.013,26.0259991 z"
+ id="rect4"
+ style="fill:#f7941e;fill-opacity:0.81568998;stroke:none" />
+ <path
+ d="m 28.857399,2.8314 0,26.025999 m -26.0259991,0 0,-26.025999"
+ id="rect4-3"
+ style="fill:none;stroke:#000000;stroke-width:1.39999998;stroke-miterlimit:2" />
+</svg>
diff --git a/silx/resources/gui/icons/colormap-none.png b/silx/resources/gui/icons/colormap-none.png
new file mode 100644
index 0000000..5441fa5
--- /dev/null
+++ b/silx/resources/gui/icons/colormap-none.png
Binary files differ
diff --git a/silx/resources/gui/icons/colormap-none.svg b/silx/resources/gui/icons/colormap-none.svg
new file mode 100644
index 0000000..127238a
--- /dev/null
+++ b/silx/resources/gui/icons/colormap-none.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="100%"
+ height="100%"
+ viewBox="0 0 32 32"
+ id="svg2">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <path
+ d="m 28.857399,2.8314 0,26.025999 m -26.0259991,0 0,-26.025999"
+ id="rect4-3"
+ style="fill:none;stroke:#000000;stroke-width:1.39999998;stroke-miterlimit:2" />
+</svg>
diff --git a/silx/resources/gui/icons/colormap-range.png b/silx/resources/gui/icons/colormap-range.png
new file mode 100644
index 0000000..6225375
--- /dev/null
+++ b/silx/resources/gui/icons/colormap-range.png
Binary files differ
diff --git a/silx/resources/gui/icons/colormap-range.svg b/silx/resources/gui/icons/colormap-range.svg
new file mode 100644
index 0000000..087af92
--- /dev/null
+++ b/silx/resources/gui/icons/colormap-range.svg
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="100%"
+ height="100%"
+ viewBox="0 0 32 32"
+ id="svg2">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <path
+ d="m 28.857399,2.8313999 0,26.0259991 -26.0259991,0 0,-26.0259991 z"
+ id="rect4"
+ style="fill:#f7941e;fill-opacity:0.81568998;stroke:none" />
+ <path
+ d="m 28.857399,2.8314 0,26.025999 m -26.0259991,0 0,-26.025999"
+ id="rect4-3"
+ style="fill:none;stroke:#000000;stroke-width:1.39999998;stroke-miterlimit:2" />
+</svg>
diff --git a/silx/resources/gui/icons/math-phase.png b/silx/resources/gui/icons/math-phase.png
index ee5800f..da3867a 100644
--- a/silx/resources/gui/icons/math-phase.png
+++ b/silx/resources/gui/icons/math-phase.png
Binary files differ
diff --git a/silx/resources/gui/icons/math-phase.svg b/silx/resources/gui/icons/math-phase.svg
index 3bd1671..44a7160 100644
--- a/silx/resources/gui/icons/math-phase.svg
+++ b/silx/resources/gui/icons/math-phase.svg
@@ -1,3 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
-<svg version="1.1" viewBox="0 0 32 32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><g><path d="m17.834 8.7344c-0.50782 1.14e-5 -0.76173 0.56642-0.76172 1.6992v8.0391c0.74218 2e-6 1.4844-0.40625 2.2266-1.2188 0.66405-0.72656 0.99608-1.9609 0.99609-3.7031-1.2e-5 -1.625-0.33595-2.875-1.0078-3.75-0.54688-0.71093-1.0313-1.0664-1.4531-1.0664m0-1.8398c1.0937 1.33e-5 2.1367 0.51564 3.1289 1.5469 1.0703 1.1016 1.6055 2.8047 1.6055 5.1094-1.4e-5 2.1172-0.53517 3.8047-1.6055 5.0625-1.0078 1.1875-2.3047 1.7812-3.8906 1.7812v4.7109h-2.1445v-4.6992c-1.5547 0-2.8555-0.59766-3.9023-1.793-1.0625-1.2187-1.5938-2.9023-1.5938-5.0508-1.3e-6 -2.2344 0.53125-3.9219 1.5938-5.0625 0.79687-0.85155 1.8437-1.3867 3.1406-1.6055v1.9102c-0.51563 0.1797-1 0.57423-1.4531 1.1836-0.67188 0.89845-1.0078 2.0899-1.0078 3.5742-3e-6 1.5781 0.33593 2.8164 1.0078 3.7148 0.60156 0.80469 1.3398 1.207 2.2148 1.207v-8.0508c-6e-6 -2.3594 0.96874-3.539 2.9062-3.5391"/></g><text x="0.49070829" y="48.29847" fill="#f7941e" font-family="Accanthis ADF Std" font-size="40px" letter-spacing="0px" word-spacing="0px" style="line-height:125%" xml:space="preserve"><tspan x="0.49070829" y="48.29847" fill="#f7941e" font-family="Sans" font-size="24px"/></text>
-</svg>
+<svg version="1.1" viewBox="0 0 32 32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><radialGradient id="d" cx="-16.701" cy="15.943" r="7.9219" gradientTransform="matrix(1,0,0,1.1509,0,-2.4056)" gradientUnits="userSpaceOnUse"><stop offset="0"/><stop stop-color="#c0c0c0" offset="1"/></radialGradient><radialGradient id="c" cx="-16.701" cy="15.943" r="7.9219" gradientTransform="matrix(1,0,0,1.1509,0,-2.4056)" gradientUnits="userSpaceOnUse" xlink:href="#d"/></defs><g transform="matrix(.062683 0 0 -.062683 15.338 21.436)"><path d="m17.834 8.7344c-0.50782 1.14e-5 -0.76173 0.56642-0.76172 1.6992v8.0391c0.74218 2e-6 1.4844-0.40625 2.2266-1.2188 0.66405-0.72656 0.99608-1.9609 0.99609-3.7031-1.2e-5 -1.625-0.33595-2.875-1.0078-3.75-0.54688-0.71093-1.0313-1.0664-1.4531-1.0664m0-1.8398c1.0937 1.33e-5 2.1367 0.51564 3.1289 1.5469 1.0703 1.1016 1.6055 2.8047 1.6055 5.1094-1.4e-5 2.1172-0.53517 3.8047-1.6055 5.0625-1.0078 1.1875-2.3047 1.7812-3.8906 1.7812v4.7109h-2.1445v-4.6992c-1.5547 0-2.8555-0.59766-3.9023-1.793-1.0625-1.2187-1.5938-2.9023-1.5938-5.0508-1.3e-6 -2.2344 0.53125-3.9219 1.5938-5.0625 0.79687-0.85155 1.8437-1.3867 3.1406-1.6055v1.9102c-0.51563 0.1797-1 0.57423-1.4531 1.1836-0.67188 0.89845-1.0078 2.0899-1.0078 3.5742-3e-6 1.5781 0.33593 2.8164 1.0078 3.7148 0.60156 0.80469 1.3398 1.207 2.2148 1.207v-8.0508c-6e-6 -2.3594 0.96874-3.539 2.9062-3.5391"/><g fill="url(#c)"><path d="m-14.111 6.8256c1.1797 1.32e-5 2.3164 0.50001 3.4102 1.5 1.2812 1.1641 1.9219 2.8945 1.9219 5.1914-1.74e-5 3.8672-1.9453 6.0508-5.8359 6.5508v4.9922h-4.1719v-4.9922c-3.8906-0.5-5.8359-2.6836-5.8359-6.5508-1e-6 -2.1562 0.64062-3.8437 1.9219-5.0625 1.0547-1.0078 2.2383-1.5117 3.5508-1.5117v2.6836c-0.17969 0.015635-0.43751 0.35548-0.77344 1.0195-0.32813 0.65626-0.49219 1.4727-0.49219 2.4492-5e-6 1.8672 0.54296 3.1914 1.6289 3.9727v-4.5938c-8e-6 -3.7656 1.5586-5.6484 4.6758-5.6484m0.12891 3.1172c-0.42189 0.046885-0.63282 0.89063-0.63281 2.5313v4.5938c1.0469-0.75781 1.5898-2.082 1.6289-3.9727 0.02342-1.0469-0.06251-1.8398-0.25781-2.3789-0.19532-0.54686-0.44142-0.80468-0.73828-0.77344" fill="url(#c)"/></g><path id="a" d="m210.56 70.719-200 16 200 16z" opacity=".99"/><use width="32" height="32" fill="#ff0000" stroke="#ff0000" xlink:href="#a"/><use transform="matrix(.98769 .15643 -.15643 .98769 13.696 -.58469)" width="32" height="32" fill="#ff2600" stroke="#ff2600" xlink:href="#a"/><use transform="matrix(.95106 .30902 -.30902 .95106 27.315 .98033)" width="32" height="32" fill="#ff4d00" stroke="#ff4d00" xlink:href="#a"/><use transform="matrix(.89101 .45399 -.45399 .89101 40.521 4.6565)" width="32" height="32" fill="#ff7300" stroke="#ff7300" xlink:href="#a"/><use transform="matrix(.80902 .58779 -.58779 .80902 52.989 10.353)" width="32" height="32" fill="#ff9900" stroke="#ff9900" xlink:href="#a"/><use transform="matrix(.70711 .70711 -.70711 .70711 64.413 17.931)" width="32" height="32" fill="#ffbf00" stroke="#ffbf00" xlink:href="#a"/><use transform="matrix(.58779 .80902 -.80902 .58779 74.511 27.202)" width="32" height="32" fill="#ffe600" stroke="#ffe600" xlink:href="#a"/><use transform="matrix(.45399 .89101 -.89101 .45399 83.034 37.938)" width="32" height="32" fill="#f2ff00" stroke="#f2ff00" xlink:href="#a"/><use transform="matrix(.30902 .95106 -.95106 .30902 89.773 49.876)" width="32" height="32" fill="#ccff00" stroke="#ccff00" xlink:href="#a"/><use transform="matrix(.15643 .98769 -.98769 .15643 94.561 62.72)" width="32" height="32" fill="#a6ff00" stroke="#a6ff00" xlink:href="#a"/><use transform="matrix(0,1,-1,0,97.281,76.156)" width="32" height="32" fill="#80ff00" stroke="#80ff00" xlink:href="#a"/><use transform="matrix(-.15643 .98769 -.98769 -.15643 97.866 89.852)" width="32" height="32" fill="#59ff00" stroke="#59ff00" xlink:href="#a"/><use transform="matrix(-.30902 .95106 -.95106 -.30902 96.301 103.47)" width="32" height="32" fill="#33ff00" stroke="#33ff00" xlink:href="#a"/><use transform="matrix(-.45399 .89101 -.89101 -.45399 92.625 116.68)" width="32" height="32" fill="#0dff00" stroke="#0dff00" xlink:href="#a"/><use transform="matrix(-.58779 .80902 -.80902 -.58779 86.928 129.15)" width="32" height="32" fill="#00ff19" stroke="#00ff19" xlink:href="#a"/><use transform="matrix(-.70711 .70711 -.70711 -.70711 79.351 140.57)" width="32" height="32" fill="#00ff40" stroke="#00ff40" xlink:href="#a"/><use transform="matrix(-.80902 .58779 -.58779 -.80902 70.08 150.67)" width="32" height="32" fill="#00ff66" stroke="#00ff66" xlink:href="#a"/><use transform="matrix(-.89101 .45399 -.45399 -.89101 59.343 159.19)" width="32" height="32" fill="#00ff8c" stroke="#00ff8c" xlink:href="#a"/><use transform="matrix(-.95106 .30902 -.30902 -.95106 47.406 165.93)" width="32" height="32" fill="#00ffb2" stroke="#00ffb2" xlink:href="#a"/><use transform="matrix(-.98769 .15643 -.15643 -.98769 34.561 170.72)" width="32" height="32" fill="#00ffd9" stroke="#00ffd9" xlink:href="#a"/><use transform="matrix(-1,0,0,-1,21.125,173.44)" width="32" height="32" fill="#00ffff" stroke="#00ffff" xlink:href="#a"/><use transform="matrix(-.98769 -.15643 .15643 -.98769 7.4292 174.02)" width="32" height="32" fill="#00d9ff" stroke="#00d9ff" xlink:href="#a"/><use transform="matrix(-.95106 -.30902 .30902 -.95106 -6.1895 172.46)" width="32" height="32" fill="#00b2ff" stroke="#00b2ff" xlink:href="#a"/><use transform="matrix(-.89101 -.45399 .45399 -.89101 -19.396 168.78)" width="32" height="32" fill="#008cff" stroke="#008cff" xlink:href="#a"/><use transform="matrix(-.80902 -.58779 .58779 -.80902 -31.864 163.08)" width="32" height="32" fill="#0066ff" stroke="#0066ff" xlink:href="#a"/><use transform="matrix(-.70711 -.70711 .70711 -.70711 -43.288 155.51)" width="32" height="32" fill="#0040ff" stroke="#0040ff" xlink:href="#a"/><use transform="matrix(-.58779 -.80902 .80902 -.58779 -53.386 146.24)" width="32" height="32" fill="#001aff" stroke="#001aff" xlink:href="#a"/><use transform="matrix(-.45399 -.89101 .89101 -.45399 -61.909 135.5)" width="32" height="32" fill="#0d00ff" stroke="#0d00ff" xlink:href="#a"/><use transform="matrix(-.30902 -.95106 .95106 -.30902 -68.648 123.56)" width="32" height="32" fill="#3300ff" stroke="#3300ff" xlink:href="#a"/><use transform="matrix(-.15643 -.98769 .98769 -.15643 -73.436 110.72)" width="32" height="32" fill="#5900ff" stroke="#5900ff" xlink:href="#a"/><use transform="matrix(0,-1,1,0,-76.156,97.281)" width="32" height="32" fill="#8000ff" stroke="#8000ff" xlink:href="#a"/><use transform="matrix(.15643 -.98769 .98769 .15643 -76.741 83.585)" width="32" height="32" fill="#a600ff" stroke="#a600ff" xlink:href="#a"/><use transform="matrix(.30902 -.95106 .95106 .30902 -75.176 69.967)" width="32" height="32" fill="#cc00ff" stroke="#cc00ff" xlink:href="#a"/><use transform="matrix(.45399 -.89101 .89101 .45399 -71.5 56.761)" width="32" height="32" fill="#f200ff" stroke="#f200ff" xlink:href="#a"/><use transform="matrix(.58779 -.80902 .80902 .58779 -65.803 44.292)" width="32" height="32" fill="#ff00e5" stroke="#ff00e5" xlink:href="#a"/><use transform="matrix(.70711 -.70711 .70711 .70711 -58.226 32.868)" width="32" height="32" fill="#ff00bf" stroke="#ff00bf" xlink:href="#a"/><use transform="matrix(.80902 -.58779 .58779 .80902 -48.955 22.77)" width="32" height="32" fill="#ff0099" stroke="#ff0099" xlink:href="#a"/><use transform="matrix(.89101 -.45399 .45399 .89101 -38.218 14.247)" width="32" height="32" fill="#ff0073" stroke="#ff0073" xlink:href="#a"/><use transform="matrix(.95106 -.30902 .30902 .95106 -26.281 7.5083)" width="32" height="32" fill="#ff004d" stroke="#ff004d" xlink:href="#a"/><use transform="matrix(.98769 -.15643 .15643 .98769 -13.436 2.72)" width="32" height="32" fill="#ff0026" stroke="#ff0026" xlink:href="#a"/></g><text x="0.49070829" y="48.29847" fill="#f7941e" font-family="Accanthis ADF Std" font-size="40px" letter-spacing="0px" word-spacing="0px" style="line-height:125%" xml:space="preserve"><tspan x="0.49070829" y="48.29847" fill="#f7941e" font-family="Sans" font-size="24px"/></text>
+<g transform="translate(8.7329 -5.8799)"><g transform="translate(-17.638 -.085622)" fill="#fff" stroke="#fff" stroke-width="1.5"><path d="m26.739 14.7c-0.50782 1.1e-5 -0.76173 0.56642-0.76172 1.6992v8.0391c0.74218 2e-6 1.4844-0.40625 2.2266-1.2188 0.66405-0.72656 0.99608-1.9609 0.99609-3.7031-1.2e-5 -1.625-0.33595-2.875-1.0078-3.75-0.54689-0.71093-1.0313-1.0664-1.4531-1.0664m0-1.8398c1.0937 1.3e-5 2.1367 0.51564 3.1289 1.5469 1.0703 1.1016 1.6055 2.8047 1.6055 5.1094-1.4e-5 2.1172-0.53517 3.8047-1.6055 5.0625-1.0078 1.1875-2.3047 1.7812-3.8906 1.7812v4.7109h-2.1445v-4.6992c-1.5547-1e-6 -2.8555-0.59766-3.9023-1.793-1.0625-1.2187-1.5938-2.9023-1.5938-5.0508-1e-6 -2.2344 0.53125-3.9219 1.5938-5.0625 0.79687-0.85155 1.8437-1.3867 3.1406-1.6055v1.9102c-0.51563 0.1797-1 0.57423-1.4531 1.1836-0.67188 0.89845-1.0078 2.0899-1.0078 3.5742-4e-6 1.5781 0.33593 2.8164 1.0078 3.7148 0.60156 0.80469 1.3398 1.207 2.2148 1.207v-8.0508c-7e-6 -2.3594 0.96874-3.539 2.9062-3.5391" fill="#fff" stroke="#fff" stroke-width="1.5"/></g><g transform="translate(-17.638 -.085622)"><path d="m26.739 14.7c-0.50782 1.1e-5 -0.76173 0.56642-0.76172 1.6992v8.0391c0.74218 2e-6 1.4844-0.40625 2.2266-1.2188 0.66405-0.72656 0.99608-1.9609 0.99609-3.7031-1.2e-5 -1.625-0.33595-2.875-1.0078-3.75-0.54689-0.71093-1.0313-1.0664-1.4531-1.0664m0-1.8398c1.0937 1.3e-5 2.1367 0.51564 3.1289 1.5469 1.0703 1.1016 1.6055 2.8047 1.6055 5.1094-1.4e-5 2.1172-0.53517 3.8047-1.6055 5.0625-1.0078 1.1875-2.3047 1.7812-3.8906 1.7812v4.7109h-2.1445v-4.6992c-1.5547-1e-6 -2.8555-0.59766-3.9023-1.793-1.0625-1.2187-1.5938-2.9023-1.5938-5.0508-1e-6 -2.2344 0.53125-3.9219 1.5938-5.0625 0.79687-0.85155 1.8437-1.3867 3.1406-1.6055v1.9102c-0.51563 0.1797-1 0.57423-1.4531 1.1836-0.67188 0.89845-1.0078 2.0899-1.0078 3.5742-4e-6 1.5781 0.33593 2.8164 1.0078 3.7148 0.60156 0.80469 1.3398 1.207 2.2148 1.207v-8.0508c-7e-6 -2.3594 0.96874-3.539 2.9062-3.5391"/></g></g></svg>
diff --git a/silx/resources/gui/icons/math-square-amplitude.png b/silx/resources/gui/icons/math-square-amplitude.png
new file mode 100644
index 0000000..2da16f2
--- /dev/null
+++ b/silx/resources/gui/icons/math-square-amplitude.png
Binary files differ
diff --git a/silx/resources/gui/icons/math-square-amplitude.svg b/silx/resources/gui/icons/math-square-amplitude.svg
new file mode 100644
index 0000000..7c18730
--- /dev/null
+++ b/silx/resources/gui/icons/math-square-amplitude.svg
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.1" viewBox="0 0 32 32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><text x="0.49070829" y="48.29847" fill="#f7941e" font-family="Accanthis ADF Std" font-size="40px" letter-spacing="0px" word-spacing="0px" style="line-height:125%" xml:space="preserve"><tspan x="0.49070829" y="48.29847" fill="#f7941e" font-family="Sans" font-size="24px"/></text>
+<g transform="translate(-1.0132 -.23022)"><g transform="translate(-.91624 -.18292)"><g transform="matrix(.82803 0 0 .82803 1.0566 4.3647)"><path d="m16 9.584-3.2109 8.707h6.4336l-3.2227-8.707m-1.3359-2.332h2.6836l6.668 17.496h-2.4609l-1.5938-4.4883h-7.8867l-1.5938 4.4883h-2.4961l6.6797-17.496"/></g><path d="m22.052 24.967v-14.708" fill="none" stroke="#000" stroke-width=".82803px"/><path d="m6.5581 24.967v-14.708" fill="none" stroke="#000" stroke-width=".82803px"/><g transform="translate(2)"><path d="m25.148 12.277h2.5664v1.1055h-4.2383v-1.1055l2.1289-1.8789c0.1901-0.17187 0.33073-0.33984 0.42188-0.50391 0.09114-0.16406 0.13672-0.33463 0.13672-0.51172-4e-6 -0.27343-0.09245-0.49349-0.27734-0.66016-0.1823-0.16666-0.42578-0.25-0.73047-0.25-0.23438 4.9e-6 -0.49089 0.050786-0.76953 0.15234-0.27865 0.098963-0.57682 0.2474-0.89453 0.44531v-1.2812c0.33854-0.11197 0.67318-0.19661 1.0039-0.25391 0.33073-0.05989 0.65494-0.089838 0.97266-0.089844 0.69791 5.9e-6 1.2396 0.15365 1.625 0.46094 0.38802 0.3073 0.58203 0.73568 0.58203 1.2852-5e-6 0.31771-0.08204 0.61459-0.24609 0.89063-0.16407 0.27344-0.50912 0.64063-1.0352 1.1016l-1.2461 1.0938"/></g></g></g></svg>
diff --git a/silx/resources/opencl/codec/byte_offset.cl b/silx/resources/opencl/codec/byte_offset.cl
new file mode 100644
index 0000000..56a24c4
--- /dev/null
+++ b/silx/resources/opencl/codec/byte_offset.cl
@@ -0,0 +1,235 @@
+/*
+ * Project: SILX: A data analysis tool-kit
+ *
+ * Copyright (C) 2017 European Synchrotron Radiation Facility
+ * Grenoble, France
+ *
+ * Principal authors: J. Kieffer (kieffer@esrf.fr)
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* To decompress CBF byte-offset compressed in parallel on GPU one needs to:
+ * - Set all values in mask and exception counter to zero.
+ * - Mark regions with exceptions and set values without exception.
+ * This generates the values (zeros for exceptions), the exception mask,
+ * counts the number of exception region and provides a start position for
+ * each exception.
+ * - Treat exceptions. For this, one thread in a workgoup treats a complete
+ * masked region in a serial fashion. All regions are treated in parallel.
+ * Values written at this stage are marked in the mask with -1.
+ * - Double scan: inclusive cum sum for values, exclusive cum sum to generate
+ * indices in output array. Values with mask = 1 are considered as 0.
+ * - Compact and copy output by removing duplicated values in exceptions.
+ */
+
+kernel void mark_exceptions(global char* raw,
+ int size,
+ int full_size,
+ global int* mask,
+ global int* values,
+ global int* cnt,
+ global int* exc)
+{
+ int gid;
+ gid = get_global_id(0);
+ if (gid<size)
+ {
+ int value, position;
+ value = raw[gid];
+ if (value == -128)
+ {
+ int maxi;
+ values[gid] = 0;
+ position = atomic_inc(cnt);
+ exc[position] = gid;
+ maxi = size - 1;
+ mask[gid] = 1;
+ mask[min(maxi, gid+1)] = 1;
+ mask[min(maxi, gid+2)] = 1;
+
+ if (((int) raw[min(gid+1, maxi)] == 0) &&
+ ((int) raw[min(gid+2, maxi)] == -128))
+ {
+ mask[min(maxi, gid+3)] = 1;
+ mask[min(maxi, gid+4)] = 1;
+ mask[min(maxi, gid+5)] = 1;
+ mask[min(maxi, gid+6)] = 1;
+ }
+ }
+ else
+ { // treat simple data
+
+ values[gid] = value;
+ }
+ }
+ else if (gid<full_size)
+ {
+ mask[gid]=1;
+ values[gid] = 0;
+ }
+}
+
+//run with WG=1, as may as exceptions
+kernel void treat_exceptions(global char* raw, //raw compressed stream
+ int size, //size of the raw compressed stream
+ global int* mask, //tells if the value is masked
+ global int* exc, //array storing the position of the start of exception zones
+ global int* values)// stores decompressed values.
+{
+ int gid = get_global_id(0);
+ int inp_pos = exc[gid];
+ if ((inp_pos<=0) || ((int)mask[inp_pos - 1] == 0))
+ {
+ int value, is_masked, next_value, inc;
+ is_masked = (mask[inp_pos] != 0);
+ while ((is_masked) && (inp_pos<size))
+ {
+ value = (int) raw[inp_pos];
+ if (value == -128)
+ { // this correspond to 16 bits exception
+ uchar low_byte = raw[inp_pos+1];
+ char high_byte = raw[inp_pos+2] ;
+ next_value = high_byte<<8 | low_byte;
+ if (next_value == -32768)
+ { // this correspond to 32 bits exception
+ uchar low_byte1 = raw[inp_pos+3],
+ low_byte2 = raw[inp_pos+4],
+ low_byte3 = raw[inp_pos+5];
+ char high_byte4 = raw[inp_pos+6] ;
+ value = high_byte4<<24 | low_byte3<<16 | low_byte2<<8 | low_byte1;
+ inc = 7;
+ }
+ else
+ {
+ value = next_value;
+ inc = 3;
+ }
+ }
+ else
+ {
+ inc = 1;
+ }
+ values[inp_pos] = value;
+ mask[inp_pos] = -1; // mark the processed data as valid in the mask
+ inp_pos += inc;
+ is_masked = (mask[inp_pos] != 0);
+ }
+ }
+}
+
+// copy the values of the elements to definitive position
+kernel void copy_result_int(global int* values,
+ global int* indexes,
+ int in_size,
+ int out_size,
+ global int* output
+ )
+{
+ int gid = get_global_id(0);
+ if (gid < in_size)
+ {
+ int current = max(indexes[gid], 0),
+ next = (gid >= (in_size - 1)) ? in_size + 1 : indexes[gid + 1];
+ //we keep always the last element
+ if ((current <= out_size) && (current < next))
+ {
+ output[current] = values[gid];
+ }
+ }
+}
+
+// copy the values of the elements to definitive position
+kernel void copy_result_float(global int* values,
+ global int* indexes,
+ int in_size,
+ int out_size,
+ global float* output
+ )
+{
+ int gid = get_global_id(0);
+ if (gid<in_size)
+ {
+ int current = max(indexes[gid], 0),
+ next = (gid >= (in_size - 1)) ? in_size + 1 : indexes[gid + 1];
+ if ((current < out_size) && (current < next))
+ {
+ output[current] = (float) values[gid];
+ }
+ }
+}
+
+
+// combined memset for all arrays used for Byte Offset decompression
+kernel void byte_offset_memset(global char* raw,
+ global int* mask,
+ global int* index,
+ global int* result,
+ int full_size,
+ int actual_size
+ )
+{
+ int gid = get_global_id(0);
+ if (gid < full_size)
+ {
+ raw[gid] = 0;
+ index[gid] = 0;
+ result[gid] = 0;
+ if (gid<actual_size)
+ {
+ mask[gid] = 0;
+ }
+ else
+ {
+ mask[gid] = 1;
+ }
+
+ }
+}
+
+
+//Simple memset kernel for char arrays
+kernel void fill_char_mem(global char* ary,
+ int size,
+ char pattern,
+ int start_at)
+{
+ int gid = get_global_id(0);
+ if ((gid >= start_at) && (gid < size))
+ {
+ ary[gid] = pattern;
+ }
+}
+
+//Simple memset kernel for int arrays
+kernel void fill_int_mem(global int* ary,
+ int size,
+ int pattern,
+ int start_at)
+{
+ int gid = get_global_id(0);
+ if ((gid >= start_at) && (gid < size))
+ {
+ ary[gid] = pattern;
+ }
+}
+
diff --git a/silx/resources/opencl/image/cast.cl b/silx/resources/opencl/image/cast.cl
new file mode 100644
index 0000000..9e23a82
--- /dev/null
+++ b/silx/resources/opencl/image/cast.cl
@@ -0,0 +1,181 @@
+/*
+ * Project: SILX: Alogorithms for image processing
+ *
+ * Copyright (C) 2013-2017 European Synchrotron Radiation Facility
+ * Grenoble, France
+ *
+ * Principal authors: J. Kieffer (kieffer@esrf.fr)
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef NB_COLOR
+ #define NB_COLOR 1
+#endif
+
+
+/**
+ * \brief Cast values of an array of uint8 into a float output array.
+ *
+ * :param array_input: Pointer to global memory with the input data as unsigned8 array
+ * :param array_float: Pointer to global memory with the output data as float array
+ * :param width: Width of the image
+ * :param height: Height of the image
+ */
+kernel void u8_to_float( global unsigned char *array_input,
+ global float *array_float,
+ const int width,
+ const int height)
+{
+ //Global memory guard for padding
+ if ((get_global_id(0) < width) && (get_global_id(1)<height))
+ {
+ int i = NB_COLOR * (get_global_id(0) + width * get_global_id(1));
+ for (int c=0; c<NB_COLOR; c++)
+ {
+ array_float[i + c] = (float) array_input[i + c];
+ } //end loop over colors
+ } //end test in image
+} //end kernel
+
+/**
+ * \brief Cast values of an array of uint8 into a float output array.
+ *
+ * :param array_input: Pointer to global memory with the input data as signed8 array
+ * :param array_float: Pointer to global memory with the output data as float array
+ * :param width: Width of the image
+ * :param height: Height of the image
+ */
+kernel void s8_to_float( global char *array_input,
+ global float *array_float,
+ const int width,
+ const int height)
+{
+ //Global memory guard for padding
+ if ((get_global_id(0) < width) && (get_global_id(1)<height))
+ {
+ int i = NB_COLOR * (get_global_id(0) + width * get_global_id(1));
+ for (int c=0; c<NB_COLOR; c++)
+ {
+ array_float[i + c] = (float) array_input[i + c];
+ } //end loop over colors
+ } //end test in image
+} //end kernel
+
+
+/**
+ * \brief cast values of an array of uint16 into a float output array.
+ *
+ * :param array_input: Pointer to global memory with the input data as unsigned16 array
+ * :param array_float: Pointer to global memory with the output data as float array
+ * :param width: Width of the image
+ * :param height: Height of the image
+ */
+kernel void u16_to_float(global unsigned short *array_input,
+ global float *array_float,
+ const int width,
+ const int height)
+{
+ //Global memory guard for padding
+ if ((get_global_id(0) < width) && (get_global_id(1)<height))
+ {
+ int i = NB_COLOR * (get_global_id(0) + width * get_global_id(1));
+ for (int c=0; c<NB_COLOR; c++)
+ {
+ array_float[i + c] = (float) array_input[i + c];
+ } //end loop over colors
+ } //end test in image
+} //end kernel
+
+/**
+ * \brief cast values of an array of int16 into a float output array.
+ *
+ * :param array_input: Pointer to global memory with the input data as signed16 array
+ * :param array_float: Pointer to global memory with the output data as float array
+ * :param width: Width of the image
+ * :param height: Height of the image
+ */
+kernel void s16_to_float(global short *array_input,
+ global float *array_float,
+ const int width,
+ const int height)
+{
+ //Global memory guard for padding
+ if ((get_global_id(0) < width) && (get_global_id(1)<height))
+ {
+ int i = NB_COLOR * (get_global_id(0) + width * get_global_id(1));
+ for (int c=0; c<NB_COLOR; c++)
+ {
+ array_float[i + c] = (float) array_input[i + c];
+ } //end loop over colors
+ } //end test in image
+}//end kernel
+
+/**
+ * \brief cast values of an array of uint32 into a float output array.
+ *
+ * :param array_input: Pointer to global memory with the input data as unsigned32 array
+ * :param array_float: Pointer to global memory with the output data as float array
+ * :param width: Width of the image
+ * :param height: Height of the image
+ */
+kernel void u32_to_float(global unsigned int *array_input,
+ global float *array_float,
+ const int width,
+ const int height)
+{
+ //Global memory guard for padding
+ if ((get_global_id(0) < width) && (get_global_id(1)<height))
+ {
+ int i = NB_COLOR * (get_global_id(0) + width * get_global_id(1));
+ for (int c=0; c<NB_COLOR; c++)
+ {
+ array_float[i + c] = (float) array_input[i + c];
+ } //end loop over colors
+ } //end test in image
+}//end kernel
+
+
+/**
+ * \brief convert values of an array of int32 into a float output array.
+ *
+ * :param array_input: Pointer to global memory with the data in int
+ * :param array_float: Pointer to global memory with the data in float
+ * :param width: Width of the image
+ * :param height: Height of the image
+ */
+kernel void s32_to_float(global int *array_input,
+ global float *array_float,
+ const int width,
+ const int height)
+{
+ //Global memory guard for padding
+ if ((get_global_id(0) < width) && (get_global_id(1)<height))
+ {
+ int i = NB_COLOR * (get_global_id(0) + width * get_global_id(1));
+ for (int c=0; c<NB_COLOR; c++)
+ {
+ array_float[i + c] = (float) array_input[i + c];
+ } //end loop over colors
+ } //end test in image
+}//end kernel
+
diff --git a/silx/resources/opencl/image/histogram.cl b/silx/resources/opencl/image/histogram.cl
new file mode 100644
index 0000000..7fb1485
--- /dev/null
+++ b/silx/resources/opencl/image/histogram.cl
@@ -0,0 +1,178 @@
+//CL//
+
+/*
+ * Project: SILX: Alogorithms for image processing
+ *
+ * Copyright (C) 2013-2018 European Synchrotron Radiation Facility
+ * Grenoble, France
+ *
+ * Principal authors: J. Kieffer (kieffer@esrf.fr)
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* Single kernel histogram for float array.
+ *
+ * Can perform histograming in log-scale (using the arcsinh)
+
+Parameters:
+ - data: buffer with the image content in float (input)
+ - data_size: input
+ - mini: Lower bound of the first bin
+ - maxi: upper bouns of the last bin
+ - map_operation: Type of pre-processor to use. if if set to !=0, use log scale
+ - hist: resulting histogram (ouptut)
+ - hist_size: number of bins
+ - tmp_hist: temporary storage of size hist_size*num_groups
+ - processed: temporary storage of size 1 initialially set to 0
+ - local_hist: local storage of size hist_size
+
+
+Grid information:
+ * use the largest WG size. If it is larger than the number of bins (hist_size),
+ take the power of 2 immediately above
+ *Schedule as many WG as the device has compute engines. No need to schuedule more,
+ it is just a waist of memory
+ * The histogram should fit in shared (local) memory and tmp_hist can be large!
+
+Assumes:
+ hist and local_hist have size hist_size
+ edges has size hist_size+2
+ tmp_hist has size hist_size*num_groups
+ processed is of size one and initially set to 0
+
+*/
+
+
+static float preprocess(float value, int code)
+{
+ //This function can be modified to have more scales
+ if (code!=0)
+ {
+ return asinh(value);
+ }
+ else
+ {
+ return value;
+ }
+}
+
+kernel void histogram(global float *data,
+ int data_size,
+ float mini,
+ float maxi,
+ int map_operation,
+ global int *hist,
+ global float *edges,
+ int hist_size,
+ global int *tmp_hist,
+ global int *processed,
+ local int *local_hist)
+{
+ // each thread
+ int lid = get_local_id(0);
+ int ws = get_local_size(0);
+ int nb_engine = get_num_groups(0);
+ int engine_id = get_group_id(0);
+
+ // memset the local_hist array
+ for (int i=0; i<hist_size; i+=ws)
+ {
+ int j = i + lid;
+ if (j<hist_size)
+ {
+ local_hist[j] = 0;
+ }
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ // Process the local data and accumulate in shared memory
+ int bloc_size = (int) ceil((float)data_size/(float)nb_engine);
+ int start = bloc_size * engine_id;
+ int stop = min(start + bloc_size, data_size);
+ float vmini = preprocess(mini, map_operation);
+ float vscale = (float)hist_size/(preprocess(maxi, map_operation) -vmini);
+ for (int i = start; i<stop; i+=ws)
+ {
+ int address = i + lid;
+ if (address < stop)
+ {
+ float value = data[address];
+ if ((!isnan(value)) && (value>=mini) && (value<=maxi))
+ {
+ float vvalue = (preprocess(value, map_operation)-vmini)*vscale;
+ int idx = clamp((int) vvalue, 0, hist_size - 1);
+ atomic_inc(&local_hist[idx]);
+ }
+ }
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ //Now copy result into the right place and reset the first value of the shared array
+ for (int i=0; i<hist_size; i+=ws)
+ {
+ int j = i + lid;
+ if (j<hist_size)
+ {
+ tmp_hist[hist_size * engine_id + j] = local_hist[j];
+ }
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ local_hist[0] = 0;
+
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ //Increment the system wide shared variable processed and share the result with the workgroup
+ if (lid == 0)
+ {
+ local_hist[0] = atomic_inc(processed);
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ // If we are the engine last to work, perform the concatenation of all results
+
+ if ((local_hist[0] + 1) == nb_engine)
+ {
+ for (int i=0; i<hist_size; i+=ws)
+ {
+ int j = i + lid;
+ int lsum = 0;
+ if (j<hist_size)
+ {
+ for (int k=0; k<nb_engine; k++)
+ {
+ lsum += tmp_hist[hist_size * k + j];
+ }
+ hist[j] = lsum;
+ edges[j] = vmini + j/vscale;
+ }
+ }
+ // Finally reset the counter
+ if (lid == 0)
+ {
+ processed[0] = 0;
+ edges[hist_size] = vmini + hist_size/vscale;;
+ }
+
+ }
+}
diff --git a/silx/resources/opencl/image/map.cl b/silx/resources/opencl/image/map.cl
new file mode 100644
index 0000000..804a5a1
--- /dev/null
+++ b/silx/resources/opencl/image/map.cl
@@ -0,0 +1,85 @@
+/*
+ * Project: SILX: Data analysis library
+ * kernel for maximum and minimum calculation
+ *
+ *
+ * Copyright (C) 2013-2017 European Synchrotron Radiation Facility
+ * Grenoble, France
+ *
+ * Principal authors: J. Kieffer (kieffer@esrf.fr)
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ */
+
+#ifndef NB_COLOR
+ #define NB_COLOR 1
+#endif
+
+
+/**
+ * \brief Linear scale of signal in an image (maybe multi-color)
+ *
+ * :param image: contains the input image
+ * :param output: contains the output image after scaling
+ * :param max_min_input: 2-floats containing the maximum and the minimum value of image
+ * :param minimum: float scalar with the minimum of the output
+ * :param maximum: float scalar with the maximum of the output
+ * :param width: integer, number of columns the matrices
+ * :param height: integer, number of lines of the matrices
+ *
+ *
+ */
+
+
+kernel void normalize_image(global float* image,
+ global float* output,
+ int width,
+ int height,
+ global float* max_min_input,
+ float minimum,
+ float maximum
+ )
+{
+ //Global memory guard for padding
+ if((get_global_id(0) < width) && (get_global_id(1)<height))
+ {
+ int idx = NB_COLOR* (get_global_id(0) + width * get_global_id(1));
+ float mini_in, maxi_in, scale;
+ maxi_in = max_min_input[0];
+ mini_in = max_min_input[1];
+ if (maxi_in == mini_in)
+ {
+ scale = NAN;
+ }
+ else
+ {
+ scale = (maximum - minimum) / (maxi_in - mini_in);
+ }
+
+ for (int c=0; c<NB_COLOR; c++)
+ {
+ output[idx+c] = fma(scale, image[idx+c]-mini_in, minimum);
+ } // end color loop
+ }//end if in IMAGE
+}//end kernel
diff --git a/silx/resources/opencl/image/max_min.cl b/silx/resources/opencl/image/max_min.cl
new file mode 100644
index 0000000..246cd48
--- /dev/null
+++ b/silx/resources/opencl/image/max_min.cl
@@ -0,0 +1,207 @@
+/*
+ * Project: SILX: Data analysis library
+ * kernel for maximum and minimum calculation
+ *
+ *
+ * Copyright (C) 2013-2017 European Synchrotron Radiation Facility
+ * Grenoble, France
+ *
+ * Principal authors: J. Kieffer (kieffer@esrf.fr)
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ */
+
+#ifndef NB_COLOR
+ #define NB_COLOR 1
+#endif
+
+
+
+#define REDUCE(a, b) ((float2) (fmax(a.x, b.x), fmin(a.y, b.y)))
+
+static float2 read_and_map(int idx,
+ global float* data)
+{
+ idx *= NB_COLOR;
+ float tmp = data[idx];
+ float2 res = (float2) (tmp, tmp);
+ if (NB_COLOR > 1)
+ {
+ for (int c=1; c<NB_COLOR; c++)
+ {
+ tmp = data[idx + c];
+ res = (float2) (fmax(res.x, tmp), fmin(res.y, tmp));
+ }
+ }
+ return res;
+}
+
+
+/**
+ * \brief max_min_global_stage1: Look for the maximum an the minimum of an array. stage1
+ *
+ * optimal workgroup size: 2^n greater than sqrt(size), limited to 512
+ * optimal total item size: (workgroup size)^2
+ * if size >total item size: adjust seq_count.
+ *
+ * :param data: Float pointer to global memory storing the vector of data.
+ * :param out: Float2 pointer to global memory storing the temporary results (workgroup size)
+ * :param seq_count: how many blocksize each thread should read
+ * :param size: size of the problem (number of element in the image
+ * :param l_data Shared memory: 2 float per thread in workgroup
+ *
+**/
+
+
+kernel void max_min_reduction_stage1( global const float *data,
+ global float2 *out,
+ int size,
+ local float2 *l_data)// local storage 2 float per thread
+{
+ int group_size = get_local_size(0);
+ int lid = get_local_id(0);
+ float2 acc;
+ int big_block = group_size * get_num_groups(0);
+ int i = lid + group_size * get_group_id(0);
+
+ if (lid<size)
+ acc = read_and_map(lid, data);
+ else
+ acc = read_and_map(0, data);
+
+ // Linear pre-reduction stage 0
+
+ while (i<size){
+ acc = REDUCE(acc, read_and_map(i, data));
+ i += big_block;
+ }
+
+ // parallel reduction stage 1
+
+ l_data[lid] = acc;
+ barrier(CLK_LOCAL_MEM_FENCE);
+ for (int block=group_size/2; block>1; block/=2)
+ {
+ if ((lid < block) && ((lid + block)<group_size)){
+ l_data[lid] = REDUCE(l_data[lid], l_data[lid + block]);
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+ }
+ if (lid == 0)
+ {
+ if (group_size > 1)
+ {
+ acc = REDUCE(l_data[0], l_data[1]);
+ }
+ else
+ {
+ acc = l_data[0];
+ }
+ out[get_group_id(0)] = acc;
+ }
+}
+
+
+/**
+ * \brief global_max_min: Look for the maximum an the minimum of an array.
+ *
+ *
+ *
+ * :param data2: Float2 pointer to global memory storing the vector of pre-reduced data (workgroup size).
+ * :param maximum: Float pointer to global memory storing the maximum value
+ * :param minumum: Float pointer to global memory storing the minimum value
+ * :param l_data Shared memory: 2 float per thread in workgroup
+ *
+**/
+
+kernel void max_min_reduction_stage2(
+ global const float2 *data2,
+ global float2 *maxmin,
+ local float2 *l_data)// local storage 2 float per thread
+{
+ int lid = get_local_id(0);
+ int group_size = get_local_size(0);
+ float2 acc = (float2)(-1.0f, -1.0f);
+ if (lid<=group_size)
+ {
+ l_data[lid] = data2[lid];
+ }
+ else
+ {
+ l_data[lid] = acc;
+ }
+
+ // parallel reduction stage 2
+
+
+ barrier(CLK_LOCAL_MEM_FENCE);
+ for (int block=group_size/2; block>1; block/=2)
+ {
+ if ((lid < block) && ((lid + block)<group_size))
+ {
+ l_data[lid] = REDUCE(l_data[lid], l_data[lid + block]);
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ }
+
+ if (lid == 0 )
+ {
+ if ( group_size > 1)
+ {
+ acc = REDUCE(l_data[0], l_data[1]);
+ }
+ else
+ {
+ acc = l_data[0];
+ }
+ maxmin[0] = acc;
+ }
+}
+
+/*This is the serial version of the min_max kernel.
+ *
+ * It has to be launched with WG=1 and only 1 WG has to be launched !
+ *
+ * :param data: Float pointer to global memory storing the vector of data.
+ * :param size: size of the
+ * :param maximum: Float pointer to global memory storing the maximum value
+ * :param minumum: Float pointer to global memory storing the minimum value
+ *
+ *
+ */
+kernel void max_min_serial(
+ global const float *data,
+ unsigned int size,
+ global float2 *maxmin
+ )
+{
+ float2 acc = read_and_map(0, data);
+ for (int i=1; i<size; i++)
+ {
+ acc = REDUCE(acc, read_and_map(i, data));
+ }
+
+ maxmin[0] = acc;
+}
diff --git a/silx/sx/__init__.py b/silx/sx/__init__.py
index 87bfb9e..bdec6e6 100644
--- a/silx/sx/__init__.py
+++ b/silx/sx/__init__.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -22,31 +22,35 @@
# THE SOFTWARE.
#
# ###########################################################################*/
-"""Convenient module to use main features of silx from the console.
-
-Usage from (I)Python console or notebook:
+"""This is a convenient package to use from Python or IPython interpreter.
+It loads the main features of silx and provides high-level functions.
>>> from silx import sx
-With IPython/jupyter, this also runs %pylab.
-From the console, it sets-up Qt in order to allow using GUI widgets.
+When used in an interpreter is sets-up Qt and loads some silx widgets.
+When used in a `jupyter <https://jupyter.org/>`_ /
+`IPython <https://ipython.org/>`_ notebook, neither Qt nor silx widgets are loaded.
+
+When used in `IPython <https://ipython.org/>`_, it also runs ``%pylab``,
+thus importing `numpy <http://www.numpy.org/>`_ and `matplotlib <https://matplotlib.org/>`_.
"""
+
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "16/01/2017"
-import logging
+import logging as _logging
import sys as _sys
-_logger = logging.getLogger(__name__)
+_logger = _logging.getLogger(__name__)
# Init logging when used from the console
if hasattr(_sys, 'ps1'):
- logging.basicConfig()
+ _logging.basicConfig()
# Probe ipython
try:
@@ -81,12 +85,22 @@ else:
del _icons # clean-up namespace
from silx.gui.plot import * # noqa
- from ._plot import plot, imshow # noqa
+ from ._plot import plot, imshow, ginput # noqa
+
+ try:
+ import OpenGL as _OpenGL
+ except ImportError:
+ _logger.warning(
+ 'Not loading silx.gui.plot3d features: PyOpenGL is not installed')
+ else:
+ del _OpenGL # clean-up namespace
+ from ._plot3d import contour3d, points3d # noqa
# %pylab
if _get_ipython is not None and _get_ipython() is not None:
- _get_ipython().enable_pylab(gui='inline' if _IS_NOTEBOOK else 'qt')
+ _get_ipython().enable_pylab(gui='inline' if _IS_NOTEBOOK else 'qt',
+ import_all=False)
# Clean-up
@@ -96,7 +110,7 @@ del _IS_NOTEBOOK
# Load some silx stuff in namespace
-from silx import * # noqa
+from silx import version # noqa
from silx.io import open # noqa
from silx.io import * # noqa
from silx.math import Histogramnd, HistogramndLut # noqa
diff --git a/silx/sx/_plot.py b/silx/sx/_plot.py
index e81e57e..dfc24d9 100644
--- a/silx/sx/_plot.py
+++ b/silx/sx/_plot.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -27,13 +27,19 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "27/06/2017"
+__date__ = "26/02/2018"
+import collections
import logging
+import time
+import weakref
+
import numpy
-from ..gui.plot import Plot1D, Plot2D
+from ..utils.weakref import WeakList
+from ..gui import qt
+from ..gui.plot import Plot1D, Plot2D, PlotWidget
from ..gui.plot.Colors import COLORDICT
from ..gui.plot.Colormap import Colormap
from silx.third_party import six
@@ -41,19 +47,15 @@ from silx.third_party import six
_logger = logging.getLogger(__name__)
+_plots = WeakList()
+"""List of widgets created through plot and imshow"""
+
def plot(*args, **kwargs):
"""
- Plot curves in a dedicated widget.
-
- This function supports a subset of matplotlib.pyplot.plot arguments.
- See: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot
-
- It opens a silx PlotWindow with its associated tools.
+ Plot curves in a :class:`~silx.gui.plot.PlotWindow.Plot1D` widget.
- Examples:
-
- First import :mod:`sx` function:
+ How to use:
>>> from silx import sx
>>> import numpy
@@ -67,8 +69,7 @@ def plot(*args, **kwargs):
>>> angles = numpy.linspace(0, numpy.pi, 100)
>>> sin_a = numpy.sin(angles)
- >>> plot_sinus = sx.plot(angles, sin_a,
- ... xlabel='angle (radian)', ylabel='sin(a)')
+ >>> plot_sinus = sx.plot(angles, sin_a, xlabel='angle (radian)', ylabel='sin(a)')
Plot many curves by giving a 2D array, provided xn, yn arrays:
@@ -96,13 +97,13 @@ def plot(*args, **kwargs):
- '-.' dash-dot line
- ':' dotted line
- Remark: The first curve will always be displayed in black no matter the
- given color. This is because it is selected by default and this is shown
- by using the black color.
-
If provided, the names arguments color, linestyle, linewidth and marker
override any style provided to a curve.
+ This function supports a subset of `matplotlib.pyplot.plot
+ <http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot>`_
+ arguments.
+
:param str color: Color to use for all curves (default: None)
:param str linestyle: Type of line to use for all curves (default: None)
:param float linewidth: With of all the curves (default: 1)
@@ -194,6 +195,7 @@ def plot(*args, **kwargs):
color=color or curve_color)
plt.show()
+ _plots.insert(0, plt)
return plt
@@ -202,14 +204,10 @@ def imshow(data=None, cmap=None, norm=Colormap.LINEAR,
aspect=False,
origin=(0., 0.), scale=(1., 1.),
title='', xlabel='X', ylabel='Y'):
- """Plot an image in a dedicated widget.
-
- This function supports a subset of matplotlib.pyplot.imshow arguments.
- See: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.imshow
-
- It opens a silx PlotWindow with its associated tools.
+ """
+ Plot an image in a :class:`~silx.gui.plot.PlotWindow.Plot2D` widget.
- Example to plot an image:
+ How to use:
>>> from silx import sx
>>> import numpy
@@ -217,6 +215,10 @@ def imshow(data=None, cmap=None, norm=Colormap.LINEAR,
>>> data = numpy.random.random(1024 * 1024).reshape(1024, 1024)
>>> plt = sx.imshow(data, title='Random data')
+ This function supports a subset of `matplotlib.pyplot.imshow
+ <http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.imshow>`_
+ arguments.
+
:param data: data to plot as an image
:type data: numpy.ndarray-like with 2 dimensions
:param str cmap: The name of the colormap to use for the plot.
@@ -268,4 +270,290 @@ def imshow(data=None, cmap=None, norm=Colormap.LINEAR,
plt.addImage(data, origin=origin, scale=scale)
plt.show()
+ _plots.insert(0, plt)
return plt
+
+
+class _GInputResult(tuple):
+ """Object storing :func:`ginput` result
+
+ :param position: Selected point coordinates in the plot (x, y)
+ :param Item item: Plot item under the selected position
+ :param indices: Selected indices in the data of the item.
+ For a curve it is a list of indices, for an image it is (row, column)
+ :param data: Value of data at selected indices.
+ For a curve it is an array of values, for an image it is a single value
+ """
+
+ def __new__(cls, position, item, indices, data):
+ return super(_GInputResult, cls).__new__(cls, position)
+
+ def __init__(self, position, item, indices, data):
+ self._itemRef = weakref.ref(item) if item is not None else None
+ self._indices = numpy.array(indices, copy=True)
+ if isinstance(data, collections.Iterable):
+ self._data = numpy.array(data, copy=True)
+ else:
+ self._data = data
+
+ def getItem(self):
+ """Returns the item at the selected position if any.
+
+ :return: plot item under the selected postion.
+ It is None if there was no item at that position or if
+ it is no more in the plot.
+ :rtype: silx.gui.plot.items.Item"""
+ return None if self._itemRef is None else self._itemRef()
+
+ def getIndices(self):
+ """Returns indices in data array at the select position
+
+ :return: 1D array of indices for curve and (row, column) for images
+ :rtype: numpy.ndarray
+ """
+ return numpy.array(self._indices, copy=True)
+
+ def getData(self):
+ """Returns data value at the selected position.
+
+ For curves, an array of (x, y) values close to the point is returned.
+ For images, either a single value or a RGB(A) array is returned.
+
+ :return: 2D array of (x, y) data values for curves (Nx2),
+ a single value for data images and RGB(A) array for images.
+ """
+ if isinstance(self._data, numpy.ndarray):
+ return numpy.array(self._data, copy=True)
+ else:
+ return self._data
+
+
+class _GInputHandler(qt.QEventLoop):
+ """Implements :func:`ginput`
+
+ :param PlotWidget plot:
+ :param int n:
+ :param float timeout:
+ """
+
+ def __init__(self, plot, n, timeout):
+ super(_GInputHandler, self).__init__()
+
+ if not isinstance(plot, PlotWidget):
+ raise ValueError('plot is not a PlotWidget: %s', plot)
+
+ self._plot = plot
+ self._timeout = timeout
+ self._markersAndResult = []
+ self._totalPoints = n
+ self._endTime = 0.
+
+ def eventFilter(self, obj, event):
+ """Event filter for plot hide event"""
+ if event.type() == qt.QEvent.Hide:
+ self.quit()
+
+ elif event.type() == qt.QEvent.KeyPress:
+ if event.key() in (qt.Qt.Key_Delete, qt.Qt.Key_Backspace) or (
+ event.key() == qt.Qt.Key_Z and event.modifiers() & qt.Qt.ControlModifier):
+ if len(self._markersAndResult) > 0:
+ legend, _ = self._markersAndResult.pop()
+ self._plot.remove(legend=legend, kind='marker')
+
+ self._updateStatusBar()
+ return True # Stop further handling of those keys
+
+ elif event.key() == qt.Qt.Key_Return:
+ self.quit()
+ return True # Stop further handling of those keys
+
+ return super(_GInputHandler, self).eventFilter(obj, event)
+
+ def exec_(self):
+ """Run blocking ginput handler
+
+ :returns: List of selected points
+ """
+ # Bootstrap
+ self._plot.setInteractiveMode(mode='zoom')
+ self._handleInteractiveModeChanged(None)
+ self._plot.sigInteractiveModeChanged.connect(
+ self._handleInteractiveModeChanged)
+
+ self._plot.installEventFilter(self)
+
+ # Run
+ if self._timeout:
+ timeoutTimer = qt.QTimer()
+ timeoutTimer.timeout.connect(self._updateStatusBar)
+ timeoutTimer.start(1000)
+
+ self._endTime = time.time() + self._timeout
+ self._updateStatusBar()
+
+ returnCode = super(_GInputHandler, self).exec_()
+
+ timeoutTimer.stop()
+ else:
+ returnCode = super(_GInputHandler, self).exec_()
+
+ # Clean-up
+ self._plot.removeEventFilter(self)
+
+ self._plot.sigInteractiveModeChanged.disconnect(
+ self._handleInteractiveModeChanged)
+
+ currentMode = self._plot.getInteractiveMode()
+ if currentMode['mode'] == 'zoom': # Stop handling mouse click
+ self._plot.sigPlotSignal.disconnect(self._handleSelect)
+
+ self._plot.statusBar().clearMessage()
+
+ points = tuple(result for _, result in self._markersAndResult)
+
+ for legend, _ in self._markersAndResult:
+ self._plot.remove(legend=legend, kind='marker')
+ self._markersAndResult = []
+
+ return points if returnCode == 0 else ()
+
+ def _updateStatusBar(self):
+ """Update status bar message"""
+ msg = 'ginput: %d/%d input points' % (len(self._markersAndResult),
+ self._totalPoints)
+ if self._timeout:
+ remaining = self._endTime - time.time()
+ if remaining < 0:
+ self.quit()
+ return
+ msg += ', %d seconds remaining' % max(1, int(remaining))
+
+ currentMode = self._plot.getInteractiveMode()
+ if currentMode['mode'] != 'zoom':
+ msg += ' (Use zoom mode to add/remove points)'
+
+ self._plot.statusBar().showMessage(msg)
+
+ def _handleSelect(self, event):
+ """Handle mouse events"""
+ if event['event'] == 'mouseClicked' and event['button'] == 'left':
+ x, y = event['x'], event['y']
+ xPixel, yPixel = event['xpixel'], event['ypixel']
+
+ # Add marker
+ legend = "sx.ginput %d" % len(self._markersAndResult)
+ self._plot.addMarker(
+ x, y,
+ legend=legend,
+ text='%d' % len(self._markersAndResult),
+ color='red',
+ draggable=False)
+
+ # Pick item at selected position
+ picked = self._plot._pickImageOrCurve(xPixel, yPixel)
+
+ if picked is None:
+ result = _GInputResult((x, y),
+ item=None,
+ indices=numpy.array((), dtype=int),
+ data=None)
+
+ elif picked[0] == 'curve':
+ curve = picked[1]
+ indices = picked[2]
+ xData = curve.getXData(copy=False)[indices]
+ yData = curve.getYData(copy=False)[indices]
+ result = _GInputResult((x, y),
+ item=curve,
+ indices=indices,
+ data=numpy.array((xData, yData)).T)
+
+ elif picked[0] == 'image':
+ image = picked[1]
+ # Get corresponding coordinate in image
+ origin = image.getOrigin()
+ scale = image.getScale()
+ column = int((x - origin[0]) / float(scale[0]))
+ row = int((y - origin[1]) / float(scale[1]))
+ data = image.getData(copy=False)[row, column]
+ result = _GInputResult((x, y),
+ item=image,
+ indices=(row, column),
+ data=data)
+
+ self._markersAndResult.append((legend, result))
+ self._updateStatusBar()
+ if len(self._markersAndResult) == self._totalPoints:
+ self.quit()
+
+ def _handleInteractiveModeChanged(self, source):
+ """Handle change of interactive mode in the plot
+
+ :param source: Objects that triggered the mode change
+ """
+ mode = self._plot.getInteractiveMode()
+ if mode['mode'] == 'zoom': # Handle click events
+ self._plot.sigPlotSignal.connect(self._handleSelect)
+ else: # Do not handle click event
+ self._plot.sigPlotSignal.disconnect(self._handleSelect)
+ self._updateStatusBar()
+
+
+def ginput(n=1, timeout=30, plot=None):
+ """Get input points on a plot.
+
+ If no plot is provided, it uses a plot widget created with
+ either :func:`silx.sx.plot` or :func:`silx.sx.imshow`.
+
+ How to use:
+
+ >>> from silx import sx
+
+ >>> sx.imshow(image) # Plot the image
+ >>> sx.ginput(1) # Request selection on the image plot
+ ((0.598, 1.234))
+
+ How to get more information about the selected positions:
+
+ >>> positions = sx.ginput(1)
+
+ >>> positions[0].getData() # Returns value(s) at selected position
+
+ >>> positions[0].getIndices() # Returns data indices at selected position
+
+ >>> positions[0].getItem() # Returns plot item at selected position
+
+ :param int n: Number of points the user need to select
+ :param float timeout: Timeout in seconds before ginput returns
+ event if selection is not completed
+ :param silx.gui.plot.PlotWidget.PlotWidget plot: An optional PlotWidget
+ from which to get input
+ :return: List of clicked points coordinates (x, y) in plot
+ :raise ValueError: If provided plot is not a PlotWidget
+ """
+ if plot is None:
+ # Select most recent visible plot widget
+ for widget in _plots:
+ if widget.isVisible():
+ plot = widget
+ break
+ else: # If no plot widgets are visible, take most recent one
+ try:
+ plot = _plots[0]
+ except IndexError:
+ pass
+ else:
+ plot.show()
+
+ if plot is None:
+ _logger.warning('No plot available to perform ginput, create one')
+ plot = Plot1D()
+ plot.show()
+
+ plot.raise_() # So window becomes the top level one
+
+ _logger.info('Performing ginput with plot widget %s', str(plot))
+ handler = _GInputHandler(plot, n, timeout)
+ points = handler.exec_()
+
+ return points
diff --git a/silx/sx/_plot3d.py b/silx/sx/_plot3d.py
new file mode 100644
index 0000000..3e67fe0
--- /dev/null
+++ b/silx/sx/_plot3d.py
@@ -0,0 +1,246 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module adds convenient functions to use plot3d widgets from the console.
+"""
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "07/02/2018"
+
+
+from collections import Iterable
+import logging
+import numpy
+
+from ..gui import qt
+from ..gui.plot3d.SceneWindow import SceneWindow
+from ..gui.plot3d.ScalarFieldView import ScalarFieldView
+from ..gui.plot3d import SFViewParamTree
+from ..gui.plot.Colormap import Colormap
+from ..gui.plot.Colors import rgba
+
+
+_logger = logging.getLogger(__name__)
+
+
+def contour3d(scalars,
+ contours=1,
+ copy=True,
+ color=None,
+ colormap='viridis',
+ vmin=None,
+ vmax=None,
+ opacity=1.):
+ """
+ Plot isosurfaces of a 3D scalar field in a :class:`~silx.gui.plot3d.ScalarFieldView.ScalarFieldView` widget.
+
+ How to use:
+
+ >>> from silx import sx
+
+ Provided data, a 3D scalar field as a numpy array of float32:
+
+ >>> plot3d_window = sx.contour3d(data)
+
+ Alternatively you can provide the level of the isosurfaces:
+
+ >>> plot3d_window = sx.contour3d(data, contours=[0.2, 0.4])
+
+ This function provides a subset of `mayavi.mlab.contour3d
+ <http://docs.enthought.com/mayavi/mayavi/auto/mlab_helper_functions.html#contour3d>`_
+ arguments.
+
+ :param scalars: The 3D scalar field to visualize
+ :type scalars: numpy.ndarray of float32 with 3 dimensions
+ :param contours:
+ Either the number of isosurfaces to draw (as an int) or
+ the isosurface level (as a float) or a list of isosurface levels
+ (as a list of float)
+ :type contours: Union[int, float, List[float]]
+ :param bool copy:
+ True (default) to make a copy of scalars.
+ False to avoid this copy (do not modify provided data afterwards)
+ :param color:
+ Color.s to use for isosurfaces.
+ Either a single color or a list of colors (one for each isosurface).
+ A color can be defined by its name (as a str) or
+ as RGB(A) as float or uint8.
+ :param str colormap:
+ If color is not provided, this colormap is used
+ for coloring isosurfaces.
+ :param vmin: Minimum value of the colormap
+ :type vmin: Union[float, None]
+ :param vmax: Maximum value of the colormap
+ :type vmax: Union[float, None]
+ :param float opacity:
+ Transparency of the isosurfaces as a float in [0., 1.]
+ :return: The widget used to visualize the data
+ :rtype: ~silx.gui.plot3d.ScalarFieldView.ScalarFieldView
+ """
+ # Prepare isolevel values
+ if isinstance(contours, int):
+ # Compute contours number of isovalues
+ mean = numpy.mean(scalars)
+ std = numpy.std(scalars)
+
+ start = mean - std * ((contours - 1) // 2)
+ contours = [start + std * index for index in range(contours)]
+
+ elif isinstance(contours, float):
+ contours = [contours]
+
+ assert isinstance(contours, Iterable)
+
+ # Prepare colors
+ if color is not None:
+ if isinstance(color, str) or isinstance(color[0], (int, float)):
+ # Single color provided, use it for all isosurfaces
+ colors = [rgba(color)] * len(contours)
+ else:
+ # As many colors as contours
+ colors = [rgba(c) for c in color]
+
+ # convert colors from float to uint8
+ colors = (numpy.array(colors) * 255).astype(numpy.uint8)
+
+ else: # Use colormap
+ colormap = Colormap(name=colormap, vmin=vmin, vmax=vmax)
+ colors = colormap.applyToData(contours)
+
+ assert len(colors) == len(contours)
+
+ # Prepare and apply opacity
+ assert isinstance(opacity, float)
+ opacity = min(max(0., opacity), 1.) # Clip opacity
+ colors[:, -1] = (colors[:, -1] * opacity).astype(numpy.uint8)
+
+ # Prepare widget
+ scalarField = ScalarFieldView()
+
+ scalarField.setBackgroundColor((0.9, 0.9, 0.9))
+ scalarField.setForegroundColor((0.1, 0.1, 0.1))
+ scalarField.setData(scalars, copy=copy)
+
+ # Create a parameter tree for the scalar field view
+ treeView = SFViewParamTree.TreeView(scalarField)
+ treeView.setSfView(scalarField) # Attach the parameter tree to the view
+
+ # Add the parameter tree to the main window in a dock widget
+ dock = qt.QDockWidget()
+ dock.setWindowTitle('Parameters')
+ dock.setWidget(treeView)
+ scalarField.addDockWidget(qt.Qt.RightDockWidgetArea, dock)
+
+ for level, color in zip(contours, colors):
+ scalarField.addIsosurface(level, color)
+
+ scalarField.show()
+
+ return scalarField
+
+
+_POINTS3D_MODE_CONVERSION = {
+ '2dcircle': 'o',
+ '2dcross': 'x',
+ '2ddash': '_',
+ '2ddiamond': 'd',
+ '2dsquare': 's',
+ 'point': ','
+}
+
+
+def points3d(x, y, z=None,
+ values=0.,
+ copy=True,
+ colormap='viridis',
+ vmin=None,
+ vmax=None,
+ mode='o'):
+ """
+ Plot a 3D scatter plot in a :class:`~silx.gui.plot3d.SceneWindow.SceneWindow` widget.
+
+ How to use:
+
+ >>> from silx import sx
+
+ Provided x, y, z, values, 4 numpy array of float32:
+
+ >>> plot3d_window = sx.points3d(x, y, z)
+
+ >>> plot3d_window = sx.points3d(x, y, z, values)
+
+ This function provides a subset of `mayavi.mlab.points3d
+ <http://docs.enthought.com/mayavi/mayavi/auto/mlab_helper_functions.html#points3d>`_
+ arguments.
+
+ :param numpy.ndarray x: X coordinates of the points
+ :param numpy.ndarray y: Y coordinates of the points
+ :param numpy.ndarray z: Z coordinates of the points (optional)
+ :param numpy.ndarray values: Values at each point (optional)
+ :param bool copy:
+ True (default) to make a copy of scalars.
+ False to avoid this copy (do not modify provided data afterwards)
+ :param str colormap:
+ Colormap to use for coding points as colors.
+ :param vmin: Minimum value of the colormap
+ :type vmin: Union[float, None]
+ :param vmax: Maximum value of the colormap
+ :type vmax: Union[float, None]
+ :param str mode: The type of marker to use
+
+ - Circle: 'o', '2dcircle'
+ - Diamond: 'd', '2ddiamond'
+ - Square: 's', '2dsquare'
+ - Plus: '+'
+ - Cross: 'x', '2dcross'
+ - Star: '*'
+ - Vertical line: '|'
+ - Horizontal line: '_', '2ddash'
+ - Point: '.'
+ - Pixel: ','
+ :return: The widget used to visualize the data
+ :rtype: ~silx.gui.plot3d.SceneWindow.SceneWindow
+ """
+ # Prepare widget
+ window = SceneWindow()
+ sceneWidget = window.getSceneWidget()
+ sceneWidget.setBackgroundColor((0.9, 0.9, 0.9))
+ sceneWidget.setForegroundColor((0.5, 0.5, 0.5))
+ sceneWidget.setTextColor((0.1, 0.1, 0.1))
+
+ mode = _POINTS3D_MODE_CONVERSION.get(mode, mode)
+
+ if z is None: # 2D scatter plot
+ scatter = sceneWidget.add2DScatter(x, y, values, copy=copy)
+ else: # 3D scatter plot
+ scatter = sceneWidget.add3DScatter(x, y, z, values, copy=copy)
+
+ colormap = Colormap(name=colormap, vmin=vmin, vmax=vmax)
+ scatter.setColormap(colormap)
+ scatter.setSymbol(mode)
+
+ window.show()
+
+ return window
diff --git a/silx/test/__init__.py b/silx/test/__init__.py
index 0a85fe2..5175601 100644
--- a/silx/test/__init__.py
+++ b/silx/test/__init__.py
@@ -26,13 +26,13 @@
It is possible to disable tests depending on Qt by setting
-:envvar:`WITH_QT_TEST` environment variable to 'False'.
+`silx.test.utils.test_options.WITH_QT_TEST = False`
It will skip all tests from :mod:`silx.test.gui`.
"""
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "22/06/2017"
+__date__ = "09/11/2017"
import logging
diff --git a/silx/test/test_resources.py b/silx/test/test_resources.py
index eaf65c1..66ac24f 100644
--- a/silx/test/test_resources.py
+++ b/silx/test/test_resources.py
@@ -26,7 +26,7 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "06/09/2017"
+__date__ = "17/01/2018"
import os
@@ -217,19 +217,6 @@ class TestExternalResources(unittest.TestCase):
shutil.rmtree(self.utilstest.data_home)
self.utilstest = None
- def test_tempdir(self):
- "test the temporary directory creation"
- d = self.utilstest.tempdir
- self.assertTrue(os.path.isdir(d))
- self.assertEqual(d, self.utilstest.tempdir, 'tmpdir is stable')
- self.utilstest.clean_up()
- self.assertFalse(os.path.isdir(d))
- e = self.utilstest.tempdir
- self.assertTrue(os.path.isdir(e))
- self.assertEqual(e, self.utilstest.tempdir, 'tmpdir is stable')
- self.assertNotEqual(d, e, "tempdir changed")
- self.utilstest.clean_up()
-
def test_download(self):
"test the download from silx.org"
f = self.utilstest.getfile("lena.png")
diff --git a/silx/test/test_sx.py b/silx/test/test_sx.py
index 0de3b35..f0da32d 100644
--- a/silx/test/test_sx.py
+++ b/silx/test/test_sx.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,16 +24,17 @@
# ###########################################################################*/
__authors__ = ["T. Vincent", "P. Knobel"]
__license__ = "MIT"
-__date__ = "05/12/2016"
+__date__ = "27/02/2018"
import logging
import os
import sys
import unittest
-
import numpy
+from silx.test.utils import test_options
+
_logger = logging.getLogger(__name__)
@@ -52,15 +53,14 @@ if sys.platform.startswith('linux') and not os.environ.get('DISPLAY', ''):
suite.addTest(SkipSXTest())
return suite
-elif os.environ.get('WITH_QT_TEST', 'True') == 'False':
+elif not test_options.WITH_QT_TEST:
# Explicitly disabled tests
- _logger.warning(
- "silx.sx tests disabled (env. variable WITH_QT_TEST=False)")
+ msg = "silx.sx tests disabled %s" % test_options.WITH_QT_TEST_REASON
+ _logger.warning(msg)
class SkipSXTest(unittest.TestCase):
def runTest(self):
- self.skipTest(
- "silx.sx tests disabled (env. variable WITH_QT_TEST=False)")
+ self.skipTest(test_options.WITH_QT_TEST_REASON)
def suite():
suite = unittest.TestSuite()
@@ -73,6 +73,7 @@ else:
from silx.gui import qt
# load TestCaseQt before sx
from silx.gui.test.utils import TestCaseQt
+ from silx.gui.plot.Colors import rgba
from silx import sx
class SXTest(TestCaseQt):
@@ -163,6 +164,110 @@ else:
title='origin=(10, 10), scale=(2, 2)')
self._expose_and_close(plt)
+ def test_ginput(self):
+ """Test ginput function
+
+ This does NOT perform interactive tests
+ """
+
+ plt = sx.plot()
+ self.qWaitForWindowExposed(plt)
+ self.qapp.processEvents()
+
+ result = sx.ginput(1, timeout=0.1)
+ self.assertEqual(len(result), 0)
+
+ plt.setAttribute(qt.Qt.WA_DeleteOnClose)
+ plt.close()
+
+ @unittest.skipUnless(test_options.WITH_GL_TEST,
+ test_options.WITH_GL_TEST_REASON)
+ def test_contour3d(self):
+ """Test contour3d function"""
+ coords = numpy.linspace(-10, 10, 64)
+ z = coords.reshape(-1, 1, 1)
+ y = coords.reshape(1, -1, 1)
+ x = coords.reshape(1, 1, -1)
+ data = numpy.sin(x * y * z) / (x * y * z)
+
+ # Just data
+ window = sx.contour3d(data)
+
+ isosurfaces = window.getIsosurfaces()
+ self.assertEqual(len(isosurfaces), 1)
+
+ self._expose_and_close(window)
+ if not window.getPlot3DWidget().isValid():
+ self.skipTest("OpenGL context is not valid")
+
+ # N contours + color
+ colors = ['red', 'green', 'blue']
+ window = sx.contour3d(data, copy=False, contours=len(colors),
+ color=colors)
+
+ isosurfaces = window.getIsosurfaces()
+ self.assertEqual(len(isosurfaces), len(colors))
+ for iso, color in zip(isosurfaces, colors):
+ self.assertEqual(rgba(iso.getColor()), rgba(color))
+
+ self._expose_and_close(window)
+
+ # by isolevel, single color
+ contours = 0.2, 0.5
+ window = sx.contour3d(data, copy=False, contours=contours,
+ color='yellow')
+
+ isosurfaces = window.getIsosurfaces()
+ self.assertEqual(len(isosurfaces), len(contours))
+ for iso, level in zip(isosurfaces, contours):
+ self.assertEqual(iso.getLevel(), level)
+ self.assertEqual(rgba(iso.getColor()),
+ rgba('yellow'))
+
+ self._expose_and_close(window)
+
+ # Single isolevel, colormap
+ window = sx.contour3d(data, copy=False, contours=0.5,
+ colormap='gray', vmin=0.6, opacity=0.4)
+
+ isosurfaces = window.getIsosurfaces()
+ self.assertEqual(len(isosurfaces), 1)
+ self.assertEqual(isosurfaces[0].getLevel(), 0.5)
+ self.assertEqual(rgba(isosurfaces[0].getColor()),
+ (0., 0., 0., 0.4))
+
+ self._expose_and_close(window)
+
+ @unittest.skipUnless(test_options.WITH_GL_TEST,
+ test_options.WITH_GL_TEST_REASON)
+ def test_points3d(self):
+ """Test points3d function"""
+ x = numpy.random.random(1024)
+ y = numpy.random.random(1024)
+ z = numpy.random.random(1024)
+ values = numpy.random.random(1024)
+
+ # 3D positions, no value
+ window = sx.points3d(x, y, z)
+
+ self._expose_and_close(window)
+ if not window.getSceneWidget().isValid():
+ self.skipTest("OpenGL context is not valid")
+
+ # 3D positions, values
+ window = sx.points3d(x, y, z, values, mode='2dsquare',
+ colormap='magma', vmin=0.4, vmax=0.5)
+ self._expose_and_close(window)
+
+ # 2D positions, no value
+ window = sx.points3d(x, y)
+ self._expose_and_close(window)
+
+ # 2D positions, values
+ window = sx.points3d(x, y, values=values, mode=',',
+ colormap='magma', vmin=0.4, vmax=0.5)
+ self._expose_and_close(window)
+
def suite():
test_suite = unittest.TestSuite()
test_suite.addTest(
diff --git a/silx/test/utils.py b/silx/test/utils.py
index 44eb899..bac415b 100644
--- a/silx/test/utils.py
+++ b/silx/test/utils.py
@@ -24,31 +24,23 @@
# ###########################################################################*/
"""Utilities for writing tests.
-- :class:`ParametricTestCase` provides a :meth:`TestCase.subTest` replacement
- for Python < 3.4
-- :class:`TestLogging` with context or the :func:`test_logging` decorator
- enables testing the number of logging messages of different levels.
- :func:`temp_dir` provides a with context to create/delete a temporary
directory.
"""
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "03/08/2017"
+__date__ = "17/01/2018"
-import os
+import sys
import contextlib
-import functools
-import logging
+import os
import numpy
import shutil
-import sys
import tempfile
-import unittest
from ..resources import ExternalResources
-_logger = logging.getLogger(__name__)
utilstest = ExternalResources(project="silx",
url_base="http://www.silx.org/pub/silx/",
@@ -56,174 +48,85 @@ utilstest = ExternalResources(project="silx",
timeout=60)
"This is the instance to be used. Singleton-like feature provided by module"
-# Parametric Test Base Class ##################################################
-
-if sys.hexversion >= 0x030400F0: # Python >= 3.4
- class ParametricTestCase(unittest.TestCase):
- pass
-else:
- class ParametricTestCase(unittest.TestCase):
- """TestCase with subTest support for Python < 3.4.
+class _TestOptions(object):
- Add subTest method to support parametric tests.
- API is the same, but behavior differs:
- If a subTest fails, the following ones are not run.
- """
+ def __init__(self):
+ self.WITH_QT_TEST = True
+ """Qt tests are included"""
- _subtest_msg = None # Class attribute to provide a default value
-
- @contextlib.contextmanager
- def subTest(self, msg=None, **params):
- """Use as unittest.TestCase.subTest method in Python >= 3.4."""
- # Format arguments as: '[msg] (key=value, ...)'
- param_str = ', '.join(['%s=%s' % (k, v) for k, v in params.items()])
- self._subtest_msg = '[%s] (%s)' % (msg or '', param_str)
- yield
- self._subtest_msg = None
-
- def shortDescription(self):
- short_desc = super(ParametricTestCase, self).shortDescription()
- if self._subtest_msg is not None:
- # Append subTest message to shortDescription
- short_desc = ' '.join(
- [msg for msg in (short_desc, self._subtest_msg) if msg])
-
- return short_desc if short_desc else None
-
-
-# Test logging messages #######################################################
-
-class TestLogging(logging.Handler):
- """Context checking the number of logging messages from a specified Logger.
-
- It disables propagation of logging message while running.
-
- This is meant to be used as a with statement, for example:
-
- >>> with TestLogging(logger, error=2, warning=0):
- >>> pass # Run tests here expecting 2 ERROR and no WARNING from logger
- ...
-
- :param logger: Name or instance of the logger to test.
- (Default: root logger)
- :type logger: str or :class:`logging.Logger`
- :param int critical: Expected number of CRITICAL messages.
- Default: Do not check.
- :param int error: Expected number of ERROR messages.
- Default: Do not check.
- :param int warning: Expected number of WARNING messages.
- Default: Do not check.
- :param int info: Expected number of INFO messages.
- Default: Do not check.
- :param int debug: Expected number of DEBUG messages.
- Default: Do not check.
- :param int notset: Expected number of NOTSET messages.
- Default: Do not check.
- :raises RuntimeError: If the message counts are the expected ones.
- """
+ self.WITH_QT_TEST_REASON = ""
+ """Reason for Qt tests are disabled if any"""
- def __init__(self, logger=None, critical=None, error=None,
- warning=None, info=None, debug=None, notset=None):
- if logger is None:
- logger = logging.getLogger()
- elif not isinstance(logger, logging.Logger):
- logger = logging.getLogger(logger)
- self.logger = logger
-
- self.records = []
-
- self.count_by_level = {
- logging.CRITICAL: critical,
- logging.ERROR: error,
- logging.WARNING: warning,
- logging.INFO: info,
- logging.DEBUG: debug,
- logging.NOTSET: notset
- }
-
- super(TestLogging, self).__init__()
-
- def __enter__(self):
- """Context (i.e., with) support"""
- self.records = [] # Reset recorded LogRecords
- self.logger.addHandler(self)
- self.logger.propagate = False
- # ensure no log message is ignored
- self.entry_level = self.logger.level * 1
- self.logger.setLevel(logging.DEBUG)
-
- def __exit__(self, exc_type, exc_value, traceback):
- """Context (i.e., with) support"""
- self.logger.removeHandler(self)
- self.logger.propagate = True
- self.logger.setLevel(self.entry_level)
-
- for level, expected_count in self.count_by_level.items():
- if expected_count is None:
- continue
-
- # Number of records for the specified level_str
- count = len([r for r in self.records if r.levelno == level])
- if count != expected_count: # That's an error
- # Resend record logs through logger as they where masked
- # to help debug
- for record in self.records:
- self.logger.handle(record)
- raise RuntimeError(
- 'Expected %d %s logging messages, got %d' % (
- expected_count, logging.getLevelName(level), count))
-
- def emit(self, record):
- """Override :meth:`logging.Handler.emit`"""
- self.records.append(record)
-
-
-def test_logging(logger=None, critical=None, error=None,
- warning=None, info=None, debug=None, notset=None):
- """Decorator checking number of logging messages.
-
- Propagation of logging messages is disabled by this decorator.
-
- In case the expected number of logging messages is not found, it raises
- a RuntimeError.
-
- >>> class Test(unittest.TestCase):
- ... @test_logging('module_logger_name', error=2, warning=0)
- ... def test(self):
- ... pass # Test expecting 2 ERROR and 0 WARNING messages
-
- :param logger: Name or instance of the logger to test.
- (Default: root logger)
- :type logger: str or :class:`logging.Logger`
- :param int critical: Expected number of CRITICAL messages.
- Default: Do not check.
- :param int error: Expected number of ERROR messages.
- Default: Do not check.
- :param int warning: Expected number of WARNING messages.
- Default: Do not check.
- :param int info: Expected number of INFO messages.
- Default: Do not check.
- :param int debug: Expected number of DEBUG messages.
- Default: Do not check.
- :param int notset: Expected number of NOTSET messages.
- Default: Do not check.
- """
- def decorator(func):
- test_context = TestLogging(logger, critical, error,
- warning, info, debug, notset)
+ self.WITH_OPENCL_TEST = True
+ """OpenCL tests are included"""
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- with test_context:
- result = func(*args, **kwargs)
- return result
- return wrapper
- return decorator
+ self.WITH_GL_TEST = True
+ """OpenGL tests are included"""
+ self.WITH_GL_TEST_REASON = ""
+ """Reason for OpenGL tests are disabled if any"""
+ self.TEST_LOW_MEM = False
+ """Skip tests using too much memory"""
+ def configure(self, parsed_options):
+ """Configure the TestOptions class from the command line arguments and the
+ environment variables
+ """
+ if not parsed_options.gui:
+ self.WITH_QT_TEST = False
+ self.WITH_QT_TEST_REASON = "Skipped by command line"
+ elif os.environ.get('WITH_QT_TEST', 'True') == 'False':
+ self.WITH_QT_TEST = False
+ self.WITH_QT_TEST_REASON = "Skipped by WITH_QT_TEST env var"
+ elif sys.platform.startswith('linux') and not os.environ.get('DISPLAY', ''):
+ self.WITH_QT_TEST = False
+ self.WITH_QT_TEST_REASON = "DISPLAY env variable not set"
+
+ if not parsed_options.opencl or os.environ.get('SILX_OPENCL', 'True') == 'False':
+ self.WITH_OPENCL_TEST = False
+ # That's an easy way to skip OpenCL tests
+ # It disable the use of OpenCL on the full silx project
+ os.environ['SILX_OPENCL'] = "False"
+
+ if not parsed_options.opengl:
+ self.WITH_GL_TEST = False
+ self.WITH_GL_TEST_REASON = "Skipped by command line"
+ elif os.environ.get('WITH_GL_TEST', 'True') == 'False':
+ self.WITH_GL_TEST = False
+ self.WITH_GL_TEST_REASON = "Skipped by WITH_GL_TEST env var"
+
+ if parsed_options.low_mem or os.environ.get('SILX_TEST_LOW_MEM', 'True') == 'False':
+ self.TEST_LOW_MEM = True
+
+ if self.WITH_QT_TEST:
+ from silx.gui import qt
+ if sys.platform == "win32" and qt.qVersion() == "5.9.2":
+ self.SKIP_TEST_FOR_ISSUE_936 = True
+
+ def add_parser_argument(self, parser):
+ """Add extrat arguments to the test argument parser
+
+ :param ArgumentParser parser: An argument parser
+ """
+ parser.add_argument("-x", "--no-gui", dest="gui", default=True,
+ action="store_false",
+ help="Disable the test of the graphical use interface")
+ parser.add_argument("-g", "--no-opengl", dest="opengl", default=True,
+ action="store_false",
+ help="Disable tests using OpenGL")
+ parser.add_argument("-o", "--no-opencl", dest="opencl", default=True,
+ action="store_false",
+ help="Disable the test of the OpenCL part")
+ parser.add_argument("-l", "--low-mem", dest="low_mem", default=False,
+ action="store_true",
+ help="Disable test with large memory consumption (>100Mbyte")
+
+
+test_options = _TestOptions()
+"""Singleton providing configuration information for all the tests"""
# Temporary directory context #################################################
diff --git a/silx/third_party/EdfFile.py b/silx/third_party/EdfFile.py
index 8a08c20..aeb9e54 100644
--- a/silx/third_party/EdfFile.py
+++ b/silx/third_party/EdfFile.py
@@ -1,6 +1,6 @@
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -689,7 +689,7 @@ class EdfFile(object):
if len(Position) != self.Images[Index].NumDim:
raise ValueError("EdfFile: coordinate with wrong dimension ")
- size_pixel = self.__GetSizeNumpyType__(self.__GetDefaultNumpyType__(self.Images[Index].DataType), index=Index)
+ size_pixel = self.__GetSizeNumpyType__(self.__GetDefaultNumpyType__(self.Images[Index].DataType, index=Index))
offset = Position[0] * size_pixel
if self.Images[Index].NumDim > 1:
size_row = size_pixel * self.Images[Index].Dim1
diff --git a/silx/third_party/_local/enum.py b/silx/third_party/_local/enum.py
deleted file mode 100644
index e15724f..0000000
--- a/silx/third_party/_local/enum.py
+++ /dev/null
@@ -1,877 +0,0 @@
-# coding: utf-8
-
-# enum34 is the new Python stdlib enum module available in Python 3.4
-# backported for previous versions of Python from 2.4 to 3.3.
-# tested on 2.6, 2.7, and 3.3+
-#
-# Downloaded from: https://pypi.python.org/pypi/enum34
-#
-# Copyright (c) 2013, Ethan Furman.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# Redistributions of source code must retain the above
-# copyright notice, this list of conditions and the
-# following disclaimer.
-#
-# Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials
-# provided with the distribution.
-#
-# Neither the name Ethan Furman nor the names of any
-# contributors may be used to endorse or promote products
-# derived from this software without specific prior written
-# permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-"""Python Enumerations"""
-
-import sys as _sys
-
-__all__ = ['Enum', 'IntEnum', 'unique']
-
-version = 1, 1, 6
-
-pyver = float('%s.%s' % _sys.version_info[:2])
-
-try:
- any
-except NameError:
- def any(iterable):
- for element in iterable:
- if element:
- return True
- return False
-
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = None
-
-try:
- basestring
-except NameError:
- # In Python 2 basestring is the ancestor of both str and unicode
- # in Python 3 it's just str, but was missing in 3.1
- basestring = str
-
-try:
- unicode
-except NameError:
- # In Python 3 unicode no longer exists (it's just str)
- unicode = str
-
-class _RouteClassAttributeToGetattr(object):
- """Route attribute access on a class to __getattr__.
-
- This is a descriptor, used to define attributes that act differently when
- accessed through an instance and through a class. Instance access remains
- normal, but access to an attribute through a class will be routed to the
- class's __getattr__ method; this is done by raising AttributeError.
-
- """
- def __init__(self, fget=None):
- self.fget = fget
-
- def __get__(self, instance, ownerclass=None):
- if instance is None:
- raise AttributeError()
- return self.fget(instance)
-
- def __set__(self, instance, value):
- raise AttributeError("can't set attribute")
-
- def __delete__(self, instance):
- raise AttributeError("can't delete attribute")
-
-
-def _is_descriptor(obj):
- """Returns True if obj is a descriptor, False otherwise."""
- return (
- hasattr(obj, '__get__') or
- hasattr(obj, '__set__') or
- hasattr(obj, '__delete__'))
-
-
-def _is_dunder(name):
- """Returns True if a __dunder__ name, False otherwise."""
- return (name[:2] == name[-2:] == '__' and
- name[2:3] != '_' and
- name[-3:-2] != '_' and
- len(name) > 4)
-
-
-def _is_sunder(name):
- """Returns True if a _sunder_ name, False otherwise."""
- return (name[0] == name[-1] == '_' and
- name[1:2] != '_' and
- name[-2:-1] != '_' and
- len(name) > 2)
-
-
-def _make_class_unpicklable(cls):
- """Make the given class un-picklable."""
- def _break_on_call_reduce(self, protocol=None):
- raise TypeError('%r cannot be pickled' % self)
- cls.__reduce_ex__ = _break_on_call_reduce
- cls.__module__ = '<unknown>'
-
-
-class _EnumDict(dict):
- """Track enum member order and ensure member names are not reused.
-
- EnumMeta will use the names found in self._member_names as the
- enumeration member names.
-
- """
- def __init__(self):
- super(_EnumDict, self).__init__()
- self._member_names = []
-
- def __setitem__(self, key, value):
- """Changes anything not dundered or not a descriptor.
-
- If a descriptor is added with the same name as an enum member, the name
- is removed from _member_names (this may leave a hole in the numerical
- sequence of values).
-
- If an enum member name is used twice, an error is raised; duplicate
- values are not checked for.
-
- Single underscore (sunder) names are reserved.
-
- Note: in 3.x __order__ is simply discarded as a not necessary piece
- leftover from 2.x
-
- """
- if pyver >= 3.0 and key in ('_order_', '__order__'):
- return
- elif key == '__order__':
- key = '_order_'
- if _is_sunder(key):
- if key != '_order_':
- raise ValueError('_names_ are reserved for future Enum use')
- elif _is_dunder(key):
- pass
- elif key in self._member_names:
- # descriptor overwriting an enum?
- raise TypeError('Attempted to reuse key: %r' % key)
- elif not _is_descriptor(value):
- if key in self:
- # enum overwriting a descriptor?
- raise TypeError('Key already defined as: %r' % self[key])
- self._member_names.append(key)
- super(_EnumDict, self).__setitem__(key, value)
-
-
-# Dummy value for Enum as EnumMeta explicity checks for it, but of course until
-# EnumMeta finishes running the first time the Enum class doesn't exist. This
-# is also why there are checks in EnumMeta like `if Enum is not None`
-Enum = None
-
-
-class EnumMeta(type):
- """Metaclass for Enum"""
- @classmethod
- def __prepare__(metacls, cls, bases):
- return _EnumDict()
-
- def __new__(metacls, cls, bases, classdict):
- # an Enum class is final once enumeration items have been defined; it
- # cannot be mixed with other types (int, float, etc.) if it has an
- # inherited __new__ unless a new __new__ is defined (or the resulting
- # class will fail).
- if type(classdict) is dict:
- original_dict = classdict
- classdict = _EnumDict()
- for k, v in original_dict.items():
- classdict[k] = v
-
- member_type, first_enum = metacls._get_mixins_(bases)
- __new__, save_new, use_args = metacls._find_new_(classdict, member_type,
- first_enum)
- # save enum items into separate mapping so they don't get baked into
- # the new class
- members = dict((k, classdict[k]) for k in classdict._member_names)
- for name in classdict._member_names:
- del classdict[name]
-
- # py2 support for definition order
- _order_ = classdict.get('_order_')
- if _order_ is None:
- if pyver < 3.0:
- try:
- _order_ = [name for (name, value) in sorted(members.items(), key=lambda item: item[1])]
- except TypeError:
- _order_ = [name for name in sorted(members.keys())]
- else:
- _order_ = classdict._member_names
- else:
- del classdict['_order_']
- if pyver < 3.0:
- _order_ = _order_.replace(',', ' ').split()
- aliases = [name for name in members if name not in _order_]
- _order_ += aliases
-
- # check for illegal enum names (any others?)
- invalid_names = set(members) & set(['mro'])
- if invalid_names:
- raise ValueError('Invalid enum member name(s): %s' % (
- ', '.join(invalid_names), ))
-
- # save attributes from super classes so we know if we can take
- # the shortcut of storing members in the class dict
- base_attributes = set([a for b in bases for a in b.__dict__])
- # create our new Enum type
- enum_class = super(EnumMeta, metacls).__new__(metacls, cls, bases, classdict)
- enum_class._member_names_ = [] # names in random order
- if OrderedDict is not None:
- enum_class._member_map_ = OrderedDict()
- else:
- enum_class._member_map_ = {} # name->value map
- enum_class._member_type_ = member_type
-
- # Reverse value->name map for hashable values.
- enum_class._value2member_map_ = {}
-
- # instantiate them, checking for duplicates as we go
- # we instantiate first instead of checking for duplicates first in case
- # a custom __new__ is doing something funky with the values -- such as
- # auto-numbering ;)
- if __new__ is None:
- __new__ = enum_class.__new__
- for member_name in _order_:
- value = members[member_name]
- if not isinstance(value, tuple):
- args = (value, )
- else:
- args = value
- if member_type is tuple: # special case for tuple enums
- args = (args, ) # wrap it one more time
- if not use_args or not args:
- enum_member = __new__(enum_class)
- if not hasattr(enum_member, '_value_'):
- enum_member._value_ = value
- else:
- enum_member = __new__(enum_class, *args)
- if not hasattr(enum_member, '_value_'):
- enum_member._value_ = member_type(*args)
- value = enum_member._value_
- enum_member._name_ = member_name
- enum_member.__objclass__ = enum_class
- enum_member.__init__(*args)
- # If another member with the same value was already defined, the
- # new member becomes an alias to the existing one.
- for name, canonical_member in enum_class._member_map_.items():
- if canonical_member.value == enum_member._value_:
- enum_member = canonical_member
- break
- else:
- # Aliases don't appear in member names (only in __members__).
- enum_class._member_names_.append(member_name)
- # performance boost for any member that would not shadow
- # a DynamicClassAttribute (aka _RouteClassAttributeToGetattr)
- if member_name not in base_attributes:
- setattr(enum_class, member_name, enum_member)
- # now add to _member_map_
- enum_class._member_map_[member_name] = enum_member
- try:
- # This may fail if value is not hashable. We can't add the value
- # to the map, and by-value lookups for this value will be
- # linear.
- enum_class._value2member_map_[value] = enum_member
- except TypeError:
- pass
-
-
- # If a custom type is mixed into the Enum, and it does not know how
- # to pickle itself, pickle.dumps will succeed but pickle.loads will
- # fail. Rather than have the error show up later and possibly far
- # from the source, sabotage the pickle protocol for this class so
- # that pickle.dumps also fails.
- #
- # However, if the new class implements its own __reduce_ex__, do not
- # sabotage -- it's on them to make sure it works correctly. We use
- # __reduce_ex__ instead of any of the others as it is preferred by
- # pickle over __reduce__, and it handles all pickle protocols.
- unpicklable = False
- if '__reduce_ex__' not in classdict:
- if member_type is not object:
- methods = ('__getnewargs_ex__', '__getnewargs__',
- '__reduce_ex__', '__reduce__')
- if not any(m in member_type.__dict__ for m in methods):
- _make_class_unpicklable(enum_class)
- unpicklable = True
-
-
- # double check that repr and friends are not the mixin's or various
- # things break (such as pickle)
- for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
- class_method = getattr(enum_class, name)
- obj_method = getattr(member_type, name, None)
- enum_method = getattr(first_enum, name, None)
- if name not in classdict and class_method is not enum_method:
- if name == '__reduce_ex__' and unpicklable:
- continue
- setattr(enum_class, name, enum_method)
-
- # method resolution and int's are not playing nice
- # Python's less than 2.6 use __cmp__
-
- if pyver < 2.6:
-
- if issubclass(enum_class, int):
- setattr(enum_class, '__cmp__', getattr(int, '__cmp__'))
-
- elif pyver < 3.0:
-
- if issubclass(enum_class, int):
- for method in (
- '__le__',
- '__lt__',
- '__gt__',
- '__ge__',
- '__eq__',
- '__ne__',
- '__hash__',
- ):
- setattr(enum_class, method, getattr(int, method))
-
- # replace any other __new__ with our own (as long as Enum is not None,
- # anyway) -- again, this is to support pickle
- if Enum is not None:
- # if the user defined their own __new__, save it before it gets
- # clobbered in case they subclass later
- if save_new:
- setattr(enum_class, '__member_new__', enum_class.__dict__['__new__'])
- setattr(enum_class, '__new__', Enum.__dict__['__new__'])
- return enum_class
-
- def __bool__(cls):
- """
- classes/types should always be True.
- """
- return True
-
- def __call__(cls, value, names=None, module=None, type=None, start=1):
- """Either returns an existing member, or creates a new enum class.
-
- This method is used both when an enum class is given a value to match
- to an enumeration member (i.e. Color(3)) and for the functional API
- (i.e. Color = Enum('Color', names='red green blue')).
-
- When used for the functional API: `module`, if set, will be stored in
- the new class' __module__ attribute; `type`, if set, will be mixed in
- as the first base class.
-
- Note: if `module` is not set this routine will attempt to discover the
- calling module by walking the frame stack; if this is unsuccessful
- the resulting class will not be pickleable.
-
- """
- if names is None: # simple value lookup
- return cls.__new__(cls, value)
- # otherwise, functional API: we're creating a new Enum type
- return cls._create_(value, names, module=module, type=type, start=start)
-
- def __contains__(cls, member):
- return isinstance(member, cls) and member.name in cls._member_map_
-
- def __delattr__(cls, attr):
- # nicer error message when someone tries to delete an attribute
- # (see issue19025).
- if attr in cls._member_map_:
- raise AttributeError(
- "%s: cannot delete Enum member." % cls.__name__)
- super(EnumMeta, cls).__delattr__(attr)
-
- def __dir__(self):
- return (['__class__', '__doc__', '__members__', '__module__'] +
- self._member_names_)
-
- @property
- def __members__(cls):
- """Returns a mapping of member name->value.
-
- This mapping lists all enum members, including aliases. Note that this
- is a copy of the internal mapping.
-
- """
- return cls._member_map_.copy()
-
- def __getattr__(cls, name):
- """Return the enum member matching `name`
-
- We use __getattr__ instead of descriptors or inserting into the enum
- class' __dict__ in order to support `name` and `value` being both
- properties for enum members (which live in the class' __dict__) and
- enum members themselves.
-
- """
- if _is_dunder(name):
- raise AttributeError(name)
- try:
- return cls._member_map_[name]
- except KeyError:
- raise AttributeError(name)
-
- def __getitem__(cls, name):
- return cls._member_map_[name]
-
- def __iter__(cls):
- return (cls._member_map_[name] for name in cls._member_names_)
-
- def __reversed__(cls):
- return (cls._member_map_[name] for name in reversed(cls._member_names_))
-
- def __len__(cls):
- return len(cls._member_names_)
-
- __nonzero__ = __bool__
-
- def __repr__(cls):
- return "<enum %r>" % cls.__name__
-
- def __setattr__(cls, name, value):
- """Block attempts to reassign Enum members.
-
- A simple assignment to the class namespace only changes one of the
- several possible ways to get an Enum member from the Enum class,
- resulting in an inconsistent Enumeration.
-
- """
- member_map = cls.__dict__.get('_member_map_', {})
- if name in member_map:
- raise AttributeError('Cannot reassign members.')
- super(EnumMeta, cls).__setattr__(name, value)
-
- def _create_(cls, class_name, names=None, module=None, type=None, start=1):
- """Convenience method to create a new Enum class.
-
- `names` can be:
-
- * A string containing member names, separated either with spaces or
- commas. Values are auto-numbered from 1.
- * An iterable of member names. Values are auto-numbered from 1.
- * An iterable of (member name, value) pairs.
- * A mapping of member name -> value.
-
- """
- if pyver < 3.0:
- # if class_name is unicode, attempt a conversion to ASCII
- if isinstance(class_name, unicode):
- try:
- class_name = class_name.encode('ascii')
- except UnicodeEncodeError:
- raise TypeError('%r is not representable in ASCII' % class_name)
- metacls = cls.__class__
- if type is None:
- bases = (cls, )
- else:
- bases = (type, cls)
- classdict = metacls.__prepare__(class_name, bases)
- _order_ = []
-
- # special processing needed for names?
- if isinstance(names, basestring):
- names = names.replace(',', ' ').split()
- if isinstance(names, (tuple, list)) and isinstance(names[0], basestring):
- names = [(e, i+start) for (i, e) in enumerate(names)]
-
- # Here, names is either an iterable of (name, value) or a mapping.
- item = None # in case names is empty
- for item in names:
- if isinstance(item, basestring):
- member_name, member_value = item, names[item]
- else:
- member_name, member_value = item
- classdict[member_name] = member_value
- _order_.append(member_name)
- # only set _order_ in classdict if name/value was not from a mapping
- if not isinstance(item, basestring):
- classdict['_order_'] = ' '.join(_order_)
- enum_class = metacls.__new__(metacls, class_name, bases, classdict)
-
- # TODO: replace the frame hack if a blessed way to know the calling
- # module is ever developed
- if module is None:
- try:
- module = _sys._getframe(2).f_globals['__name__']
- except (AttributeError, ValueError):
- pass
- if module is None:
- _make_class_unpicklable(enum_class)
- else:
- enum_class.__module__ = module
-
- return enum_class
-
- @staticmethod
- def _get_mixins_(bases):
- """Returns the type for creating enum members, and the first inherited
- enum class.
-
- bases: the tuple of bases that was given to __new__
-
- """
- if not bases or Enum is None:
- return object, Enum
-
-
- # double check that we are not subclassing a class with existing
- # enumeration members; while we're at it, see if any other data
- # type has been mixed in so we can use the correct __new__
- member_type = first_enum = None
- for base in bases:
- if (base is not Enum and
- issubclass(base, Enum) and
- base._member_names_):
- raise TypeError("Cannot extend enumerations")
- # base is now the last base in bases
- if not issubclass(base, Enum):
- raise TypeError("new enumerations must be created as "
- "`ClassName([mixin_type,] enum_type)`")
-
- # get correct mix-in type (either mix-in type of Enum subclass, or
- # first base if last base is Enum)
- if not issubclass(bases[0], Enum):
- member_type = bases[0] # first data type
- first_enum = bases[-1] # enum type
- else:
- for base in bases[0].__mro__:
- # most common: (IntEnum, int, Enum, object)
- # possible: (<Enum 'AutoIntEnum'>, <Enum 'IntEnum'>,
- # <class 'int'>, <Enum 'Enum'>,
- # <class 'object'>)
- if issubclass(base, Enum):
- if first_enum is None:
- first_enum = base
- else:
- if member_type is None:
- member_type = base
-
- return member_type, first_enum
-
- if pyver < 3.0:
- @staticmethod
- def _find_new_(classdict, member_type, first_enum):
- """Returns the __new__ to be used for creating the enum members.
-
- classdict: the class dictionary given to __new__
- member_type: the data type whose __new__ will be used by default
- first_enum: enumeration to check for an overriding __new__
-
- """
- # now find the correct __new__, checking to see of one was defined
- # by the user; also check earlier enum classes in case a __new__ was
- # saved as __member_new__
- __new__ = classdict.get('__new__', None)
- if __new__:
- return None, True, True # __new__, save_new, use_args
-
- N__new__ = getattr(None, '__new__')
- O__new__ = getattr(object, '__new__')
- if Enum is None:
- E__new__ = N__new__
- else:
- E__new__ = Enum.__dict__['__new__']
- # check all possibles for __member_new__ before falling back to
- # __new__
- for method in ('__member_new__', '__new__'):
- for possible in (member_type, first_enum):
- try:
- target = possible.__dict__[method]
- except (AttributeError, KeyError):
- target = getattr(possible, method, None)
- if target not in [
- None,
- N__new__,
- O__new__,
- E__new__,
- ]:
- if method == '__member_new__':
- classdict['__new__'] = target
- return None, False, True
- if isinstance(target, staticmethod):
- target = target.__get__(member_type)
- __new__ = target
- break
- if __new__ is not None:
- break
- else:
- __new__ = object.__new__
-
- # if a non-object.__new__ is used then whatever value/tuple was
- # assigned to the enum member name will be passed to __new__ and to the
- # new enum member's __init__
- if __new__ is object.__new__:
- use_args = False
- else:
- use_args = True
-
- return __new__, False, use_args
- else:
- @staticmethod
- def _find_new_(classdict, member_type, first_enum):
- """Returns the __new__ to be used for creating the enum members.
-
- classdict: the class dictionary given to __new__
- member_type: the data type whose __new__ will be used by default
- first_enum: enumeration to check for an overriding __new__
-
- """
- # now find the correct __new__, checking to see of one was defined
- # by the user; also check earlier enum classes in case a __new__ was
- # saved as __member_new__
- __new__ = classdict.get('__new__', None)
-
- # should __new__ be saved as __member_new__ later?
- save_new = __new__ is not None
-
- if __new__ is None:
- # check all possibles for __member_new__ before falling back to
- # __new__
- for method in ('__member_new__', '__new__'):
- for possible in (member_type, first_enum):
- target = getattr(possible, method, None)
- if target not in (
- None,
- None.__new__,
- object.__new__,
- Enum.__new__,
- ):
- __new__ = target
- break
- if __new__ is not None:
- break
- else:
- __new__ = object.__new__
-
- # if a non-object.__new__ is used then whatever value/tuple was
- # assigned to the enum member name will be passed to __new__ and to the
- # new enum member's __init__
- if __new__ is object.__new__:
- use_args = False
- else:
- use_args = True
-
- return __new__, save_new, use_args
-
-
-########################################################
-# In order to support Python 2 and 3 with a single
-# codebase we have to create the Enum methods separately
-# and then use the `type(name, bases, dict)` method to
-# create the class.
-########################################################
-temp_enum_dict = {}
-temp_enum_dict['__doc__'] = "Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n"
-
-def __new__(cls, value):
- # all enum instances are actually created during class construction
- # without calling this method; this method is called by the metaclass'
- # __call__ (i.e. Color(3) ), and by pickle
- if type(value) is cls:
- # For lookups like Color(Color.red)
- value = value.value
- #return value
- # by-value search for a matching enum member
- # see if it's in the reverse mapping (for hashable values)
- try:
- if value in cls._value2member_map_:
- return cls._value2member_map_[value]
- except TypeError:
- # not there, now do long search -- O(n) behavior
- for member in cls._member_map_.values():
- if member.value == value:
- return member
- raise ValueError("%s is not a valid %s" % (value, cls.__name__))
-temp_enum_dict['__new__'] = __new__
-del __new__
-
-def __repr__(self):
- return "<%s.%s: %r>" % (
- self.__class__.__name__, self._name_, self._value_)
-temp_enum_dict['__repr__'] = __repr__
-del __repr__
-
-def __str__(self):
- return "%s.%s" % (self.__class__.__name__, self._name_)
-temp_enum_dict['__str__'] = __str__
-del __str__
-
-if pyver >= 3.0:
- def __dir__(self):
- added_behavior = [
- m
- for cls in self.__class__.mro()
- for m in cls.__dict__
- if m[0] != '_' and m not in self._member_map_
- ]
- return (['__class__', '__doc__', '__module__', ] + added_behavior)
- temp_enum_dict['__dir__'] = __dir__
- del __dir__
-
-def __format__(self, format_spec):
- # mixed-in Enums should use the mixed-in type's __format__, otherwise
- # we can get strange results with the Enum name showing up instead of
- # the value
-
- # pure Enum branch
- if self._member_type_ is object:
- cls = str
- val = str(self)
- # mix-in branch
- else:
- cls = self._member_type_
- val = self.value
- return cls.__format__(val, format_spec)
-temp_enum_dict['__format__'] = __format__
-del __format__
-
-
-####################################
-# Python's less than 2.6 use __cmp__
-
-if pyver < 2.6:
-
- def __cmp__(self, other):
- if type(other) is self.__class__:
- if self is other:
- return 0
- return -1
- return NotImplemented
- raise TypeError("unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__))
- temp_enum_dict['__cmp__'] = __cmp__
- del __cmp__
-
-else:
-
- def __le__(self, other):
- raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__))
- temp_enum_dict['__le__'] = __le__
- del __le__
-
- def __lt__(self, other):
- raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__))
- temp_enum_dict['__lt__'] = __lt__
- del __lt__
-
- def __ge__(self, other):
- raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__))
- temp_enum_dict['__ge__'] = __ge__
- del __ge__
-
- def __gt__(self, other):
- raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__))
- temp_enum_dict['__gt__'] = __gt__
- del __gt__
-
-
-def __eq__(self, other):
- if type(other) is self.__class__:
- return self is other
- return NotImplemented
-temp_enum_dict['__eq__'] = __eq__
-del __eq__
-
-def __ne__(self, other):
- if type(other) is self.__class__:
- return self is not other
- return NotImplemented
-temp_enum_dict['__ne__'] = __ne__
-del __ne__
-
-def __hash__(self):
- return hash(self._name_)
-temp_enum_dict['__hash__'] = __hash__
-del __hash__
-
-def __reduce_ex__(self, proto):
- return self.__class__, (self._value_, )
-temp_enum_dict['__reduce_ex__'] = __reduce_ex__
-del __reduce_ex__
-
-# _RouteClassAttributeToGetattr is used to provide access to the `name`
-# and `value` properties of enum members while keeping some measure of
-# protection from modification, while still allowing for an enumeration
-# to have members named `name` and `value`. This works because enumeration
-# members are not set directly on the enum class -- __getattr__ is
-# used to look them up.
-
-@_RouteClassAttributeToGetattr
-def name(self):
- return self._name_
-temp_enum_dict['name'] = name
-del name
-
-@_RouteClassAttributeToGetattr
-def value(self):
- return self._value_
-temp_enum_dict['value'] = value
-del value
-
-@classmethod
-def _convert(cls, name, module, filter, source=None):
- """
- Create a new Enum subclass that replaces a collection of global constants
- """
- # convert all constants from source (or module) that pass filter() to
- # a new Enum called name, and export the enum and its members back to
- # module;
- # also, replace the __reduce_ex__ method so unpickling works in
- # previous Python versions
- module_globals = vars(_sys.modules[module])
- if source:
- source = vars(source)
- else:
- source = module_globals
- members = dict((name, value) for name, value in source.items() if filter(name))
- cls = cls(name, members, module=module)
- cls.__reduce_ex__ = _reduce_ex_by_name
- module_globals.update(cls.__members__)
- module_globals[name] = cls
- return cls
-temp_enum_dict['_convert'] = _convert
-del _convert
-
-Enum = EnumMeta('Enum', (object, ), temp_enum_dict)
-del temp_enum_dict
-
-# Enum has now been created
-###########################
-
-class IntEnum(int, Enum):
- """Enum where members are also (and must be) ints"""
-
-def _reduce_ex_by_name(self, proto):
- return self.name
-
-def unique(enumeration):
- """Class decorator that ensures only unique members exist in an enumeration."""
- duplicates = []
- for name, member in enumeration.__members__.items():
- if name != member.name:
- duplicates.append((name, member.name))
- if duplicates:
- duplicate_names = ', '.join(
- ["%s -> %s" % (alias, name) for (alias, name) in duplicates]
- )
- raise ValueError('duplicate names found in %r: %s' %
- (enumeration, duplicate_names)
- )
- return enumeration
diff --git a/silx/third_party/_local/six.py b/silx/third_party/_local/six.py
deleted file mode 100644
index 190c023..0000000
--- a/silx/third_party/_local/six.py
+++ /dev/null
@@ -1,868 +0,0 @@
-"""Utilities for writing code that runs on Python 2 and 3"""
-
-# Copyright (c) 2010-2015 Benjamin Peterson
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-from __future__ import absolute_import
-
-import functools
-import itertools
-import operator
-import sys
-import types
-
-__author__ = "Benjamin Peterson <benjamin@python.org>"
-__version__ = "1.10.0"
-
-
-# Useful for very coarse version differentiation.
-PY2 = sys.version_info[0] == 2
-PY3 = sys.version_info[0] == 3
-PY34 = sys.version_info[0:2] >= (3, 4)
-
-if PY3:
- string_types = str,
- integer_types = int,
- class_types = type,
- text_type = str
- binary_type = bytes
-
- MAXSIZE = sys.maxsize
-else:
- string_types = basestring,
- integer_types = (int, long)
- class_types = (type, types.ClassType)
- text_type = unicode
- binary_type = str
-
- if sys.platform.startswith("java"):
- # Jython always uses 32 bits.
- MAXSIZE = int((1 << 31) - 1)
- else:
- # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
- class X(object):
-
- def __len__(self):
- return 1 << 31
- try:
- len(X())
- except OverflowError:
- # 32-bit
- MAXSIZE = int((1 << 31) - 1)
- else:
- # 64-bit
- MAXSIZE = int((1 << 63) - 1)
- del X
-
-
-def _add_doc(func, doc):
- """Add documentation to a function."""
- func.__doc__ = doc
-
-
-def _import_module(name):
- """Import module, returning the module after the last dot."""
- __import__(name)
- return sys.modules[name]
-
-
-class _LazyDescr(object):
-
- def __init__(self, name):
- self.name = name
-
- def __get__(self, obj, tp):
- result = self._resolve()
- setattr(obj, self.name, result) # Invokes __set__.
- try:
- # This is a bit ugly, but it avoids running this again by
- # removing this descriptor.
- delattr(obj.__class__, self.name)
- except AttributeError:
- pass
- return result
-
-
-class MovedModule(_LazyDescr):
-
- def __init__(self, name, old, new=None):
- super(MovedModule, self).__init__(name)
- if PY3:
- if new is None:
- new = name
- self.mod = new
- else:
- self.mod = old
-
- def _resolve(self):
- return _import_module(self.mod)
-
- def __getattr__(self, attr):
- _module = self._resolve()
- value = getattr(_module, attr)
- setattr(self, attr, value)
- return value
-
-
-class _LazyModule(types.ModuleType):
-
- def __init__(self, name):
- super(_LazyModule, self).__init__(name)
- self.__doc__ = self.__class__.__doc__
-
- def __dir__(self):
- attrs = ["__doc__", "__name__"]
- attrs += [attr.name for attr in self._moved_attributes]
- return attrs
-
- # Subclasses should override this
- _moved_attributes = []
-
-
-class MovedAttribute(_LazyDescr):
-
- def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
- super(MovedAttribute, self).__init__(name)
- if PY3:
- if new_mod is None:
- new_mod = name
- self.mod = new_mod
- if new_attr is None:
- if old_attr is None:
- new_attr = name
- else:
- new_attr = old_attr
- self.attr = new_attr
- else:
- self.mod = old_mod
- if old_attr is None:
- old_attr = name
- self.attr = old_attr
-
- def _resolve(self):
- module = _import_module(self.mod)
- return getattr(module, self.attr)
-
-
-class _SixMetaPathImporter(object):
-
- """
- A meta path importer to import six.moves and its submodules.
-
- This class implements a PEP302 finder and loader. It should be compatible
- with Python 2.5 and all existing versions of Python3
- """
-
- def __init__(self, six_module_name):
- self.name = six_module_name
- self.known_modules = {}
-
- def _add_module(self, mod, *fullnames):
- for fullname in fullnames:
- self.known_modules[self.name + "." + fullname] = mod
-
- def _get_module(self, fullname):
- return self.known_modules[self.name + "." + fullname]
-
- def find_module(self, fullname, path=None):
- if fullname in self.known_modules:
- return self
- return None
-
- def __get_module(self, fullname):
- try:
- return self.known_modules[fullname]
- except KeyError:
- raise ImportError("This loader does not know module " + fullname)
-
- def load_module(self, fullname):
- try:
- # in case of a reload
- return sys.modules[fullname]
- except KeyError:
- pass
- mod = self.__get_module(fullname)
- if isinstance(mod, MovedModule):
- mod = mod._resolve()
- else:
- mod.__loader__ = self
- sys.modules[fullname] = mod
- return mod
-
- def is_package(self, fullname):
- """
- Return true, if the named module is a package.
-
- We need this method to get correct spec objects with
- Python 3.4 (see PEP451)
- """
- return hasattr(self.__get_module(fullname), "__path__")
-
- def get_code(self, fullname):
- """Return None
-
- Required, if is_package is implemented"""
- self.__get_module(fullname) # eventually raises ImportError
- return None
- get_source = get_code # same as get_code
-
-_importer = _SixMetaPathImporter(__name__)
-
-
-class _MovedItems(_LazyModule):
-
- """Lazy loading of moved objects"""
- __path__ = [] # mark as package
-
-
-_moved_attributes = [
- MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
- MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
- MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
- MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
- MovedAttribute("intern", "__builtin__", "sys"),
- MovedAttribute("map", "itertools", "builtins", "imap", "map"),
- MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
- MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
- MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
- MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
- MovedAttribute("reduce", "__builtin__", "functools"),
- MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
- MovedAttribute("StringIO", "StringIO", "io"),
- MovedAttribute("UserDict", "UserDict", "collections"),
- MovedAttribute("UserList", "UserList", "collections"),
- MovedAttribute("UserString", "UserString", "collections"),
- MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
- MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
- MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
- MovedModule("builtins", "__builtin__"),
- MovedModule("configparser", "ConfigParser"),
- MovedModule("copyreg", "copy_reg"),
- MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
- MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
- MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
- MovedModule("http_cookies", "Cookie", "http.cookies"),
- MovedModule("html_entities", "htmlentitydefs", "html.entities"),
- MovedModule("html_parser", "HTMLParser", "html.parser"),
- MovedModule("http_client", "httplib", "http.client"),
- MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
- MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
- MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
- MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
- MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
- MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
- MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
- MovedModule("cPickle", "cPickle", "pickle"),
- MovedModule("queue", "Queue"),
- MovedModule("reprlib", "repr"),
- MovedModule("socketserver", "SocketServer"),
- MovedModule("_thread", "thread", "_thread"),
- MovedModule("tkinter", "Tkinter"),
- MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
- MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
- MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
- MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
- MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
- MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
- MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
- MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
- MovedModule("tkinter_colorchooser", "tkColorChooser",
- "tkinter.colorchooser"),
- MovedModule("tkinter_commondialog", "tkCommonDialog",
- "tkinter.commondialog"),
- MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
- MovedModule("tkinter_font", "tkFont", "tkinter.font"),
- MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
- MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
- "tkinter.simpledialog"),
- MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
- MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
- MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
- MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
- MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
- MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
-]
-# Add windows specific modules.
-if sys.platform == "win32":
- _moved_attributes += [
- MovedModule("winreg", "_winreg"),
- ]
-
-for attr in _moved_attributes:
- setattr(_MovedItems, attr.name, attr)
- if isinstance(attr, MovedModule):
- _importer._add_module(attr, "moves." + attr.name)
-del attr
-
-_MovedItems._moved_attributes = _moved_attributes
-
-moves = _MovedItems(__name__ + ".moves")
-_importer._add_module(moves, "moves")
-
-
-class Module_six_moves_urllib_parse(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_parse"""
-
-
-_urllib_parse_moved_attributes = [
- MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
- MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
- MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
- MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
- MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
- MovedAttribute("urljoin", "urlparse", "urllib.parse"),
- MovedAttribute("urlparse", "urlparse", "urllib.parse"),
- MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
- MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
- MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
- MovedAttribute("quote", "urllib", "urllib.parse"),
- MovedAttribute("quote_plus", "urllib", "urllib.parse"),
- MovedAttribute("unquote", "urllib", "urllib.parse"),
- MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
- MovedAttribute("urlencode", "urllib", "urllib.parse"),
- MovedAttribute("splitquery", "urllib", "urllib.parse"),
- MovedAttribute("splittag", "urllib", "urllib.parse"),
- MovedAttribute("splituser", "urllib", "urllib.parse"),
- MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
- MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
- MovedAttribute("uses_params", "urlparse", "urllib.parse"),
- MovedAttribute("uses_query", "urlparse", "urllib.parse"),
- MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
-]
-for attr in _urllib_parse_moved_attributes:
- setattr(Module_six_moves_urllib_parse, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
-
-_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
- "moves.urllib_parse", "moves.urllib.parse")
-
-
-class Module_six_moves_urllib_error(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_error"""
-
-
-_urllib_error_moved_attributes = [
- MovedAttribute("URLError", "urllib2", "urllib.error"),
- MovedAttribute("HTTPError", "urllib2", "urllib.error"),
- MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
-]
-for attr in _urllib_error_moved_attributes:
- setattr(Module_six_moves_urllib_error, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
-
-_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
- "moves.urllib_error", "moves.urllib.error")
-
-
-class Module_six_moves_urllib_request(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_request"""
-
-
-_urllib_request_moved_attributes = [
- MovedAttribute("urlopen", "urllib2", "urllib.request"),
- MovedAttribute("install_opener", "urllib2", "urllib.request"),
- MovedAttribute("build_opener", "urllib2", "urllib.request"),
- MovedAttribute("pathname2url", "urllib", "urllib.request"),
- MovedAttribute("url2pathname", "urllib", "urllib.request"),
- MovedAttribute("getproxies", "urllib", "urllib.request"),
- MovedAttribute("Request", "urllib2", "urllib.request"),
- MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
- MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
- MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
- MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
- MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
- MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
- MovedAttribute("FileHandler", "urllib2", "urllib.request"),
- MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
- MovedAttribute("urlretrieve", "urllib", "urllib.request"),
- MovedAttribute("urlcleanup", "urllib", "urllib.request"),
- MovedAttribute("URLopener", "urllib", "urllib.request"),
- MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
- MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
-]
-for attr in _urllib_request_moved_attributes:
- setattr(Module_six_moves_urllib_request, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
-
-_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
- "moves.urllib_request", "moves.urllib.request")
-
-
-class Module_six_moves_urllib_response(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_response"""
-
-
-_urllib_response_moved_attributes = [
- MovedAttribute("addbase", "urllib", "urllib.response"),
- MovedAttribute("addclosehook", "urllib", "urllib.response"),
- MovedAttribute("addinfo", "urllib", "urllib.response"),
- MovedAttribute("addinfourl", "urllib", "urllib.response"),
-]
-for attr in _urllib_response_moved_attributes:
- setattr(Module_six_moves_urllib_response, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
-
-_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
- "moves.urllib_response", "moves.urllib.response")
-
-
-class Module_six_moves_urllib_robotparser(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_robotparser"""
-
-
-_urllib_robotparser_moved_attributes = [
- MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
-]
-for attr in _urllib_robotparser_moved_attributes:
- setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
-
-_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
- "moves.urllib_robotparser", "moves.urllib.robotparser")
-
-
-class Module_six_moves_urllib(types.ModuleType):
-
- """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
- __path__ = [] # mark as package
- parse = _importer._get_module("moves.urllib_parse")
- error = _importer._get_module("moves.urllib_error")
- request = _importer._get_module("moves.urllib_request")
- response = _importer._get_module("moves.urllib_response")
- robotparser = _importer._get_module("moves.urllib_robotparser")
-
- def __dir__(self):
- return ['parse', 'error', 'request', 'response', 'robotparser']
-
-_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
- "moves.urllib")
-
-
-def add_move(move):
- """Add an item to six.moves."""
- setattr(_MovedItems, move.name, move)
-
-
-def remove_move(name):
- """Remove item from six.moves."""
- try:
- delattr(_MovedItems, name)
- except AttributeError:
- try:
- del moves.__dict__[name]
- except KeyError:
- raise AttributeError("no such move, %r" % (name,))
-
-
-if PY3:
- _meth_func = "__func__"
- _meth_self = "__self__"
-
- _func_closure = "__closure__"
- _func_code = "__code__"
- _func_defaults = "__defaults__"
- _func_globals = "__globals__"
-else:
- _meth_func = "im_func"
- _meth_self = "im_self"
-
- _func_closure = "func_closure"
- _func_code = "func_code"
- _func_defaults = "func_defaults"
- _func_globals = "func_globals"
-
-
-try:
- advance_iterator = next
-except NameError:
- def advance_iterator(it):
- return it.next()
-next = advance_iterator
-
-
-try:
- callable = callable
-except NameError:
- def callable(obj):
- return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
-
-
-if PY3:
- def get_unbound_function(unbound):
- return unbound
-
- create_bound_method = types.MethodType
-
- def create_unbound_method(func, cls):
- return func
-
- Iterator = object
-else:
- def get_unbound_function(unbound):
- return unbound.im_func
-
- def create_bound_method(func, obj):
- return types.MethodType(func, obj, obj.__class__)
-
- def create_unbound_method(func, cls):
- return types.MethodType(func, None, cls)
-
- class Iterator(object):
-
- def next(self):
- return type(self).__next__(self)
-
- callable = callable
-_add_doc(get_unbound_function,
- """Get the function out of a possibly unbound function""")
-
-
-get_method_function = operator.attrgetter(_meth_func)
-get_method_self = operator.attrgetter(_meth_self)
-get_function_closure = operator.attrgetter(_func_closure)
-get_function_code = operator.attrgetter(_func_code)
-get_function_defaults = operator.attrgetter(_func_defaults)
-get_function_globals = operator.attrgetter(_func_globals)
-
-
-if PY3:
- def iterkeys(d, **kw):
- return iter(d.keys(**kw))
-
- def itervalues(d, **kw):
- return iter(d.values(**kw))
-
- def iteritems(d, **kw):
- return iter(d.items(**kw))
-
- def iterlists(d, **kw):
- return iter(d.lists(**kw))
-
- viewkeys = operator.methodcaller("keys")
-
- viewvalues = operator.methodcaller("values")
-
- viewitems = operator.methodcaller("items")
-else:
- def iterkeys(d, **kw):
- return d.iterkeys(**kw)
-
- def itervalues(d, **kw):
- return d.itervalues(**kw)
-
- def iteritems(d, **kw):
- return d.iteritems(**kw)
-
- def iterlists(d, **kw):
- return d.iterlists(**kw)
-
- viewkeys = operator.methodcaller("viewkeys")
-
- viewvalues = operator.methodcaller("viewvalues")
-
- viewitems = operator.methodcaller("viewitems")
-
-_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
-_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
-_add_doc(iteritems,
- "Return an iterator over the (key, value) pairs of a dictionary.")
-_add_doc(iterlists,
- "Return an iterator over the (key, [values]) pairs of a dictionary.")
-
-
-if PY3:
- def b(s):
- return s.encode("latin-1")
-
- def u(s):
- return s
- unichr = chr
- import struct
- int2byte = struct.Struct(">B").pack
- del struct
- byte2int = operator.itemgetter(0)
- indexbytes = operator.getitem
- iterbytes = iter
- import io
- StringIO = io.StringIO
- BytesIO = io.BytesIO
- _assertCountEqual = "assertCountEqual"
- if sys.version_info[1] <= 1:
- _assertRaisesRegex = "assertRaisesRegexp"
- _assertRegex = "assertRegexpMatches"
- else:
- _assertRaisesRegex = "assertRaisesRegex"
- _assertRegex = "assertRegex"
-else:
- def b(s):
- return s
- # Workaround for standalone backslash
-
- def u(s):
- return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
- unichr = unichr
- int2byte = chr
-
- def byte2int(bs):
- return ord(bs[0])
-
- def indexbytes(buf, i):
- return ord(buf[i])
- iterbytes = functools.partial(itertools.imap, ord)
- import StringIO
- StringIO = BytesIO = StringIO.StringIO
- _assertCountEqual = "assertItemsEqual"
- _assertRaisesRegex = "assertRaisesRegexp"
- _assertRegex = "assertRegexpMatches"
-_add_doc(b, """Byte literal""")
-_add_doc(u, """Text literal""")
-
-
-def assertCountEqual(self, *args, **kwargs):
- return getattr(self, _assertCountEqual)(*args, **kwargs)
-
-
-def assertRaisesRegex(self, *args, **kwargs):
- return getattr(self, _assertRaisesRegex)(*args, **kwargs)
-
-
-def assertRegex(self, *args, **kwargs):
- return getattr(self, _assertRegex)(*args, **kwargs)
-
-
-if PY3:
- exec_ = getattr(moves.builtins, "exec")
-
- def reraise(tp, value, tb=None):
- if value is None:
- value = tp()
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
-
-else:
- def exec_(_code_, _globs_=None, _locs_=None):
- """Execute code in a namespace."""
- if _globs_ is None:
- frame = sys._getframe(1)
- _globs_ = frame.f_globals
- if _locs_ is None:
- _locs_ = frame.f_locals
- del frame
- elif _locs_ is None:
- _locs_ = _globs_
- exec("""exec _code_ in _globs_, _locs_""")
-
- exec_("""def reraise(tp, value, tb=None):
- raise tp, value, tb
-""")
-
-
-if sys.version_info[:2] == (3, 2):
- exec_("""def raise_from(value, from_value):
- if from_value is None:
- raise value
- raise value from from_value
-""")
-elif sys.version_info[:2] > (3, 2):
- exec_("""def raise_from(value, from_value):
- raise value from from_value
-""")
-else:
- def raise_from(value, from_value):
- raise value
-
-
-print_ = getattr(moves.builtins, "print", None)
-if print_ is None:
- def print_(*args, **kwargs):
- """The new-style print function for Python 2.4 and 2.5."""
- fp = kwargs.pop("file", sys.stdout)
- if fp is None:
- return
-
- def write(data):
- if not isinstance(data, basestring):
- data = str(data)
- # If the file has an encoding, encode unicode with it.
- if (isinstance(fp, file) and
- isinstance(data, unicode) and
- fp.encoding is not None):
- errors = getattr(fp, "errors", None)
- if errors is None:
- errors = "strict"
- data = data.encode(fp.encoding, errors)
- fp.write(data)
- want_unicode = False
- sep = kwargs.pop("sep", None)
- if sep is not None:
- if isinstance(sep, unicode):
- want_unicode = True
- elif not isinstance(sep, str):
- raise TypeError("sep must be None or a string")
- end = kwargs.pop("end", None)
- if end is not None:
- if isinstance(end, unicode):
- want_unicode = True
- elif not isinstance(end, str):
- raise TypeError("end must be None or a string")
- if kwargs:
- raise TypeError("invalid keyword arguments to print()")
- if not want_unicode:
- for arg in args:
- if isinstance(arg, unicode):
- want_unicode = True
- break
- if want_unicode:
- newline = unicode("\n")
- space = unicode(" ")
- else:
- newline = "\n"
- space = " "
- if sep is None:
- sep = space
- if end is None:
- end = newline
- for i, arg in enumerate(args):
- if i:
- write(sep)
- write(arg)
- write(end)
-if sys.version_info[:2] < (3, 3):
- _print = print_
-
- def print_(*args, **kwargs):
- fp = kwargs.get("file", sys.stdout)
- flush = kwargs.pop("flush", False)
- _print(*args, **kwargs)
- if flush and fp is not None:
- fp.flush()
-
-_add_doc(reraise, """Reraise an exception.""")
-
-if sys.version_info[0:2] < (3, 4):
- def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
- updated=functools.WRAPPER_UPDATES):
- def wrapper(f):
- f = functools.wraps(wrapped, assigned, updated)(f)
- f.__wrapped__ = wrapped
- return f
- return wrapper
-else:
- wraps = functools.wraps
-
-
-def with_metaclass(meta, *bases):
- """Create a base class with a metaclass."""
- # This requires a bit of explanation: the basic idea is to make a dummy
- # metaclass for one level of class instantiation that replaces itself with
- # the actual metaclass.
- class metaclass(meta):
-
- def __new__(cls, name, this_bases, d):
- return meta(name, bases, d)
- return type.__new__(metaclass, 'temporary_class', (), {})
-
-
-def add_metaclass(metaclass):
- """Class decorator for creating a class with a metaclass."""
- def wrapper(cls):
- orig_vars = cls.__dict__.copy()
- slots = orig_vars.get('__slots__')
- if slots is not None:
- if isinstance(slots, str):
- slots = [slots]
- for slots_var in slots:
- orig_vars.pop(slots_var)
- orig_vars.pop('__dict__', None)
- orig_vars.pop('__weakref__', None)
- return metaclass(cls.__name__, cls.__bases__, orig_vars)
- return wrapper
-
-
-def python_2_unicode_compatible(klass):
- """
- A decorator that defines __unicode__ and __str__ methods under Python 2.
- Under Python 3 it does nothing.
-
- To support Python 2 and 3 with a single code base, define a __str__ method
- returning text and apply this decorator to the class.
- """
- if PY2:
- if '__str__' not in klass.__dict__:
- raise ValueError("@python_2_unicode_compatible cannot be applied "
- "to %s because it doesn't define __str__()." %
- klass.__name__)
- klass.__unicode__ = klass.__str__
- klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
- return klass
-
-
-# Complete the moves implementation.
-# This code is at the end of this module to speed up module loading.
-# Turn this module into a package.
-__path__ = [] # required for PEP 302 and PEP 451
-__package__ = __name__ # see PEP 366 @ReservedAssignment
-if globals().get("__spec__") is not None:
- __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable
-# Remove other six meta path importers, since they cause problems. This can
-# happen if six is removed from sys.modules and then reloaded. (Setuptools does
-# this for some reason.)
-if sys.meta_path:
- for i, importer in enumerate(sys.meta_path):
- # Here's some real nastiness: Another "instance" of the six module might
- # be floating around. Therefore, we can't use isinstance() to check for
- # the six meta path importer, since the other six instance will have
- # inserted an importer with different class.
- if (type(importer).__name__ == "_SixMetaPathImporter" and
- importer.name == __name__):
- del sys.meta_path[i]
- break
- del i, importer
-# Finally, add the importer to the meta path import hook.
-sys.meta_path.append(_importer)
diff --git a/silx/third_party/concurrent_futures.py b/silx/third_party/concurrent_futures.py
new file mode 100644
index 0000000..bd917cb
--- /dev/null
+++ b/silx/third_party/concurrent_futures.py
@@ -0,0 +1,59 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2018 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Wrapper module for the `concurrent.futures` package.
+
+The `concurrent.futures` package is available in python>=3.2.
+
+For Python2, it tries to fill this module with the local copy
+of `concurrent.futures` if it exists.
+Otherwise it expects to have the `concurrent.futures` packaged
+installed in the Python path.
+For Python3, it uses the module from Python.
+
+It should be used like that:
+
+.. code-block::
+
+ from silx.third_party import concurrent_futures
+
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "15/02/2018"
+
+import sys
+
+if sys.version_info < (3,): # Use Python 2 backport
+ try:
+ # try to import the local version
+ from ._local.concurrent_futures import * # noqa
+ except ImportError:
+ # else try to import it from the python path
+ from concurrent.futures import * # noqa
+else: # Use Python 3 standard library
+ from concurrent.futures import * # noqa
diff --git a/silx/third_party/scipy_spatial.py b/silx/third_party/scipy_spatial.py
new file mode 100644
index 0000000..9885154
--- /dev/null
+++ b/silx/third_party/scipy_spatial.py
@@ -0,0 +1,51 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Wrapper module for `scipy.spatial.Delaunay` class.
+
+Uses a local copy of `scipy.spatial.Delaunay` if available,
+else it loads it from `scipy`.
+
+It should be used like that:
+
+.. code-block::
+
+ from silx.third_party.scipy_spatial import Delaunay
+
+"""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "07/11/2017"
+
+try:
+ # try to import silx local copy of Delaunay
+ from ._local.scipy_spatial import Delaunay # noqa
+except ImportError:
+ # else import it from the python path
+ from scipy.spatial import Delaunay # noqa
+
+__all__ = ['Delaunay']
diff --git a/silx/third_party/setup.py b/silx/third_party/setup.py
index 7477456..147091b 100644
--- a/silx/third_party/setup.py
+++ b/silx/third_party/setup.py
@@ -4,7 +4,7 @@
#
# /*##########################################################################
#
-# Copyright (c) 2016 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -28,7 +28,7 @@
__authors__ = ["Valentin Valls"]
__license__ = "MIT"
-__date__ = "26/04/2017"
+__date__ = "07/11/2017"
import os
from numpy.distutils.misc_util import Configuration
@@ -40,6 +40,8 @@ def configuration(parent_package='', top_path=None):
local_path = os.path.join(top_path, parent_package, "third_party", "_local")
if os.path.exists(local_path):
config.add_subpackage('_local')
+ config.add_subpackage('_local.scipy_spatial')
+ config.add_subpackage('_local.concurrent_futures')
return config
diff --git a/silx/utils/array_like.py b/silx/utils/array_like.py
index f4c85bf..11f531d 100644
--- a/silx/utils/array_like.py
+++ b/silx/utils/array_like.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -300,7 +300,7 @@ class ListOfImages(object):
The returned object refers to
the same images but with a different :attr:`transposition`.
- :param list[int] transposition: List/tuple of dimension numbers in the
+ :param List[int] transposition: List/tuple of dimension numbers in the
wanted order.
If ``None`` (default), reverse the dimensions.
:return: new :class:`ListOfImages` object
@@ -568,7 +568,7 @@ class DatasetView(object):
The returned object refers to
the same dataset but with a different :attr:`transposition`.
- :param list[int] transposition: List of dimension numbers in the wanted order.
+ :param List[int] transposition: List of dimension numbers in the wanted order.
If ``None`` (default), reverse the dimensions.
:return: Transposed DatasetView
"""
diff --git a/silx/utils/deprecation.py b/silx/utils/deprecation.py
index f1d2a79..f9ba017 100644
--- a/silx/utils/deprecation.py
+++ b/silx/utils/deprecation.py
@@ -28,7 +28,7 @@ from __future__ import absolute_import, print_function, division
__authors__ = ["Jerome Kieffer", "H. Payno", "P. Knobel"]
__license__ = "MIT"
-__date__ = "11/09/2017"
+__date__ = "26/02/2018"
import sys
import logging
@@ -40,7 +40,7 @@ depreclog = logging.getLogger("silx.DEPRECATION")
deprecache = set([])
-def deprecated(func=None, reason=None, replacement=None, since_version=None, only_once=True):
+def deprecated(func=None, reason=None, replacement=None, since_version=None, only_once=True, skip_backtrace_count=1):
"""
Decorator that deprecates the use of a function
@@ -52,6 +52,8 @@ def deprecated(func=None, reason=None, replacement=None, since_version=None, onl
deprecated (e.g. "0.5.0").
:param bool only_once: If true, the deprecation warning will only be
generated one time. Default is true.
+ :param int skip_backtrace_count: Amount of last backtrace to ignore when
+ logging the backtrace
"""
def decorator(func):
@functools.wraps(func)
@@ -64,7 +66,7 @@ def deprecated(func=None, reason=None, replacement=None, since_version=None, onl
replacement=replacement,
since_version=since_version,
only_once=only_once,
- skip_backtrace_count=1)
+ skip_backtrace_count=skip_backtrace_count)
return func(*args, **kwargs)
return wrapper
if func is not None:
diff --git a/silx/utils/exceptions.py b/silx/utils/exceptions.py
new file mode 100644
index 0000000..addba89
--- /dev/null
+++ b/silx/utils/exceptions.py
@@ -0,0 +1,33 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Bunch of useful exceptions"""
+
+__authors__ = ["H. Payno"]
+__license__ = "MIT"
+__date__ = "17/01/2018"
+
+
+class NotEditableError(Exception):
+ """Exception emitted when try to access to a non editable attribute"""
diff --git a/silx/utils/launcher.py b/silx/utils/launcher.py
index 8d2c81c..059e990 100644
--- a/silx/utils/launcher.py
+++ b/silx/utils/launcher.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2016 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -41,7 +41,7 @@ import logging
_logger = logging.getLogger(__name__)
-class LauncherCommand():
+class LauncherCommand(object):
"""Description of a command"""
def __init__(self, name, description=None, module_name=None, function=None):
@@ -68,17 +68,9 @@ class LauncherCommand():
try:
module = importlib.import_module(self.module_name)
return module
- except ImportError as e:
- if "No module name" in e.args[0]:
- msg = "Error while reaching module '%s'"
- _logger.debug(msg, self.module_name, exc_info=True)
- missing_module = e.args[0].split("'")[1]
- msg = "Module '%s' is not installed but is mandatory."\
- + " You can install it using \"pip install %s\"."
- _logger.error(msg, missing_module, missing_module)
- else:
- msg = "Error while reaching module '%s'"
- _logger.error(msg, self.module_name, exc_info=True)
+ except ImportError:
+ msg = "Error while reaching module '%s'"
+ _logger.error(msg, self.module_name, exc_info=True)
return None
def get_function(self):
diff --git a/silx/utils/property.py b/silx/utils/property.py
new file mode 100644
index 0000000..10d5d98
--- /dev/null
+++ b/silx/utils/property.py
@@ -0,0 +1,52 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Bunch of useful decorators"""
+
+from __future__ import absolute_import, print_function, division
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "22/02/2018"
+
+
+class classproperty(property):
+ """
+ Decorator to transform an object method into a class property.
+
+ This code are equivalent, but the second one can be decorated with
+ deprecation warning for example.
+
+ .. code-block:: python
+
+ class Foo(object):
+ VALUE = 10
+
+ class Foo2(object):
+ @classproperty
+ def VALUE(self):
+ return 10
+ """
+ def __get__(self, cls, owner):
+ return classmethod(self.fget).__get__(None, owner)()
diff --git a/silx/utils/test/test_deprecation.py b/silx/utils/test/test_deprecation.py
index b5c5de4..0aa06a0 100644
--- a/silx/utils/test/test_deprecation.py
+++ b/silx/utils/test/test_deprecation.py
@@ -26,12 +26,12 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "11/09/2017"
+__date__ = "17/01/2018"
import unittest
from .. import deprecation
-from silx.test import utils
+from silx.utils import testutils
class TestDeprecation(unittest.TestCase):
@@ -53,22 +53,22 @@ class TestDeprecation(unittest.TestCase):
def deprecatedEveryTime(self):
pass
- @utils.test_logging(deprecation.depreclog.name, warning=1)
+ @testutils.test_logging(deprecation.depreclog.name, warning=1)
def testAnnotationWithoutParam(self):
self.deprecatedWithoutParam()
- @utils.test_logging(deprecation.depreclog.name, warning=1)
+ @testutils.test_logging(deprecation.depreclog.name, warning=1)
def testAnnotationWithParams(self):
self.deprecatedWithParams()
- @utils.test_logging(deprecation.depreclog.name, warning=3)
+ @testutils.test_logging(deprecation.depreclog.name, warning=3)
def testLoggedEveryTime(self):
"""Logged everytime cause it is 3 different locations"""
self.deprecatedOnlyOnce()
self.deprecatedOnlyOnce()
self.deprecatedOnlyOnce()
- @utils.test_logging(deprecation.depreclog.name, warning=1)
+ @testutils.test_logging(deprecation.depreclog.name, warning=1)
def testLoggedSingleTime(self):
def log():
self.deprecatedOnlyOnce()
@@ -76,18 +76,18 @@ class TestDeprecation(unittest.TestCase):
log()
log()
- @utils.test_logging(deprecation.depreclog.name, warning=3)
+ @testutils.test_logging(deprecation.depreclog.name, warning=3)
def testLoggedEveryTime2(self):
self.deprecatedEveryTime()
self.deprecatedEveryTime()
self.deprecatedEveryTime()
- @utils.test_logging(deprecation.depreclog.name, warning=1)
+ @testutils.test_logging(deprecation.depreclog.name, warning=1)
def testWarning(self):
deprecation.deprecated_warning(type_="t", name="n")
def testBacktrace(self):
- testLogging = utils.TestLogging(deprecation.depreclog.name)
+ testLogging = testutils.TestLogging(deprecation.depreclog.name)
with testLogging:
self.deprecatedEveryTime()
message = testLogging.records[0].getMessage()
diff --git a/silx/utils/test/test_launcher.py b/silx/utils/test/test_launcher.py
index b3b6f98..87b7158 100644
--- a/silx/utils/test/test_launcher.py
+++ b/silx/utils/test/test_launcher.py
@@ -26,12 +26,12 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "03/04/2017"
+__date__ = "17/01/2018"
import sys
import unittest
-from silx.test.utils import ParametricTestCase
+from silx.utils.testutils import ParametricTestCase
from .. import launcher
diff --git a/silx/utils/testutils.py b/silx/utils/testutils.py
new file mode 100644
index 0000000..82c2ce3
--- /dev/null
+++ b/silx/utils/testutils.py
@@ -0,0 +1,281 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Utilities for writing tests.
+
+- :class:`ParametricTestCase` provides a :meth:`TestCase.subTest` replacement
+ for Python < 3.4
+- :class:`TestLogging` with context or the :func:`test_logging` decorator
+ enables testing the number of logging messages of different levels.
+"""
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "26/01/2018"
+
+
+import contextlib
+import functools
+import logging
+import sys
+import unittest
+
+_logger = logging.getLogger(__name__)
+
+
+if sys.hexversion >= 0x030400F0: # Python >= 3.4
+ class ParametricTestCase(unittest.TestCase):
+ pass
+else:
+ class ParametricTestCase(unittest.TestCase):
+ """TestCase with subTest support for Python < 3.4.
+
+ Add subTest method to support parametric tests.
+ API is the same, but behavior differs:
+ If a subTest fails, the following ones are not run.
+ """
+
+ _subtest_msg = None # Class attribute to provide a default value
+
+ @contextlib.contextmanager
+ def subTest(self, msg=None, **params):
+ """Use as unittest.TestCase.subTest method in Python >= 3.4."""
+ # Format arguments as: '[msg] (key=value, ...)'
+ param_str = ', '.join(['%s=%s' % (k, v) for k, v in params.items()])
+ self._subtest_msg = '[%s] (%s)' % (msg or '', param_str)
+ yield
+ self._subtest_msg = None
+
+ def shortDescription(self):
+ short_desc = super(ParametricTestCase, self).shortDescription()
+ if self._subtest_msg is not None:
+ # Append subTest message to shortDescription
+ short_desc = ' '.join(
+ [msg for msg in (short_desc, self._subtest_msg) if msg])
+
+ return short_desc if short_desc else None
+
+
+def parameterize(test_case_class, *args, **kwargs):
+ """Create a suite containing all tests taken from the given
+ subclass, passing them the parameters.
+
+ .. code-block:: python
+
+ class TestParameterizedCase(unittest.TestCase):
+ def __init__(self, methodName='runTest', foo=None):
+ unittest.TestCase.__init__(self, methodName)
+ self.foo = foo
+
+ def suite():
+ testSuite = unittest.TestSuite()
+ testSuite.addTest(parameterize(TestParameterizedCase, foo=10))
+ testSuite.addTest(parameterize(TestParameterizedCase, foo=50))
+ return testSuite
+ """
+ test_loader = unittest.TestLoader()
+ test_names = test_loader.getTestCaseNames(test_case_class)
+ suite = unittest.TestSuite()
+ for name in test_names:
+ suite.addTest(test_case_class(name, *args, **kwargs))
+ return suite
+
+
+class TestLogging(logging.Handler):
+ """Context checking the number of logging messages from a specified Logger.
+
+ It disables propagation of logging message while running.
+
+ This is meant to be used as a with statement, for example:
+
+ >>> with TestLogging(logger, error=2, warning=0):
+ >>> pass # Run tests here expecting 2 ERROR and no WARNING from logger
+ ...
+
+ :param logger: Name or instance of the logger to test.
+ (Default: root logger)
+ :type logger: str or :class:`logging.Logger`
+ :param int critical: Expected number of CRITICAL messages.
+ Default: Do not check.
+ :param int error: Expected number of ERROR messages.
+ Default: Do not check.
+ :param int warning: Expected number of WARNING messages.
+ Default: Do not check.
+ :param int info: Expected number of INFO messages.
+ Default: Do not check.
+ :param int debug: Expected number of DEBUG messages.
+ Default: Do not check.
+ :param int notset: Expected number of NOTSET messages.
+ Default: Do not check.
+ :raises RuntimeError: If the message counts are the expected ones.
+ """
+
+ def __init__(self, logger=None, critical=None, error=None,
+ warning=None, info=None, debug=None, notset=None):
+ if logger is None:
+ logger = logging.getLogger()
+ elif not isinstance(logger, logging.Logger):
+ logger = logging.getLogger(logger)
+ self.logger = logger
+
+ self.records = []
+
+ self.count_by_level = {
+ logging.CRITICAL: critical,
+ logging.ERROR: error,
+ logging.WARNING: warning,
+ logging.INFO: info,
+ logging.DEBUG: debug,
+ logging.NOTSET: notset
+ }
+
+ super(TestLogging, self).__init__()
+
+ def __enter__(self):
+ """Context (i.e., with) support"""
+ self.records = [] # Reset recorded LogRecords
+ self.logger.addHandler(self)
+ self.logger.propagate = False
+ # ensure no log message is ignored
+ self.entry_level = self.logger.level * 1
+ self.logger.setLevel(logging.DEBUG)
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ """Context (i.e., with) support"""
+ self.logger.removeHandler(self)
+ self.logger.propagate = True
+ self.logger.setLevel(self.entry_level)
+
+ for level, expected_count in self.count_by_level.items():
+ if expected_count is None:
+ continue
+
+ # Number of records for the specified level_str
+ count = len([r for r in self.records if r.levelno == level])
+ if count != expected_count: # That's an error
+ # Resend record logs through logger as they where masked
+ # to help debug
+ for record in self.records:
+ self.logger.handle(record)
+ raise RuntimeError(
+ 'Expected %d %s logging messages, got %d' % (
+ expected_count, logging.getLevelName(level), count))
+
+ def emit(self, record):
+ """Override :meth:`logging.Handler.emit`"""
+ self.records.append(record)
+
+
+def test_logging(logger=None, critical=None, error=None,
+ warning=None, info=None, debug=None, notset=None):
+ """Decorator checking number of logging messages.
+
+ Propagation of logging messages is disabled by this decorator.
+
+ In case the expected number of logging messages is not found, it raises
+ a RuntimeError.
+
+ >>> class Test(unittest.TestCase):
+ ... @test_logging('module_logger_name', error=2, warning=0)
+ ... def test(self):
+ ... pass # Test expecting 2 ERROR and 0 WARNING messages
+
+ :param logger: Name or instance of the logger to test.
+ (Default: root logger)
+ :type logger: str or :class:`logging.Logger`
+ :param int critical: Expected number of CRITICAL messages.
+ Default: Do not check.
+ :param int error: Expected number of ERROR messages.
+ Default: Do not check.
+ :param int warning: Expected number of WARNING messages.
+ Default: Do not check.
+ :param int info: Expected number of INFO messages.
+ Default: Do not check.
+ :param int debug: Expected number of DEBUG messages.
+ Default: Do not check.
+ :param int notset: Expected number of NOTSET messages.
+ Default: Do not check.
+ """
+ def decorator(func):
+ test_context = TestLogging(logger, critical, error,
+ warning, info, debug, notset)
+
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ with test_context:
+ result = func(*args, **kwargs)
+ return result
+ return wrapper
+ return decorator
+
+
+# Simulate missing library context
+class EnsureImportError(object):
+ """This context manager allows to simulate the unavailability
+ of a library, even if it is actually available. It ensures that
+ an ImportError is raised if the code inside the context tries to
+ import the module.
+
+ It can be used to test that a correct fallback library is used,
+ or that the expected error code is returned.
+
+ Trivial example::
+
+ from silx.utils.testutils import EnsureImportError
+
+ with EnsureImportError("h5py"):
+ try:
+ import h5py
+ except ImportError:
+ print("Good")
+
+ .. note::
+
+ This context manager does not remove the library from the namespace,
+ if it is already imported. It only ensures that any attempt to import
+ it again will cause an ImportError to be raised.
+ """
+ def __init__(self, name):
+ """
+
+ :param str name: Name of module to be hidden (e.g. "h5py")
+ """
+ self.module_name = name
+
+ def __enter__(self):
+ """Simulate failed import by setting sys.modules[name]=None"""
+ if self.module_name not in sys.modules:
+ self._delete_on_exit = True
+ self._backup = None
+ else:
+ self._delete_on_exit = False
+ self._backup = sys.modules[self.module_name]
+ sys.modules[self.module_name] = None
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ """Restore previous state"""
+ if self._delete_on_exit:
+ del sys.modules[self.module_name]
+ else:
+ sys.modules[self.module_name] = self._backup
diff --git a/version.py b/version.py
index 8ba98ff..512554b 100644
--- a/version.py
+++ b/version.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2016 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -53,11 +53,11 @@ from __future__ import absolute_import, print_function, division
__authors__ = ["Jérôme Kieffer"]
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-__date__ = "01/10/2017"
+__date__ = "26/02/2018"
__status__ = "production"
__docformat__ = 'restructuredtext'
__all__ = ["date", "version_info", "strictversion", "hexversion", "debianversion",
- "calc_hexversion", "citation"]
+ "calc_hexversion"]
RELEASE_LEVEL_VALUE = {"dev": 0,
"alpha": 10,
@@ -67,8 +67,8 @@ RELEASE_LEVEL_VALUE = {"dev": 0,
"final": 15}
MAJOR = 0
-MINOR = 6
-MICRO = 1
+MINOR = 7
+MICRO = 0
RELEV = "final" # <16
SERIAL = 0 # <16
@@ -114,7 +114,6 @@ def calc_hexversion(major=0, minor=0, micro=0, releaselevel="dev", serial=0):
hexversion = calc_hexversion(*version_info)
-citation = "doi:10.5281/zenodo.1000472"
if __name__ == "__main__":
print(version)