datalab-platform 0.0.1.dev0__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- datalab/__init__.py +35 -2
- datalab/adapters_metadata/__init__.py +31 -0
- datalab/adapters_metadata/base_adapter.py +316 -0
- datalab/adapters_metadata/common.py +422 -0
- datalab/adapters_metadata/geometry_adapter.py +98 -0
- datalab/adapters_metadata/table_adapter.py +84 -0
- datalab/adapters_plotpy/__init__.py +54 -0
- datalab/adapters_plotpy/annotations.py +124 -0
- datalab/adapters_plotpy/base.py +110 -0
- datalab/adapters_plotpy/converters.py +86 -0
- datalab/adapters_plotpy/factories.py +80 -0
- datalab/adapters_plotpy/objects/__init__.py +0 -0
- datalab/adapters_plotpy/objects/base.py +197 -0
- datalab/adapters_plotpy/objects/image.py +157 -0
- datalab/adapters_plotpy/objects/scalar.py +565 -0
- datalab/adapters_plotpy/objects/signal.py +264 -0
- datalab/adapters_plotpy/roi/__init__.py +0 -0
- datalab/adapters_plotpy/roi/base.py +146 -0
- datalab/adapters_plotpy/roi/factory.py +93 -0
- datalab/adapters_plotpy/roi/image.py +207 -0
- datalab/adapters_plotpy/roi/signal.py +72 -0
- datalab/app.py +98 -0
- datalab/config.py +817 -0
- datalab/control/__init__.py +0 -0
- datalab/control/baseproxy.py +776 -0
- datalab/control/proxy.py +343 -0
- datalab/control/remote.py +1005 -0
- datalab/data/doc/DataLab_en.pdf +0 -0
- datalab/data/doc/DataLab_fr.pdf +0 -0
- datalab/data/icons/analysis/delete_results.svg +109 -0
- datalab/data/icons/analysis/fw1e2.svg +156 -0
- datalab/data/icons/analysis/fwhm.svg +156 -0
- datalab/data/icons/analysis/histogram.svg +49 -0
- datalab/data/icons/analysis/peak_detect.svg +160 -0
- datalab/data/icons/analysis/plot_results.svg +151 -0
- datalab/data/icons/analysis/show_results.svg +83 -0
- datalab/data/icons/analysis/stats.svg +49 -0
- datalab/data/icons/analysis.svg +120 -0
- datalab/data/icons/apply.svg +3 -0
- datalab/data/icons/check_all.svg +15 -0
- datalab/data/icons/collapse.svg +44 -0
- datalab/data/icons/collapse_selection.svg +63 -0
- datalab/data/icons/console.svg +101 -0
- datalab/data/icons/create/1d-normal.svg +8 -0
- datalab/data/icons/create/1d-poisson.svg +9 -0
- datalab/data/icons/create/1d-uniform.svg +8 -0
- datalab/data/icons/create/1d-zero.svg +57 -0
- datalab/data/icons/create/2d-gaussian.svg +56 -0
- datalab/data/icons/create/2d-normal.svg +38 -0
- datalab/data/icons/create/2d-poisson.svg +38 -0
- datalab/data/icons/create/2d-ramp.svg +90 -0
- datalab/data/icons/create/2d-sinc.svg +62 -0
- datalab/data/icons/create/2d-uniform.svg +38 -0
- datalab/data/icons/create/2d-zero.svg +13 -0
- datalab/data/icons/create/checkerboard.svg +39 -0
- datalab/data/icons/create/cosine.svg +12 -0
- datalab/data/icons/create/exponential.svg +55 -0
- datalab/data/icons/create/gaussian.svg +12 -0
- datalab/data/icons/create/grating.svg +29 -0
- datalab/data/icons/create/linear_chirp.svg +7 -0
- datalab/data/icons/create/logistic.svg +7 -0
- datalab/data/icons/create/lorentzian.svg +12 -0
- datalab/data/icons/create/planck.svg +12 -0
- datalab/data/icons/create/polynomial.svg +7 -0
- datalab/data/icons/create/pulse.svg +12 -0
- datalab/data/icons/create/ring.svg +18 -0
- datalab/data/icons/create/sawtooth.svg +7 -0
- datalab/data/icons/create/siemens.svg +35 -0
- datalab/data/icons/create/sinc.svg +12 -0
- datalab/data/icons/create/sine.svg +7 -0
- datalab/data/icons/create/square.svg +7 -0
- datalab/data/icons/create/square_pulse.svg +7 -0
- datalab/data/icons/create/step.svg +7 -0
- datalab/data/icons/create/step_pulse.svg +12 -0
- datalab/data/icons/create/triangle.svg +7 -0
- datalab/data/icons/create/voigt.svg +12 -0
- datalab/data/icons/edit/annotations.svg +72 -0
- datalab/data/icons/edit/annotations_copy.svg +114 -0
- datalab/data/icons/edit/annotations_delete.svg +83 -0
- datalab/data/icons/edit/annotations_edit.svg +98 -0
- datalab/data/icons/edit/annotations_export.svg +85 -0
- datalab/data/icons/edit/annotations_import.svg +85 -0
- datalab/data/icons/edit/annotations_paste.svg +100 -0
- datalab/data/icons/edit/copy_titles.svg +109 -0
- datalab/data/icons/edit/delete.svg +84 -0
- datalab/data/icons/edit/delete_all.svg +214 -0
- datalab/data/icons/edit/duplicate.svg +64 -0
- datalab/data/icons/edit/goto_source.svg +60 -0
- datalab/data/icons/edit/metadata.svg +60 -0
- datalab/data/icons/edit/metadata_add.svg +80 -0
- datalab/data/icons/edit/metadata_copy.svg +96 -0
- datalab/data/icons/edit/metadata_delete.svg +62 -0
- datalab/data/icons/edit/metadata_export.svg +68 -0
- datalab/data/icons/edit/metadata_import.svg +68 -0
- datalab/data/icons/edit/metadata_paste.svg +79 -0
- datalab/data/icons/edit/move_down.svg +55 -0
- datalab/data/icons/edit/move_up.svg +54 -0
- datalab/data/icons/edit/new_group.svg +76 -0
- datalab/data/icons/edit/recompute.svg +60 -0
- datalab/data/icons/edit/rename.svg +49 -0
- datalab/data/icons/edit.svg +16 -0
- datalab/data/icons/expand.svg +44 -0
- datalab/data/icons/expand_selection.svg +63 -0
- datalab/data/icons/fit/cdf_fit.svg +56 -0
- datalab/data/icons/fit/exponential_fit.svg +55 -0
- datalab/data/icons/fit/gaussian_fit.svg +62 -0
- datalab/data/icons/fit/interactive_fit.svg +101 -0
- datalab/data/icons/fit/linear_fit.svg +57 -0
- datalab/data/icons/fit/lorentzian_fit.svg +209 -0
- datalab/data/icons/fit/multigaussian_fit.svg +85 -0
- datalab/data/icons/fit/multilorentzian_fit.svg +85 -0
- datalab/data/icons/fit/piecewiseexponential_fit.svg +209 -0
- datalab/data/icons/fit/planckian_fit.svg +62 -0
- datalab/data/icons/fit/polynomial_fit.svg +59 -0
- datalab/data/icons/fit/sigmoid_fit.svg +56 -0
- datalab/data/icons/fit/sinusoidal_fit.svg +72 -0
- datalab/data/icons/fit/twohalfgaussian_fit.svg +63 -0
- datalab/data/icons/fit/voigt_fit.svg +57 -0
- datalab/data/icons/group.svg +56 -0
- datalab/data/icons/h5/h5array.svg +59 -0
- datalab/data/icons/h5/h5attrs.svg +75 -0
- datalab/data/icons/h5/h5browser.svg +133 -0
- datalab/data/icons/h5/h5file.svg +69 -0
- datalab/data/icons/h5/h5group.svg +49 -0
- datalab/data/icons/h5/h5scalar.svg +1 -0
- datalab/data/icons/help_pdf.svg +46 -0
- datalab/data/icons/history.svg +7 -0
- datalab/data/icons/image.svg +135 -0
- datalab/data/icons/io/fileopen_directory.svg +60 -0
- datalab/data/icons/io/fileopen_h5.svg +84 -0
- datalab/data/icons/io/fileopen_ima.svg +187 -0
- datalab/data/icons/io/fileopen_py.svg +123 -0
- datalab/data/icons/io/fileopen_sig.svg +138 -0
- datalab/data/icons/io/filesave_h5.svg +97 -0
- datalab/data/icons/io/filesave_ima.svg +200 -0
- datalab/data/icons/io/filesave_py.svg +136 -0
- datalab/data/icons/io/filesave_sig.svg +151 -0
- datalab/data/icons/io/import_text.svg +144 -0
- datalab/data/icons/io/save_to_directory.svg +134 -0
- datalab/data/icons/io.svg +84 -0
- datalab/data/icons/libre-camera-flash-off.svg +1 -0
- datalab/data/icons/libre-camera-flash-on.svg +1 -0
- datalab/data/icons/libre-gui-about.svg +1 -0
- datalab/data/icons/libre-gui-action-delete.svg +1 -0
- datalab/data/icons/libre-gui-add.svg +1 -0
- datalab/data/icons/libre-gui-arrow-down.svg +1 -0
- datalab/data/icons/libre-gui-arrow-left.svg +1 -0
- datalab/data/icons/libre-gui-arrow-right.svg +1 -0
- datalab/data/icons/libre-gui-arrow-up.svg +1 -0
- datalab/data/icons/libre-gui-close.svg +40 -0
- datalab/data/icons/libre-gui-cogs.svg +1 -0
- datalab/data/icons/libre-gui-globe.svg +1 -0
- datalab/data/icons/libre-gui-help.svg +1 -0
- datalab/data/icons/libre-gui-link.svg +1 -0
- datalab/data/icons/libre-gui-menu.svg +1 -0
- datalab/data/icons/libre-gui-pencil.svg +1 -0
- datalab/data/icons/libre-gui-plugin.svg +1 -0
- datalab/data/icons/libre-gui-questions.svg +1 -0
- datalab/data/icons/libre-gui-settings.svg +1 -0
- datalab/data/icons/libre-gui-unlink.svg +1 -0
- datalab/data/icons/libre-tech-ram.svg +1 -0
- datalab/data/icons/libre-toolbox.svg +1 -0
- datalab/data/icons/logs.svg +1 -0
- datalab/data/icons/markers.svg +74 -0
- datalab/data/icons/menu.svg +13 -0
- datalab/data/icons/new_ima.svg +148 -0
- datalab/data/icons/new_sig.svg +123 -0
- datalab/data/icons/operations/abs.svg +116 -0
- datalab/data/icons/operations/arithmetic.svg +123 -0
- datalab/data/icons/operations/average.svg +124 -0
- datalab/data/icons/operations/complex_from_magnitude_phase.svg +116 -0
- datalab/data/icons/operations/complex_from_real_imag.svg +124 -0
- datalab/data/icons/operations/constant.svg +116 -0
- datalab/data/icons/operations/constant_add.svg +109 -0
- datalab/data/icons/operations/constant_divide.svg +109 -0
- datalab/data/icons/operations/constant_multiply.svg +109 -0
- datalab/data/icons/operations/constant_subtract.svg +109 -0
- datalab/data/icons/operations/convert_dtype.svg +117 -0
- datalab/data/icons/operations/convolution.svg +46 -0
- datalab/data/icons/operations/deconvolution.svg +57 -0
- datalab/data/icons/operations/derivative.svg +127 -0
- datalab/data/icons/operations/difference.svg +52 -0
- datalab/data/icons/operations/division.svg +139 -0
- datalab/data/icons/operations/exp.svg +116 -0
- datalab/data/icons/operations/flip_horizontally.svg +69 -0
- datalab/data/icons/operations/flip_vertically.svg +74 -0
- datalab/data/icons/operations/im.svg +124 -0
- datalab/data/icons/operations/integral.svg +50 -0
- datalab/data/icons/operations/inverse.svg +143 -0
- datalab/data/icons/operations/log10.svg +109 -0
- datalab/data/icons/operations/phase.svg +116 -0
- datalab/data/icons/operations/power.svg +118 -0
- datalab/data/icons/operations/product.svg +124 -0
- datalab/data/icons/operations/profile.svg +379 -0
- datalab/data/icons/operations/profile_average.svg +399 -0
- datalab/data/icons/operations/profile_radial.svg +261 -0
- datalab/data/icons/operations/profile_segment.svg +262 -0
- datalab/data/icons/operations/quadratic_difference.svg +84 -0
- datalab/data/icons/operations/re.svg +124 -0
- datalab/data/icons/operations/rotate_left.svg +72 -0
- datalab/data/icons/operations/rotate_right.svg +72 -0
- datalab/data/icons/operations/signals_to_image.svg +314 -0
- datalab/data/icons/operations/sqrt.svg +110 -0
- datalab/data/icons/operations/std.svg +124 -0
- datalab/data/icons/operations/sum.svg +102 -0
- datalab/data/icons/play_demo.svg +9 -0
- datalab/data/icons/processing/axis_transform.svg +62 -0
- datalab/data/icons/processing/bandpass.svg +79 -0
- datalab/data/icons/processing/bandstop.svg +71 -0
- datalab/data/icons/processing/binning.svg +126 -0
- datalab/data/icons/processing/clip.svg +119 -0
- datalab/data/icons/processing/detrending.svg +173 -0
- datalab/data/icons/processing/distribute_on_grid.svg +769 -0
- datalab/data/icons/processing/edge_detection.svg +46 -0
- datalab/data/icons/processing/erase.svg +1 -0
- datalab/data/icons/processing/exposure.svg +143 -0
- datalab/data/icons/processing/fourier.svg +104 -0
- datalab/data/icons/processing/highpass.svg +59 -0
- datalab/data/icons/processing/interpolation.svg +71 -0
- datalab/data/icons/processing/level_adjustment.svg +70 -0
- datalab/data/icons/processing/lowpass.svg +60 -0
- datalab/data/icons/processing/morphology.svg +49 -0
- datalab/data/icons/processing/noise_addition.svg +114 -0
- datalab/data/icons/processing/noise_reduction.svg +38 -0
- datalab/data/icons/processing/normalize.svg +84 -0
- datalab/data/icons/processing/offset_correction.svg +131 -0
- datalab/data/icons/processing/resampling1d.svg +101 -0
- datalab/data/icons/processing/resampling2d.svg +240 -0
- datalab/data/icons/processing/reset_positions.svg +185 -0
- datalab/data/icons/processing/resize.svg +9 -0
- datalab/data/icons/processing/reverse_signal_x.svg +171 -0
- datalab/data/icons/processing/stability.svg +11 -0
- datalab/data/icons/processing/swap_x_y.svg +65 -0
- datalab/data/icons/processing/thresholding.svg +63 -0
- datalab/data/icons/processing/windowing.svg +45 -0
- datalab/data/icons/properties.svg +26 -0
- datalab/data/icons/reset.svg +9 -0
- datalab/data/icons/restore.svg +40 -0
- datalab/data/icons/roi/roi.svg +76 -0
- datalab/data/icons/roi/roi_coordinate.svg +78 -0
- datalab/data/icons/roi/roi_copy.svg +112 -0
- datalab/data/icons/roi/roi_delete.svg +81 -0
- datalab/data/icons/roi/roi_export.svg +87 -0
- datalab/data/icons/roi/roi_graphical.svg +78 -0
- datalab/data/icons/roi/roi_grid.svg +67 -0
- datalab/data/icons/roi/roi_ima.svg +188 -0
- datalab/data/icons/roi/roi_import.svg +87 -0
- datalab/data/icons/roi/roi_new.svg +81 -0
- datalab/data/icons/roi/roi_new_circle.svg +95 -0
- datalab/data/icons/roi/roi_new_polygon.svg +110 -0
- datalab/data/icons/roi/roi_new_rectangle.svg +70 -0
- datalab/data/icons/roi/roi_paste.svg +98 -0
- datalab/data/icons/roi/roi_sig.svg +124 -0
- datalab/data/icons/shapes.svg +134 -0
- datalab/data/icons/signal.svg +103 -0
- datalab/data/icons/table.svg +85 -0
- datalab/data/icons/table_unavailable.svg +102 -0
- datalab/data/icons/to_signal.svg +124 -0
- datalab/data/icons/tour/next.svg +44 -0
- datalab/data/icons/tour/previous.svg +44 -0
- datalab/data/icons/tour/rewind.svg +51 -0
- datalab/data/icons/tour/stop.svg +47 -0
- datalab/data/icons/tour/tour.svg +16 -0
- datalab/data/icons/uncheck_all.svg +78 -0
- datalab/data/icons/view/curve_antialiasing.svg +50 -0
- datalab/data/icons/view/new_window.svg +98 -0
- datalab/data/icons/view/refresh-auto.svg +57 -0
- datalab/data/icons/view/refresh-manual.svg +51 -0
- datalab/data/icons/view/reset_curve_styles.svg +96 -0
- datalab/data/icons/view/show_first.svg +55 -0
- datalab/data/icons/view/show_titles.svg +46 -0
- datalab/data/icons/visualization.svg +51 -0
- datalab/data/logo/DataLab-Banner-150.png +0 -0
- datalab/data/logo/DataLab-Banner-200.png +0 -0
- datalab/data/logo/DataLab-Banner2-100.png +0 -0
- datalab/data/logo/DataLab-Splash.png +0 -0
- datalab/data/logo/DataLab-watermark.png +0 -0
- datalab/data/logo/DataLab.svg +83 -0
- datalab/data/tests/reordering_test.h5 +0 -0
- datalab/data/tutorials/fabry_perot/fabry-perot1.jpg +0 -0
- datalab/data/tutorials/fabry_perot/fabry-perot2.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_13.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_18.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_23.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_30.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_35.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_40.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_45.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_50.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_55.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_60.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_65.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_70.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_75.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_80.jpg +0 -0
- datalab/env.py +542 -0
- datalab/gui/__init__.py +89 -0
- datalab/gui/actionhandler.py +1701 -0
- datalab/gui/docks.py +473 -0
- datalab/gui/h5io.py +150 -0
- datalab/gui/macroeditor.py +310 -0
- datalab/gui/main.py +2081 -0
- datalab/gui/newobject.py +217 -0
- datalab/gui/objectview.py +766 -0
- datalab/gui/panel/__init__.py +48 -0
- datalab/gui/panel/base.py +3254 -0
- datalab/gui/panel/image.py +157 -0
- datalab/gui/panel/macro.py +607 -0
- datalab/gui/panel/signal.py +164 -0
- datalab/gui/plothandler.py +800 -0
- datalab/gui/processor/__init__.py +84 -0
- datalab/gui/processor/base.py +2456 -0
- datalab/gui/processor/catcher.py +75 -0
- datalab/gui/processor/image.py +1214 -0
- datalab/gui/processor/signal.py +755 -0
- datalab/gui/profiledialog.py +333 -0
- datalab/gui/roieditor.py +633 -0
- datalab/gui/roigrideditor.py +208 -0
- datalab/gui/settings.py +612 -0
- datalab/gui/tour.py +908 -0
- datalab/h5/__init__.py +12 -0
- datalab/h5/common.py +314 -0
- datalab/h5/generic.py +580 -0
- datalab/h5/native.py +39 -0
- datalab/h5/utils.py +95 -0
- datalab/objectmodel.py +640 -0
- datalab/plugins/_readme_.txt +9 -0
- datalab/plugins/datalab_imageformats.py +175 -0
- datalab/plugins/datalab_testdata.py +190 -0
- datalab/plugins.py +355 -0
- datalab/tests/__init__.py +199 -0
- datalab/tests/backbone/__init__.py +1 -0
- datalab/tests/backbone/config_unit_test.py +170 -0
- datalab/tests/backbone/config_versioning_unit_test.py +34 -0
- datalab/tests/backbone/dictlistserial_app_test.py +38 -0
- datalab/tests/backbone/errorcatcher_unit_test.py +69 -0
- datalab/tests/backbone/errormsgbox_unit_test.py +50 -0
- datalab/tests/backbone/execenv_unit.py +262 -0
- datalab/tests/backbone/loadtest_gdi.py +147 -0
- datalab/tests/backbone/long_callback.py +96 -0
- datalab/tests/backbone/main_app_test.py +137 -0
- datalab/tests/backbone/memory_leak.py +43 -0
- datalab/tests/backbone/procisolation1_unit.py +128 -0
- datalab/tests/backbone/procisolation2_unit.py +171 -0
- datalab/tests/backbone/procisolation_unit_test.py +22 -0
- datalab/tests/backbone/profiling_app.py +27 -0
- datalab/tests/backbone/strings_unit_test.py +65 -0
- datalab/tests/backbone/title_formatting_unit_test.py +82 -0
- datalab/tests/conftest.py +131 -0
- datalab/tests/features/__init__.py +1 -0
- datalab/tests/features/applauncher/__init__.py +1 -0
- datalab/tests/features/applauncher/launcher1_app_test.py +28 -0
- datalab/tests/features/applauncher/launcher2_app_test.py +30 -0
- datalab/tests/features/common/__init__.py +1 -0
- datalab/tests/features/common/add_metadata_app_test.py +134 -0
- datalab/tests/features/common/add_metadata_unit_test.py +267 -0
- datalab/tests/features/common/annotations_management_unit_test.py +152 -0
- datalab/tests/features/common/auto_analysis_recompute_unit_test.py +240 -0
- datalab/tests/features/common/createobject_unit_test.py +50 -0
- datalab/tests/features/common/geometry_results_app_test.py +135 -0
- datalab/tests/features/common/interactive_processing_test.py +1109 -0
- datalab/tests/features/common/io_app_test.py +75 -0
- datalab/tests/features/common/large_results_app_test.py +187 -0
- datalab/tests/features/common/metadata_all_patterns_test.py +103 -0
- datalab/tests/features/common/metadata_app_test.py +139 -0
- datalab/tests/features/common/metadata_io_unit_test.py +60 -0
- datalab/tests/features/common/misc_app_test.py +236 -0
- datalab/tests/features/common/multiple_geometry_results_unit_test.py +122 -0
- datalab/tests/features/common/multiple_table_results_unit_test.py +64 -0
- datalab/tests/features/common/operation_modes_app_test.py +392 -0
- datalab/tests/features/common/plot_results_app_test.py +278 -0
- datalab/tests/features/common/reorder_app_test.py +75 -0
- datalab/tests/features/common/result_deletion_unit_test.py +96 -0
- datalab/tests/features/common/result_merged_label_unit_test.py +154 -0
- datalab/tests/features/common/result_shape_settings_unit_test.py +223 -0
- datalab/tests/features/common/roi_plotitem_unit_test.py +64 -0
- datalab/tests/features/common/roieditor_unit_test.py +102 -0
- datalab/tests/features/common/save_to_dir_app_test.py +163 -0
- datalab/tests/features/common/save_to_dir_unit_test.py +474 -0
- datalab/tests/features/common/stat_app_test.py +40 -0
- datalab/tests/features/common/stats_tools_unit_test.py +77 -0
- datalab/tests/features/common/table_results_app_test.py +52 -0
- datalab/tests/features/common/textimport_unit_test.py +131 -0
- datalab/tests/features/common/uuid_preservation_test.py +281 -0
- datalab/tests/features/common/worker_unit_test.py +402 -0
- datalab/tests/features/control/__init__.py +1 -0
- datalab/tests/features/control/connect_dialog.py +28 -0
- datalab/tests/features/control/embedded1_unit_test.py +304 -0
- datalab/tests/features/control/embedded2_unit_test.py +52 -0
- datalab/tests/features/control/remoteclient_app_test.py +219 -0
- datalab/tests/features/control/remoteclient_unit.py +75 -0
- datalab/tests/features/control/simpleclient_unit_test.py +321 -0
- datalab/tests/features/hdf5/__init__.py +1 -0
- datalab/tests/features/hdf5/h5browser1_unit_test.py +31 -0
- datalab/tests/features/hdf5/h5browser2_unit.py +55 -0
- datalab/tests/features/hdf5/h5browser_app_test.py +77 -0
- datalab/tests/features/hdf5/h5import_app_test.py +25 -0
- datalab/tests/features/hdf5/h5importer_app_test.py +34 -0
- datalab/tests/features/image/__init__.py +1 -0
- datalab/tests/features/image/annotations_app_test.py +28 -0
- datalab/tests/features/image/annotations_unit_test.py +80 -0
- datalab/tests/features/image/average_app_test.py +46 -0
- datalab/tests/features/image/background_dialog_test.py +70 -0
- datalab/tests/features/image/blobs_app_test.py +50 -0
- datalab/tests/features/image/contour_app_test.py +42 -0
- datalab/tests/features/image/contour_fabryperot_app_test.py +51 -0
- datalab/tests/features/image/denoise_app_test.py +31 -0
- datalab/tests/features/image/distribute_on_grid_app_test.py +95 -0
- datalab/tests/features/image/edges_app_test.py +31 -0
- datalab/tests/features/image/erase_app_test.py +21 -0
- datalab/tests/features/image/fft2d_app_test.py +27 -0
- datalab/tests/features/image/flatfield_app_test.py +40 -0
- datalab/tests/features/image/geometry_transform_unit_test.py +396 -0
- datalab/tests/features/image/imagetools_app_test.py +51 -0
- datalab/tests/features/image/imagetools_unit_test.py +27 -0
- datalab/tests/features/image/load_app_test.py +73 -0
- datalab/tests/features/image/morph_app_test.py +32 -0
- datalab/tests/features/image/offsetcorrection_app_test.py +30 -0
- datalab/tests/features/image/peak2d_app_test.py +53 -0
- datalab/tests/features/image/profile_app_test.py +73 -0
- datalab/tests/features/image/profile_dialog_test.py +56 -0
- datalab/tests/features/image/roi_app_test.py +98 -0
- datalab/tests/features/image/roi_circ_app_test.py +62 -0
- datalab/tests/features/image/roi_manipulation_app_test.py +268 -0
- datalab/tests/features/image/roigrid_unit_test.py +60 -0
- datalab/tests/features/image/side_by_side_app_test.py +52 -0
- datalab/tests/features/macro/__init__.py +1 -0
- datalab/tests/features/macro/macro_app_test.py +28 -0
- datalab/tests/features/macro/macroeditor_unit_test.py +102 -0
- datalab/tests/features/signal/__init__.py +1 -0
- datalab/tests/features/signal/baseline_dialog_test.py +53 -0
- datalab/tests/features/signal/deltax_dialog_unit_test.py +34 -0
- datalab/tests/features/signal/fft1d_app_test.py +26 -0
- datalab/tests/features/signal/filter_app_test.py +44 -0
- datalab/tests/features/signal/fitdialog_unit_test.py +50 -0
- datalab/tests/features/signal/interpolation_app_test.py +110 -0
- datalab/tests/features/signal/loadbigsignal_app_test.py +80 -0
- datalab/tests/features/signal/multiple_rois_unit_test.py +132 -0
- datalab/tests/features/signal/pulse_features_app_test.py +118 -0
- datalab/tests/features/signal/pulse_features_roi_app_test.py +55 -0
- datalab/tests/features/signal/roi_app_test.py +78 -0
- datalab/tests/features/signal/roi_manipulation_app_test.py +261 -0
- datalab/tests/features/signal/select_xy_cursor_unit_test.py +46 -0
- datalab/tests/features/signal/signalpeakdetection_dialog_test.py +33 -0
- datalab/tests/features/signal/signals_to_image_app_test.py +98 -0
- datalab/tests/features/signal/xarray_compat_app_test.py +128 -0
- datalab/tests/features/tour_unit_test.py +22 -0
- datalab/tests/features/utilities/__init__.py +1 -0
- datalab/tests/features/utilities/installconf_unit_test.py +21 -0
- datalab/tests/features/utilities/logview_app_test.py +21 -0
- datalab/tests/features/utilities/logview_error.py +24 -0
- datalab/tests/features/utilities/logview_unit_test.py +21 -0
- datalab/tests/features/utilities/memstatus_app_test.py +42 -0
- datalab/tests/features/utilities/settings_unit_test.py +88 -0
- datalab/tests/scenarios/__init__.py +1 -0
- datalab/tests/scenarios/beautiful_app.py +121 -0
- datalab/tests/scenarios/common.py +463 -0
- datalab/tests/scenarios/demo.py +212 -0
- datalab/tests/scenarios/example_app_test.py +47 -0
- datalab/tests/scenarios/scenario_h5_app_test.py +75 -0
- datalab/tests/scenarios/scenario_ima1_app_test.py +34 -0
- datalab/tests/scenarios/scenario_ima2_app_test.py +34 -0
- datalab/tests/scenarios/scenario_mac_app_test.py +58 -0
- datalab/tests/scenarios/scenario_sig1_app_test.py +36 -0
- datalab/tests/scenarios/scenario_sig2_app_test.py +35 -0
- datalab/utils/__init__.py +1 -0
- datalab/utils/conf.py +304 -0
- datalab/utils/dephash.py +105 -0
- datalab/utils/qthelpers.py +633 -0
- datalab/utils/strings.py +34 -0
- datalab/utils/tests.py +0 -0
- datalab/widgets/__init__.py +1 -0
- datalab/widgets/connection.py +138 -0
- datalab/widgets/filedialog.py +91 -0
- datalab/widgets/fileviewer.py +84 -0
- datalab/widgets/fitdialog.py +788 -0
- datalab/widgets/h5browser.py +1048 -0
- datalab/widgets/imagebackground.py +111 -0
- datalab/widgets/instconfviewer.py +175 -0
- datalab/widgets/logviewer.py +80 -0
- datalab/widgets/signalbaseline.py +90 -0
- datalab/widgets/signalcursor.py +208 -0
- datalab/widgets/signaldeltax.py +151 -0
- datalab/widgets/signalpeak.py +199 -0
- datalab/widgets/status.py +249 -0
- datalab/widgets/textimport.py +786 -0
- datalab/widgets/warningerror.py +223 -0
- datalab/widgets/wizard.py +286 -0
- datalab_platform-1.0.0.dist-info/METADATA +121 -0
- datalab_platform-1.0.0.dist-info/RECORD +494 -0
- datalab_platform-0.0.1.dev0.dist-info/METADATA +0 -67
- datalab_platform-0.0.1.dev0.dist-info/RECORD +0 -7
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/WHEEL +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/entry_points.txt +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Example of high-level test scenario
|
|
5
|
+
|
|
6
|
+
Create an image object from Scikit-image human mitosis sample,
|
|
7
|
+
then open DataLab to show it.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
|
|
11
|
+
# guitest: show
|
|
12
|
+
|
|
13
|
+
import sigima.objects
|
|
14
|
+
import sigima.params
|
|
15
|
+
from sigima.tests.data import get_test_image
|
|
16
|
+
|
|
17
|
+
from datalab.control.proxy import proxy_context
|
|
18
|
+
from datalab.tests import skip_if_opencv_missing
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_example_app() -> None:
|
|
22
|
+
"""Example of high-level test scenario using proxy interface"""
|
|
23
|
+
with proxy_context("local") as proxy:
|
|
24
|
+
data = get_test_image("flower.npy").data
|
|
25
|
+
image = sigima.objects.create_image("Test image with peaks", data)
|
|
26
|
+
proxy.add_object(image)
|
|
27
|
+
proxy.calc("roberts")
|
|
28
|
+
data_size = data.shape[0]
|
|
29
|
+
n = data_size // 5
|
|
30
|
+
roi = sigima.objects.create_image_roi(
|
|
31
|
+
"rectangle", [n, n, data_size - 2 * n, data_size - 2 * n]
|
|
32
|
+
)
|
|
33
|
+
proxy.calc("compute_roi_extraction", roi)
|
|
34
|
+
param = sigima.params.BlobOpenCVParam.create(
|
|
35
|
+
min_dist_between_blobs=0.1,
|
|
36
|
+
filter_by_color=False,
|
|
37
|
+
min_area=500,
|
|
38
|
+
max_area=2000,
|
|
39
|
+
filter_by_circularity=True,
|
|
40
|
+
min_circularity=0.2,
|
|
41
|
+
)
|
|
42
|
+
with skip_if_opencv_missing():
|
|
43
|
+
proxy.calc("blob_opencv", param)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
test_example_app()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
DataLab mainwindow automation test
|
|
5
|
+
----------------------------------
|
|
6
|
+
|
|
7
|
+
This test scenario shows how to use the DataLab application in a test
|
|
8
|
+
scenario. It also validates the HDF5 file format.
|
|
9
|
+
|
|
10
|
+
This scenario executes the following steps:
|
|
11
|
+
|
|
12
|
+
- Creating two test signals
|
|
13
|
+
- Creating two test images
|
|
14
|
+
- Creating a macro
|
|
15
|
+
- Saving current project (h5 file)
|
|
16
|
+
- Removing all objects
|
|
17
|
+
- Opening another project (h5 file)
|
|
18
|
+
- Access current image metadata
|
|
19
|
+
- Checking macro code
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
|
|
23
|
+
# guitest: show
|
|
24
|
+
|
|
25
|
+
import os.path as osp
|
|
26
|
+
|
|
27
|
+
from sigima.params import ClipParam
|
|
28
|
+
from sigima.tests.data import create_noisy_gaussian_image, create_paracetamol_signal
|
|
29
|
+
|
|
30
|
+
from datalab.env import execenv
|
|
31
|
+
from datalab.tests import datalab_test_app_context, helpers
|
|
32
|
+
from datalab.tests.scenarios import scenario_mac_app_test
|
|
33
|
+
from datalab.utils.strings import save_html_diff
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_scenario_h5():
|
|
37
|
+
"""Example of high-level test scenario with HDF5 file"""
|
|
38
|
+
with helpers.WorkdirRestoringTempDir() as tmpdir:
|
|
39
|
+
with datalab_test_app_context(console=False) as win:
|
|
40
|
+
# === Creating two test signals
|
|
41
|
+
panel = win.signalpanel
|
|
42
|
+
sig1 = create_paracetamol_signal()
|
|
43
|
+
panel.add_object(sig1)
|
|
44
|
+
panel.processor.run_feature("derivative")
|
|
45
|
+
# === Creating two test images
|
|
46
|
+
panel = win.imagepanel
|
|
47
|
+
ima1 = create_noisy_gaussian_image(add_annotations=True)
|
|
48
|
+
panel.add_object(ima1)
|
|
49
|
+
param = ClipParam.create(upper=ima1.data.mean())
|
|
50
|
+
panel.processor.run_feature("clip", param)
|
|
51
|
+
# === Creating a macro
|
|
52
|
+
scode = scenario_mac_app_test.add_macro_sample(win, 0).get_code()
|
|
53
|
+
scenario_mac_app_test.add_macro_sample(win, 1)
|
|
54
|
+
# === Saving project
|
|
55
|
+
fname = osp.join(tmpdir, "test.h5")
|
|
56
|
+
win.save_to_h5_file(fname)
|
|
57
|
+
# === Removing all objects
|
|
58
|
+
for panel in win.panels:
|
|
59
|
+
panel.remove_all_objects()
|
|
60
|
+
# === Reopening previously saved project
|
|
61
|
+
win.open_h5_files([fname], import_all=True, reset_all=True)
|
|
62
|
+
# === Accessing object metadata
|
|
63
|
+
obj = win.imagepanel.objmodel.get_groups()[0][0]
|
|
64
|
+
execenv.print(f"Image '{obj.title}':")
|
|
65
|
+
for key, value in obj.metadata.items():
|
|
66
|
+
execenv.print(f' metadata["{key}"] = {value}')
|
|
67
|
+
# === Checking macro code
|
|
68
|
+
lcode = win.macropanel.get_macro(1).get_code()
|
|
69
|
+
if lcode != scode:
|
|
70
|
+
save_html_diff(scode, lcode, "Saved code", "Loaded code", "macro0.html")
|
|
71
|
+
raise AssertionError("Macro code is not the same as saved")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
if __name__ == "__main__":
|
|
75
|
+
test_scenario_h5()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Image processing test scenario
|
|
5
|
+
------------------------------
|
|
6
|
+
|
|
7
|
+
Testing all the image processing features, without process isolation.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# pylint: disable=duplicate-code
|
|
11
|
+
# guitest: show
|
|
12
|
+
|
|
13
|
+
from datalab.config import Conf
|
|
14
|
+
from datalab.env import execenv
|
|
15
|
+
from datalab.tests import datalab_test_app_context
|
|
16
|
+
from datalab.tests.scenarios import common
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_scenario_image() -> None:
|
|
20
|
+
"""Run image unit test scenario 1 (no process isolation)"""
|
|
21
|
+
assert Conf.main.process_isolation_enabled.get(), (
|
|
22
|
+
"Process isolation must be enabled"
|
|
23
|
+
)
|
|
24
|
+
with datalab_test_app_context(save=True) as win:
|
|
25
|
+
with win.context_no_refresh():
|
|
26
|
+
execenv.print("Testing image features without process isolation...")
|
|
27
|
+
win.set_process_isolation_enabled(False)
|
|
28
|
+
common.run_image_computations(win)
|
|
29
|
+
win.imagepanel.remove_all_objects()
|
|
30
|
+
execenv.print("==> OK")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
test_scenario_image()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Image processing test scenario
|
|
5
|
+
------------------------------
|
|
6
|
+
|
|
7
|
+
Testing all the image processing features, with process isolation.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# pylint: disable=duplicate-code
|
|
11
|
+
# guitest: show
|
|
12
|
+
|
|
13
|
+
from datalab.config import Conf
|
|
14
|
+
from datalab.env import execenv
|
|
15
|
+
from datalab.tests import datalab_test_app_context
|
|
16
|
+
from datalab.tests.scenarios import common
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_scenario_image2() -> None:
|
|
20
|
+
"""Run image unit test scenario 2 (process isolation)"""
|
|
21
|
+
assert Conf.main.process_isolation_enabled.get(), (
|
|
22
|
+
"Process isolation must be enabled"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
with datalab_test_app_context(save=True) as win:
|
|
26
|
+
execenv.print("Testing image features *with* process isolation...")
|
|
27
|
+
common.run_image_computations(win, all_types=False)
|
|
28
|
+
oids = win.imagepanel.objmodel.get_object_ids()
|
|
29
|
+
win.imagepanel.open_separate_view(oids[:4])
|
|
30
|
+
execenv.print("==> OK")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
test_scenario_image2()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Macro-commands test scenario
|
|
5
|
+
----------------------------
|
|
6
|
+
|
|
7
|
+
Testing all the macro-commands features.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
|
|
11
|
+
# guitest: show
|
|
12
|
+
|
|
13
|
+
import os.path as osp
|
|
14
|
+
import time
|
|
15
|
+
|
|
16
|
+
from datalab.gui.macroeditor import Macro
|
|
17
|
+
from datalab.gui.main import DLMainWindow
|
|
18
|
+
from datalab.tests import datalab_test_app_context, helpers
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def add_macro_sample(win: DLMainWindow, index: int) -> Macro:
|
|
22
|
+
"""Add a macro sample to the macro panel
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
win: DLMainWindow
|
|
26
|
+
index: index of the macro sample to add
|
|
27
|
+
"""
|
|
28
|
+
macro = win.macropanel.add_macro()
|
|
29
|
+
macro.title = f"Test macro {index}"
|
|
30
|
+
samples = [
|
|
31
|
+
"import time; [print(f'{i}:{time.sleep(.1)}') for i in range(50)]",
|
|
32
|
+
"print('Hello world')",
|
|
33
|
+
]
|
|
34
|
+
assert index < len(samples), f"index={index} is out of range"
|
|
35
|
+
macro.set_code(samples[index])
|
|
36
|
+
return macro
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_scenario_macro() -> None:
|
|
40
|
+
"""Example of high-level test scenario with HDF5 file"""
|
|
41
|
+
with helpers.WorkdirRestoringTempDir() as tmpdir:
|
|
42
|
+
with datalab_test_app_context(console=False) as win:
|
|
43
|
+
win.set_current_panel("macro")
|
|
44
|
+
add_macro_sample(win, 0)
|
|
45
|
+
win.macropanel.run_macro()
|
|
46
|
+
time.sleep(1)
|
|
47
|
+
win.macropanel.stop_macro()
|
|
48
|
+
code2 = add_macro_sample(win, 1).get_code()
|
|
49
|
+
fname = osp.join(tmpdir, "test.macro")
|
|
50
|
+
win.macropanel.export_macro_to_file(2, fname)
|
|
51
|
+
win.macropanel.remove_macro()
|
|
52
|
+
macro_nb = win.macropanel.import_macro_from_file(fname)
|
|
53
|
+
macro2 = win.macropanel.get_macro(macro_nb)
|
|
54
|
+
assert macro2.get_code() == code2, "Macro code is not the same"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
test_scenario_macro()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Signal processing test scenario
|
|
5
|
+
-------------------------------
|
|
6
|
+
|
|
7
|
+
Testing all the signal processing features, without process isolation.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# pylint: disable=duplicate-code
|
|
11
|
+
# guitest: show
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from datalab.config import Conf
|
|
16
|
+
from datalab.env import execenv
|
|
17
|
+
from datalab.tests import datalab_test_app_context
|
|
18
|
+
from datalab.tests.scenarios import common
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_scenario_signal1() -> None:
|
|
22
|
+
"""Run signal unit test scenario 1 (no process isolation)"""
|
|
23
|
+
assert Conf.main.process_isolation_enabled.get(), (
|
|
24
|
+
"Process isolation must be enabled"
|
|
25
|
+
)
|
|
26
|
+
with datalab_test_app_context(save=True) as win:
|
|
27
|
+
with win.context_no_refresh():
|
|
28
|
+
execenv.print("Testing signal features (process isolation: off)...")
|
|
29
|
+
win.set_process_isolation_enabled(False)
|
|
30
|
+
common.run_signal_computations(win, all_types=True)
|
|
31
|
+
win.signalpanel.remove_all_objects()
|
|
32
|
+
execenv.print("==> OK")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
test_scenario_signal1()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Signal processing test scenario
|
|
5
|
+
-------------------------------
|
|
6
|
+
|
|
7
|
+
Testing all the signal processing features, with process isolation.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# pylint: disable=duplicate-code
|
|
11
|
+
# guitest: show
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from datalab.config import Conf
|
|
16
|
+
from datalab.env import execenv
|
|
17
|
+
from datalab.tests import datalab_test_app_context
|
|
18
|
+
from datalab.tests.scenarios import common
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_scenario_signal2() -> None:
|
|
22
|
+
"""Run signal unit test scenario 2 (process isolation)"""
|
|
23
|
+
assert Conf.main.process_isolation_enabled.get(), (
|
|
24
|
+
"Process isolation must be enabled"
|
|
25
|
+
)
|
|
26
|
+
with datalab_test_app_context(save=True) as win:
|
|
27
|
+
execenv.print("Testing signal features (process isolation: on)...")
|
|
28
|
+
common.run_signal_computations(win, all_types=False)
|
|
29
|
+
oids = win.signalpanel.objmodel.get_object_ids()
|
|
30
|
+
win.signalpanel.open_separate_view(oids[:3])
|
|
31
|
+
execenv.print("==> OK")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
if __name__ == "__main__":
|
|
35
|
+
test_scenario_signal2()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#
|
datalab/utils/conf.py
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
DataLab Configuration utilities
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import os.path as osp
|
|
11
|
+
import warnings
|
|
12
|
+
from collections.abc import Generator
|
|
13
|
+
from contextlib import contextmanager
|
|
14
|
+
from typing import TYPE_CHECKING, Any
|
|
15
|
+
|
|
16
|
+
import guidata.dataset as gds
|
|
17
|
+
from guidata.configtools import MONOSPACE, get_family
|
|
18
|
+
from guidata.userconfig import NoDefault, UserConfig
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
import qtpy.QtGui as QG
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AppUserConfig(UserConfig):
|
|
25
|
+
"""Application user configuration"""
|
|
26
|
+
|
|
27
|
+
def to_dict(self) -> dict:
|
|
28
|
+
"""Return configuration as a dictionary"""
|
|
29
|
+
confdict = {}
|
|
30
|
+
for section in self.sections():
|
|
31
|
+
secdict = {}
|
|
32
|
+
for option, value in self.items(section, raw=self.raw):
|
|
33
|
+
secdict[option] = value
|
|
34
|
+
confdict[section] = secdict
|
|
35
|
+
return confdict
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
CONF = AppUserConfig({})
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Configuration:
|
|
42
|
+
"""Configuration file"""
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def initialize(cls, name: str, version: str, load: bool) -> None:
|
|
46
|
+
"""Initialize configuration"""
|
|
47
|
+
CONF.set_application(name, version, load=load)
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def reset(cls) -> None:
|
|
51
|
+
"""Reset configuration"""
|
|
52
|
+
global CONF # pylint: disable=global-statement
|
|
53
|
+
CONF.cleanup() # Remove configuration file
|
|
54
|
+
CONF = AppUserConfig({})
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def get_filename(cls) -> str:
|
|
58
|
+
"""Return configuration file name"""
|
|
59
|
+
return CONF.filename()
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def get_path(cls, basename: str) -> str:
|
|
63
|
+
"""Return filename path inside configuration directory"""
|
|
64
|
+
return CONF.get_path(basename)
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def to_dict(cls) -> dict:
|
|
68
|
+
"""Return configuration as a dictionary"""
|
|
69
|
+
return CONF.to_dict()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class Section:
|
|
73
|
+
"""Configuration section"""
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def set_name(cls, section: str) -> None:
|
|
77
|
+
"""Set section name"""
|
|
78
|
+
cls._name = section
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def get_name(cls) -> str:
|
|
82
|
+
"""Return section name"""
|
|
83
|
+
return cls._name
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class Option:
|
|
87
|
+
"""Configuration option handler"""
|
|
88
|
+
|
|
89
|
+
def __init__(self) -> None:
|
|
90
|
+
self.section = None
|
|
91
|
+
self.option = None
|
|
92
|
+
|
|
93
|
+
def get(self, default=NoDefault) -> Any:
|
|
94
|
+
"""Get configuration option value"""
|
|
95
|
+
return CONF.get(self.section, self.option, default)
|
|
96
|
+
|
|
97
|
+
def set(self, value: Any) -> None:
|
|
98
|
+
"""Set configuration option value"""
|
|
99
|
+
CONF.set(self.section, self.option, value)
|
|
100
|
+
|
|
101
|
+
def remove(self) -> None:
|
|
102
|
+
"""Remove configuration option"""
|
|
103
|
+
# No use case for this method yet (quite dangerous!)
|
|
104
|
+
CONF.remove_option(self.section, self.option)
|
|
105
|
+
|
|
106
|
+
@contextmanager
|
|
107
|
+
def temp(self, value: Any) -> Generator[None, None, None]:
|
|
108
|
+
"""Temporarily set configuration option value
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
value: new value
|
|
112
|
+
"""
|
|
113
|
+
old_value = self.get()
|
|
114
|
+
self.set(value)
|
|
115
|
+
yield
|
|
116
|
+
self.set(old_value)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class FontOption(Option):
|
|
120
|
+
"""Font configuration option handler"""
|
|
121
|
+
|
|
122
|
+
def get(self, default=NoDefault) -> str:
|
|
123
|
+
"""Get font name from configuration"""
|
|
124
|
+
if default is NoDefault:
|
|
125
|
+
default = (MONOSPACE, 9, False)
|
|
126
|
+
family = CONF.get(self.section, self.option + "_family", default[0])
|
|
127
|
+
size = CONF.get(self.section, self.option + "_size", default[1])
|
|
128
|
+
bold = CONF.get(self.section, self.option + "_bold", default[2])
|
|
129
|
+
return family, size, bold
|
|
130
|
+
|
|
131
|
+
def set(self, value: tuple[str | list[str], int, bool]) -> None:
|
|
132
|
+
"""Set font name in configuration"""
|
|
133
|
+
assert isinstance(value, tuple), (
|
|
134
|
+
"Font value must be a tuple (family, size, bold)"
|
|
135
|
+
)
|
|
136
|
+
CONF.set(self.section, self.option + "_family", value[0])
|
|
137
|
+
CONF.set(self.section, self.option + "_size", value[1])
|
|
138
|
+
CONF.set(self.section, self.option + "_bold", value[2])
|
|
139
|
+
|
|
140
|
+
def get_font(self) -> QG.QFont:
|
|
141
|
+
"""Get QFont from configuration"""
|
|
142
|
+
# Import here to avoid having to create a Qt application when
|
|
143
|
+
# just manipulating configuration files
|
|
144
|
+
from qtpy import QtGui as QG # pylint: disable=import-outside-toplevel
|
|
145
|
+
|
|
146
|
+
family, size, bold = self.get()
|
|
147
|
+
if isinstance(family, (list, tuple)):
|
|
148
|
+
family = get_family(family)
|
|
149
|
+
return QG.QFont(family, size, QG.QFont.Bold if bold else QG.QFont.Normal)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class ConfigPathOption(Option):
|
|
153
|
+
"""Configuration file path configuration option handler"""
|
|
154
|
+
|
|
155
|
+
def get(self, default=NoDefault) -> str:
|
|
156
|
+
"""Get configuration file path from configuration"""
|
|
157
|
+
if default is NoDefault:
|
|
158
|
+
default = ""
|
|
159
|
+
fname = super().get(default)
|
|
160
|
+
if osp.basename(fname) != fname:
|
|
161
|
+
raise ValueError(f"Invalid configuration file name {fname}")
|
|
162
|
+
return CONF.get_path(osp.basename(fname))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class WorkingDirOption(Option):
|
|
166
|
+
"""Working directory configuration option handler"""
|
|
167
|
+
|
|
168
|
+
def get(self, default=NoDefault) -> str:
|
|
169
|
+
"""Get working directory from configuration"""
|
|
170
|
+
if default is NoDefault:
|
|
171
|
+
default = ""
|
|
172
|
+
path = super().get(default)
|
|
173
|
+
if osp.isdir(path):
|
|
174
|
+
return path
|
|
175
|
+
return ""
|
|
176
|
+
|
|
177
|
+
def set(self, value: str) -> None:
|
|
178
|
+
"""Set working directory in configuration"""
|
|
179
|
+
if not osp.isdir(value):
|
|
180
|
+
value = osp.dirname(value)
|
|
181
|
+
if not osp.isdir(value):
|
|
182
|
+
raise FileNotFoundError(f"Invalid working directory name {value}")
|
|
183
|
+
os.chdir(value)
|
|
184
|
+
super().set(value)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class EnumOption(Option):
|
|
188
|
+
"""Enumeration option handler"""
|
|
189
|
+
|
|
190
|
+
def __init__(self, values: list[Any], default: Any = NoDefault) -> None:
|
|
191
|
+
super().__init__()
|
|
192
|
+
if default is NoDefault:
|
|
193
|
+
default = values[0]
|
|
194
|
+
self.values = values
|
|
195
|
+
self.default = default
|
|
196
|
+
|
|
197
|
+
def get(self, default: Any = NoDefault) -> Any:
|
|
198
|
+
"""Get configuration option value"""
|
|
199
|
+
value = super().get(default)
|
|
200
|
+
if value not in self.values:
|
|
201
|
+
# Only show a warning here, as the configuration file may be edited manually
|
|
202
|
+
warnings.warn(
|
|
203
|
+
f"Invalid value {value} for option {self.option}, "
|
|
204
|
+
f"expected {self.values}"
|
|
205
|
+
)
|
|
206
|
+
return self.default
|
|
207
|
+
return value
|
|
208
|
+
|
|
209
|
+
def set(self, value: Any) -> None:
|
|
210
|
+
"""Set configuration option value"""
|
|
211
|
+
if value not in self.values:
|
|
212
|
+
raise ValueError(
|
|
213
|
+
f"Invalid value {value} for option {self.option}, "
|
|
214
|
+
f"expected {self.values}"
|
|
215
|
+
)
|
|
216
|
+
super().set(value)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class DataSetOption(Option):
|
|
220
|
+
"""DataSet option handler"""
|
|
221
|
+
|
|
222
|
+
def __init__(self, default_instance: gds.DataSet | None = None) -> None:
|
|
223
|
+
super().__init__()
|
|
224
|
+
self.default_instance = default_instance
|
|
225
|
+
|
|
226
|
+
def set_default_instance(self, default_instance: gds.DataSet) -> None:
|
|
227
|
+
"""Set the default instance (for lazy initialization)"""
|
|
228
|
+
self.default_instance = default_instance
|
|
229
|
+
|
|
230
|
+
def get(self, default: Any = NoDefault) -> gds.DataSet:
|
|
231
|
+
"""Get configuration option value"""
|
|
232
|
+
# Use provided default or fall back to default_instance
|
|
233
|
+
effective_default = (
|
|
234
|
+
default if default is not NoDefault else self.default_instance
|
|
235
|
+
)
|
|
236
|
+
try:
|
|
237
|
+
json_str = super().get(default)
|
|
238
|
+
except RuntimeError as exc:
|
|
239
|
+
# Option not yet registered in CONF - register it with default
|
|
240
|
+
if effective_default is None:
|
|
241
|
+
raise ValueError(
|
|
242
|
+
f"No default instance set for option '{self.option}' "
|
|
243
|
+
f"in section '{self.section}'"
|
|
244
|
+
) from exc
|
|
245
|
+
# Register the default value in CONF (writes to config file)
|
|
246
|
+
self.set(effective_default)
|
|
247
|
+
return effective_default
|
|
248
|
+
# If the option doesn't exist, super().get() returns the default parameter
|
|
249
|
+
if not isinstance(json_str, str):
|
|
250
|
+
return json_str
|
|
251
|
+
if json_str is NoDefault or not json_str:
|
|
252
|
+
if effective_default is None:
|
|
253
|
+
raise ValueError(
|
|
254
|
+
f"No default instance set for option '{self.option}' "
|
|
255
|
+
f"in section '{self.section}'"
|
|
256
|
+
)
|
|
257
|
+
return effective_default
|
|
258
|
+
# Unescape percent signs that were escaped for ConfigParser
|
|
259
|
+
json_str = json_str.replace("%%", "%")
|
|
260
|
+
try:
|
|
261
|
+
return gds.json_to_dataset(json_str)
|
|
262
|
+
except Exception as exc: # pylint: disable=broad-except
|
|
263
|
+
# Corrupted JSON: remove the option and return default
|
|
264
|
+
self.remove()
|
|
265
|
+
if effective_default is None:
|
|
266
|
+
raise ValueError(
|
|
267
|
+
f"No default instance set for option '{self.option}' "
|
|
268
|
+
f"in section '{self.section}'"
|
|
269
|
+
) from exc
|
|
270
|
+
return effective_default
|
|
271
|
+
|
|
272
|
+
def set(self, value: gds.DataSet) -> None:
|
|
273
|
+
"""Set configuration option value"""
|
|
274
|
+
json_str = gds.dataset_to_json(value)
|
|
275
|
+
# Escape percent signs for ConfigParser (which uses % for interpolation)
|
|
276
|
+
json_str = json_str.replace("%", "%%")
|
|
277
|
+
super().set(json_str)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class SectionMeta(type):
|
|
281
|
+
"""Configuration metaclass"""
|
|
282
|
+
|
|
283
|
+
# pylint: disable=bad-mcs-classmethod-argument
|
|
284
|
+
def __new__(cls, name, bases, dct):
|
|
285
|
+
optlist = []
|
|
286
|
+
for attrname, obj in list(dct.items()):
|
|
287
|
+
if isinstance(obj, Option):
|
|
288
|
+
obj.option = attrname
|
|
289
|
+
optlist.append(obj)
|
|
290
|
+
dct["_options"] = optlist
|
|
291
|
+
return type.__new__(cls, name, bases, dct)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class ConfMeta(type):
|
|
295
|
+
"""Configuration metaclass"""
|
|
296
|
+
|
|
297
|
+
# pylint: disable=bad-mcs-classmethod-argument
|
|
298
|
+
def __new__(cls, name, bases, dct):
|
|
299
|
+
for attrname, obj in list(dct.items()):
|
|
300
|
+
if isinstance(obj, Section):
|
|
301
|
+
obj.set_name(attrname)
|
|
302
|
+
for option in obj._options:
|
|
303
|
+
option.section = attrname
|
|
304
|
+
return type.__new__(cls, name, bases, dct)
|