bec-widgets 0.57.7__tar.gz → 0.58.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/CHANGELOG.md +28 -28
  2. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/PKG-INFO +1 -1
  3. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/cli/client.py +1 -1
  4. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/examples/jupyter_console/jupyter_console_window.py +2 -3
  5. bec_widgets-0.58.1/bec_widgets/utils/colors.py +276 -0
  6. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/dock/dock.py +0 -32
  7. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/dock/dock_area.py +4 -0
  8. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/plots/waveform/waveform.py +3 -3
  9. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/plots/waveform/waveform_curve.py +27 -11
  10. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/spiral_progress_bar/spiral_progress_bar.py +4 -12
  11. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/pyproject.toml +1 -1
  12. bec_widgets-0.58.1/tests/unit_tests/test_color_validation.py +60 -0
  13. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_waveform1d.py +3 -3
  14. bec_widgets-0.57.7/bec_widgets/utils/colors.py +0 -65
  15. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/.git_hooks/pre-commit +0 -0
  16. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/.gitignore +0 -0
  17. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/.gitlab/issue_templates/bug_report_template.md +0 -0
  18. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/.gitlab/issue_templates/documentation_update_template.md +0 -0
  19. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/.gitlab/issue_templates/feature_request_template.md +0 -0
  20. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/.gitlab/merge_request_templates/default.md +0 -0
  21. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/.gitlab-ci.yml +0 -0
  22. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/.pylintrc +0 -0
  23. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/.readthedocs.yaml +0 -0
  24. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/LICENSE +0 -0
  25. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/README.md +0 -0
  26. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/__init__.py +0 -0
  27. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/assets/bec_widgets_icon.png +0 -0
  28. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/assets/terminal_icon.png +0 -0
  29. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/cli/__init__.py +0 -0
  30. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/cli/auto_updates.py +0 -0
  31. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/cli/client_utils.py +0 -0
  32. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/cli/generate_cli.py +0 -0
  33. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/cli/rpc_register.py +0 -0
  34. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/cli/rpc_wigdet_handler.py +0 -0
  35. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/cli/server.py +0 -0
  36. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/examples/__init__.py +0 -0
  37. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/examples/jupyter_console/__init__.py +0 -0
  38. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/examples/jupyter_console/jupyter_console_window.ui +0 -0
  39. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/examples/motor_movement/__init__.py +0 -0
  40. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/examples/motor_movement/motor_control_compilations.py +0 -0
  41. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/examples/motor_movement/motor_controller.ui +0 -0
  42. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/__init__.py +0 -0
  43. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/bec_connector.py +0 -0
  44. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/bec_dispatcher.py +0 -0
  45. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/bec_table.py +0 -0
  46. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/container_utils.py +0 -0
  47. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/crosshair.py +0 -0
  48. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/entry_validator.py +0 -0
  49. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/layout_manager.py +0 -0
  50. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/plugin_utils.py +0 -0
  51. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/rpc_decorator.py +0 -0
  52. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/thread_checker.py +0 -0
  53. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/ui_loader.py +0 -0
  54. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/validator_delegate.py +0 -0
  55. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/widget_io.py +0 -0
  56. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/utils/yaml_dialog.py +0 -0
  57. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/__init__.py +0 -0
  58. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/dock/__init__.py +0 -0
  59. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/__init__.py +0 -0
  60. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/figure.py +0 -0
  61. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/plots/__init__.py +0 -0
  62. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/plots/image/__init__.py +0 -0
  63. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/plots/image/image.py +0 -0
  64. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/plots/image/image_item.py +0 -0
  65. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/plots/image/image_processor.py +0 -0
  66. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/plots/motor_map/__init__.py +0 -0
  67. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/plots/motor_map/motor_map.py +0 -0
  68. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/plots/plot_base.py +0 -0
  69. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/figure/plots/waveform/__init__.py +0 -0
  70. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/jupyter_console/__init__.py +0 -0
  71. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/jupyter_console/jupyter_console.py +0 -0
  72. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/__init__.py +0 -0
  73. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/motor_control.py +0 -0
  74. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/motor_table/__init__.py +0 -0
  75. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/motor_table/motor_table.py +0 -0
  76. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/motor_table/motor_table.ui +0 -0
  77. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/movement_absolute/__init__.py +0 -0
  78. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.py +0 -0
  79. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.ui +0 -0
  80. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/movement_relative/__init__.py +0 -0
  81. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/movement_relative/movement_relative.py +0 -0
  82. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/movement_relative/movement_relative.ui +0 -0
  83. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/selection/__init__.py +0 -0
  84. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/selection/selection.py +0 -0
  85. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/motor_control/selection/selection.ui +0 -0
  86. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/scan_control/__init__.py +0 -0
  87. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/scan_control/scan_control.py +0 -0
  88. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/spiral_progress_bar/__init__.py +0 -0
  89. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/spiral_progress_bar/ring.py +0 -0
  90. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/toolbar/__init__.py +0 -0
  91. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/bec_widgets/widgets/toolbar/toolbar.py +0 -0
  92. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/Makefile +0 -0
  93. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/_static/custom.css +0 -0
  94. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/_templates/custom-class-template.rst +0 -0
  95. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/_templates/custom-module-template.rst +0 -0
  96. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/api_reference/api_reference.md +0 -0
  97. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/assets/apps_48dp.svg +0 -0
  98. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/assets/display_settings_48dp.svg +0 -0
  99. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/assets/index_api.svg +0 -0
  100. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/assets/index_contribute.svg +0 -0
  101. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/assets/index_getting_started.svg +0 -0
  102. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/assets/index_user_guide.svg +0 -0
  103. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/assets/rocket_launch_48dp.svg +0 -0
  104. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/conf.py +0 -0
  105. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/developer/developer.md +0 -0
  106. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/index.md +0 -0
  107. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/introduction/introduction.md +0 -0
  108. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/make.bat +0 -0
  109. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/requirements.txt +0 -0
  110. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/api_reference/api_reference.md +0 -0
  111. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/applications/applications.md +0 -0
  112. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/customisation.md +0 -0
  113. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/getting_started/BECDockArea.png +0 -0
  114. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/getting_started/auto_updates.md +0 -0
  115. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/getting_started/getting_started.md +0 -0
  116. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/getting_started/gui_complex_gui.gif +0 -0
  117. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/getting_started/installation.md +0 -0
  118. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/getting_started/quick_start.md +0 -0
  119. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/user.md +0 -0
  120. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/widgets/BECFigure.png +0 -0
  121. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/widgets/bec_figure.md +0 -0
  122. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/widgets/image_plot.gif +0 -0
  123. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/widgets/motor.gif +0 -0
  124. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/widgets/progress_bar.gif +0 -0
  125. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/widgets/scatter_2D.gif +0 -0
  126. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/widgets/spiral_progress_bar.md +0 -0
  127. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/widgets/w1D.gif +0 -0
  128. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/docs/user/widgets/widgets.md +0 -0
  129. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/__init__.py +0 -0
  130. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/end-2-end/__init__.py +0 -0
  131. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/end-2-end/conftest.py +0 -0
  132. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/end-2-end/test_bec_dock_rpc_e2e.py +0 -0
  133. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/end-2-end/test_bec_figure_rpc_e2e.py +0 -0
  134. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/end-2-end/test_rpc_register_e2e.py +0 -0
  135. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/__init__.py +0 -0
  136. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/client_mocks.py +0 -0
  137. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/conftest.py +0 -0
  138. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_bec_connector.py +0 -0
  139. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_bec_dispatcher.py +0 -0
  140. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_bec_dock.py +0 -0
  141. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_bec_figure.py +0 -0
  142. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_bec_motor_map.py +0 -0
  143. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_client_utils.py +0 -0
  144. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_configs/config_device.yaml +0 -0
  145. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_configs/config_device_no_entry.yaml +0 -0
  146. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_configs/config_scan.yaml +0 -0
  147. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_crosshair.py +0 -0
  148. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_generate_cli_client.py +0 -0
  149. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_motor_control.py +0 -0
  150. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_msgs/__init__.py +0 -0
  151. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_msgs/available_scans_message.py +0 -0
  152. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_plot_base.py +0 -0
  153. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_rpc_register.py +0 -0
  154. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_scan_control.py +0 -0
  155. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_spiral_progress_bar.py +0 -0
  156. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_widget_io.py +0 -0
  157. {bec_widgets-0.57.7 → bec_widgets-0.58.1}/tests/unit_tests/test_yaml_dialog.py +0 -0
@@ -2,6 +2,34 @@
2
2
 
3
3
 
4
4
 
5
+ ## v0.58.1 (2024-06-07)
6
+
7
+ ### Fix
8
+
9
+ * fix(dock): new dock can be detached upon creation ([`02a2608`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/02a26086c4540127a11c235cba30afc4fd712007))
10
+
11
+
12
+ ## v0.58.0 (2024-06-07)
13
+
14
+ ### Feature
15
+
16
+ * feat(utils.colors): general color validators ([`3094632`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/30946321348abc349fb4003dc39d0232dc19606c))
17
+
18
+ ### Fix
19
+
20
+ * fix: bar colormap dynamic setting ([`67fd5e8`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/67fd5e8581f60fe64027ac57f1f12cefa4d28343))
21
+
22
+ * fix: formatting isort ([`bf699ec`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/bf699ec1fbe2aacd31854e84fb0438c336840fcf))
23
+
24
+ * fix(curve): 2D scatter updated if color_map_z is changed ([`6985ff0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6985ff0fcef9791b53198206ec8cbccd1d65ef99))
25
+
26
+ * fix(curve): color_map_z setting works ([`33f7be4`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/33f7be42c512402dab3fdd9781a8234e3ec5f4ba))
27
+
28
+ ### Test
29
+
30
+ * test(color): validation tests added ([`c0ddece`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c0ddeceeeabacbf33019a8f24b18821926dc17ac))
31
+
32
+
5
33
  ## v0.57.7 (2024-06-07)
6
34
 
7
35
  ### Documentation
@@ -125,36 +153,8 @@
125
153
 
126
154
  ## v0.56.2 (2024-06-05)
127
155
 
128
- ### Documentation
129
-
130
- * docs: restructured docs layout ([`3c9181d`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3c9181d93d68faa4efb3b91c486ca9ca935975a0))
131
-
132
156
  ### Fix
133
157
 
134
158
  * fix(bar): ring saves current value in config ([`9648e3e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9648e3ea96a4109be6be694d855151ed6d3ad661))
135
159
 
136
160
  * fix(dock): dock saves configs of all children widgets ([`4be756a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4be756a8676421c3a3451458995232407295df84))
137
-
138
- * fix(dock_area): save/restore state is saved in config ([`46face0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/46face0ee59122f04cb383da685a6658beeeb389))
139
-
140
- * fix(figure): added correct types of configs to subplot widgets ([`6f3b1ea`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6f3b1ea985c18929b9bab54239eeb600f03b274a))
141
-
142
-
143
- ## v0.56.1 (2024-06-04)
144
-
145
- ### Fix
146
-
147
- * fix(spiral_progress_bar/rings): config min/max values added check for floats ([`9d615c9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9d615c915c8f7cc2ea8f1dc17993b98fe462c682))
148
-
149
- * fix(spiral_progress_bar): Endpoint is always stored as a string in the RingConnection Config ([`d253991`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d2539918b296559e1d684344e179775a2423daa9))
150
-
151
-
152
- ## v0.56.0 (2024-05-29)
153
-
154
- ### Documentation
155
-
156
- * docs(examples): example apps section deleted ([`ad208a5`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ad208a5ef8495c45a8b83a4850ba9a1041b42717))
157
-
158
- ### Fix
159
-
160
- * fix(examples): outdated examples removed (mca_plot.py, stream_plot.py, motor_example.py) ([`ddc9510`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ddc9510c2ba8dadf291809eeb5b135a105259492))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.57.7
3
+ Version: 0.58.1
4
4
  Summary: BEC Widgets
5
5
  Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec_widgets/issues
6
6
  Project-URL: Homepage, https://gitlab.psi.ch/bec/bec_widgets
@@ -753,7 +753,7 @@ class BECCurve(RPCBase):
753
753
  """
754
754
 
755
755
  @rpc_call
756
- def set_colormap(self, colormap: "str"):
756
+ def set_colormap_z(self, colormap: "str"):
757
757
  """
758
758
  Set the colormap for the scatter plot z gradient.
759
759
 
@@ -86,9 +86,10 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
86
86
  self.console_layout.addWidget(self.console)
87
87
 
88
88
  def _init_figure(self):
89
- self.figure.plot(x_name="samx", y_name="bpm4d")
89
+ self.figure.plot(x_name="samx", y_name="samy", z_name="bpm4i", color_map_z="cividis")
90
90
  self.figure.motor_map("samx", "samy")
91
91
  self.figure.image("eiger", color_map="viridis", vrange=(0, 100))
92
+ self.figure.add_plot(x_name="samx", y_name="samy", z_name="bpm4i", color_map_z="magma")
92
93
 
93
94
  self.figure.change_layout(2, 2)
94
95
 
@@ -97,8 +98,6 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
97
98
  self.w3 = self.figure[1, 0]
98
99
 
99
100
  # curves for w1
100
- self.w1.plot(x_name="samx", y_name="samy", z_name="bpm4i")
101
- self.w1.plot(x_name="samx", y_name="samy", z_name="bpm3a")
102
101
  self.c1 = self.w1.get_config()
103
102
 
104
103
  def _init_dock(self):
@@ -0,0 +1,276 @@
1
+ import re
2
+ from typing import Literal
3
+
4
+ import numpy as np
5
+ import pyqtgraph as pg
6
+ from pydantic_core import PydanticCustomError
7
+ from qtpy.QtGui import QColor
8
+
9
+
10
+ class Colors:
11
+
12
+ @staticmethod
13
+ def golden_ratio(num: int) -> list:
14
+ """Calculate the golden ratio for a given number of angles.
15
+
16
+ Args:
17
+ num (int): Number of angles
18
+
19
+ Returns:
20
+ list: List of angles calculated using the golden ratio.
21
+ """
22
+ phi = 2 * np.pi * ((1 + np.sqrt(5)) / 2)
23
+ angles = []
24
+ for ii in range(num):
25
+ x = np.cos(ii * phi)
26
+ y = np.sin(ii * phi)
27
+ angle = np.arctan2(y, x)
28
+ angles.append(angle)
29
+ return angles
30
+
31
+ @staticmethod
32
+ def golden_angle_color(
33
+ colormap: str, num: int, format: Literal["QColor", "HEX", "RGB"] = "QColor"
34
+ ) -> list:
35
+ """
36
+ Extract num colors from the specified colormap following golden angle distribution and return them in the specified format.
37
+
38
+ Args:
39
+ colormap (str): Name of the colormap.
40
+ num (int): Number of requested colors.
41
+ format (Literal["QColor","HEX","RGB"]): The format of the returned colors ('RGB', 'HEX', 'QColor').
42
+
43
+ Returns:
44
+ list: List of colors in the specified format.
45
+
46
+ Raises:
47
+ ValueError: If the number of requested colors is greater than the number of colors in the colormap.
48
+ """
49
+ cmap = pg.colormap.get(colormap)
50
+ cmap_colors = cmap.getColors(mode="float")
51
+ if num > len(cmap_colors):
52
+ raise ValueError(
53
+ f"Number of colors requested ({num}) is greater than the number of colors in the colormap ({len(cmap_colors)})"
54
+ )
55
+ angles = Colors.golden_ratio(len(cmap_colors))
56
+ color_selection = np.round(np.interp(angles, (-np.pi, np.pi), (0, len(cmap_colors))))
57
+ colors = []
58
+ for ii in color_selection[:num]:
59
+ color = cmap_colors[int(ii)]
60
+ if format.upper() == "HEX":
61
+ colors.append(QColor.fromRgbF(*color).name())
62
+ elif format.upper() == "RGB":
63
+ colors.append(tuple((np.array(color) * 255).astype(int)))
64
+ elif format.upper() == "QCOLOR":
65
+ colors.append(QColor.fromRgbF(*color))
66
+ else:
67
+ raise ValueError("Unsupported format. Please choose 'RGB', 'HEX', or 'QColor'.")
68
+ return colors
69
+
70
+ @staticmethod
71
+ def validate_color(color: tuple | str) -> tuple | str:
72
+ """
73
+ Validate the color input if it is HEX or RGBA compatible. Can be used in any pydantic model as a field validator.
74
+
75
+ Args:
76
+ color(tuple|str): The color to be validated. Can be a tuple of RGBA values or a HEX string.
77
+
78
+ Returns:
79
+ tuple|str: The validated color.
80
+ """
81
+ CSS_COLOR_NAMES = {
82
+ "aliceblue",
83
+ "antiquewhite",
84
+ "aqua",
85
+ "aquamarine",
86
+ "azure",
87
+ "beige",
88
+ "bisque",
89
+ "black",
90
+ "blanchedalmond",
91
+ "blue",
92
+ "blueviolet",
93
+ "brown",
94
+ "burlywood",
95
+ "cadetblue",
96
+ "chartreuse",
97
+ "chocolate",
98
+ "coral",
99
+ "cornflowerblue",
100
+ "cornsilk",
101
+ "crimson",
102
+ "cyan",
103
+ "darkblue",
104
+ "darkcyan",
105
+ "darkgoldenrod",
106
+ "darkgray",
107
+ "darkgreen",
108
+ "darkgrey",
109
+ "darkkhaki",
110
+ "darkmagenta",
111
+ "darkolivegreen",
112
+ "darkorange",
113
+ "darkorchid",
114
+ "darkred",
115
+ "darksalmon",
116
+ "darkseagreen",
117
+ "darkslateblue",
118
+ "darkslategray",
119
+ "darkslategrey",
120
+ "darkturquoise",
121
+ "darkviolet",
122
+ "deeppink",
123
+ "deepskyblue",
124
+ "dimgray",
125
+ "dimgrey",
126
+ "dodgerblue",
127
+ "firebrick",
128
+ "floralwhite",
129
+ "forestgreen",
130
+ "fuchsia",
131
+ "gainsboro",
132
+ "ghostwhite",
133
+ "gold",
134
+ "goldenrod",
135
+ "gray",
136
+ "green",
137
+ "greenyellow",
138
+ "grey",
139
+ "honeydew",
140
+ "hotpink",
141
+ "indianred",
142
+ "indigo",
143
+ "ivory",
144
+ "khaki",
145
+ "lavender",
146
+ "lavenderblush",
147
+ "lawngreen",
148
+ "lemonchiffon",
149
+ "lightblue",
150
+ "lightcoral",
151
+ "lightcyan",
152
+ "lightgoldenrodyellow",
153
+ "lightgray",
154
+ "lightgreen",
155
+ "lightgrey",
156
+ "lightpink",
157
+ "lightsalmon",
158
+ "lightseagreen",
159
+ "lightskyblue",
160
+ "lightslategray",
161
+ "lightslategrey",
162
+ "lightsteelblue",
163
+ "lightyellow",
164
+ "lime",
165
+ "limegreen",
166
+ "linen",
167
+ "magenta",
168
+ "maroon",
169
+ "mediumaquamarine",
170
+ "mediumblue",
171
+ "mediumorchid",
172
+ "mediumpurple",
173
+ "mediumseagreen",
174
+ "mediumslateblue",
175
+ "mediumspringgreen",
176
+ "mediumturquoise",
177
+ "mediumvioletred",
178
+ "midnightblue",
179
+ "mintcream",
180
+ "mistyrose",
181
+ "moccasin",
182
+ "navajowhite",
183
+ "navy",
184
+ "oldlace",
185
+ "olive",
186
+ "olivedrab",
187
+ "orange",
188
+ "orangered",
189
+ "orchid",
190
+ "palegoldenrod",
191
+ "palegreen",
192
+ "paleturquoise",
193
+ "palevioletred",
194
+ "papayawhip",
195
+ "peachpuff",
196
+ "peru",
197
+ "pink",
198
+ "plum",
199
+ "powderblue",
200
+ "purple",
201
+ "red",
202
+ "rosybrown",
203
+ "royalblue",
204
+ "saddlebrown",
205
+ "salmon",
206
+ "sandybrown",
207
+ "seagreen",
208
+ "seashell",
209
+ "sienna",
210
+ "silver",
211
+ "skyblue",
212
+ "slateblue",
213
+ "slategray",
214
+ "slategrey",
215
+ "snow",
216
+ "springgreen",
217
+ "steelblue",
218
+ "tan",
219
+ "teal",
220
+ "thistle",
221
+ "tomato",
222
+ "turquoise",
223
+ "violet",
224
+ "wheat",
225
+ "white",
226
+ "whitesmoke",
227
+ "yellow",
228
+ "yellowgreen",
229
+ }
230
+ if isinstance(color, str):
231
+ hex_pattern = re.compile(r"^#(?:[0-9a-fA-F]{3}){1,2}$")
232
+ if hex_pattern.match(color):
233
+ return color
234
+ elif color.lower() in CSS_COLOR_NAMES:
235
+ return color
236
+ else:
237
+ raise PydanticCustomError(
238
+ "unsupported color",
239
+ "The color must be a valid HEX string or CSS Color.",
240
+ {"wrong_value": color},
241
+ )
242
+ elif isinstance(color, tuple):
243
+ if len(color) != 4:
244
+ raise PydanticCustomError(
245
+ "unsupported color",
246
+ "The color must be a tuple of 4 elements (R, G, B, A).",
247
+ {"wrong_value": color},
248
+ )
249
+ for value in color:
250
+ if not 0 <= value <= 255:
251
+ raise PydanticCustomError(
252
+ "unsupported color",
253
+ f"The color values must be between 0 and 255 in RGBA format (R,G,B,A)",
254
+ {"wrong_value": color},
255
+ )
256
+ return color
257
+
258
+ @staticmethod
259
+ def validate_color_map(color_map: str) -> str:
260
+ """
261
+ Validate the colormap input if it is supported by pyqtgraph. Can be used in any pydantic model as a field validator. If validation fails it prints all available colormaps from pyqtgraph instance.
262
+
263
+ Args:
264
+ color_map(str): The colormap to be validated.
265
+
266
+ Returns:
267
+ str: The validated colormap.
268
+ """
269
+ available_colormaps = pg.colormap.listMaps()
270
+ if color_map not in available_colormaps:
271
+ raise PydanticCustomError(
272
+ "unsupported colormap",
273
+ f"Colormap '{color_map}' not found in the current installation of pyqtgraph. Choose on the following: {available_colormaps}.",
274
+ {"wrong_value": color_map},
275
+ )
276
+ return color_map
@@ -153,38 +153,6 @@ class BECDock(BECConnector, Dock):
153
153
  """
154
154
  return list(RPCWidgetHandler.widget_classes.keys())
155
155
 
156
- # def add_widget_bec(
157
- # self,
158
- # widget_type: str,
159
- # row=None,
160
- # col=0,
161
- # rowspan=1,
162
- # colspan=1,
163
- # shift: Literal["down", "up", "left", "right"] = "down",
164
- # ):
165
- # """
166
- # Add a widget to the dock.
167
- #
168
- # Args:
169
- # widget_type(str): The widget to add. Only BEC RPC widgets from RPCWidgetHandler are allowed.
170
- # row(int): The row to add the widget to. If None, the widget will be added to the next available row.
171
- # col(int): The column to add the widget to.
172
- # rowspan(int): The number of rows the widget should span.
173
- # colspan(int): The number of columns the widget should span.
174
- # shift(Literal["down", "up", "left", "right"]): The direction to shift the widgets if the position is occupied.
175
- # """
176
- # if row is None:
177
- # row = self.layout.rowCount()
178
- #
179
- # if self.layout_manager.is_position_occupied(row, col):
180
- # self.layout_manager.shift_widgets(shift, start_row=row)
181
- #
182
- # widget = RPCWidgetHandler.create_widget(widget_type)
183
- # self.addWidget(widget, row=row, col=col, rowspan=rowspan, colspan=colspan)
184
- # self.config.widgets[widget.gui_id] = widget.config
185
- #
186
- # return widget
187
-
188
156
  def add_widget(
189
157
  self,
190
158
  widget: BECConnector | str,
@@ -137,6 +137,7 @@ class BECDockArea(BECConnector, DockArea):
137
137
  position: Literal["bottom", "top", "left", "right", "above", "below"] = None,
138
138
  relative_to: BECDock | None = None,
139
139
  closable: bool = False,
140
+ floating: bool = False,
140
141
  prefix: str = "dock",
141
142
  widget: str | QWidget | None = None,
142
143
  row: int = None,
@@ -152,6 +153,7 @@ class BECDockArea(BECConnector, DockArea):
152
153
  position(Literal["bottom", "top", "left", "right", "above", "below"]): The position of the dock.
153
154
  relative_to(BECDock): The dock to which the new dock should be added relative to.
154
155
  closable(bool): Whether the dock is closable.
156
+ floating(bool): Whether the dock is detached after creating.
155
157
  prefix(str): The prefix for the dock name if no name is provided.
156
158
  widget(str|QWidget|None): The widget to be added to the dock. While using RPC, only BEC RPC widgets from RPCWidgetHandler are allowed.
157
159
  row(int): The row of the added widget.
@@ -192,6 +194,8 @@ class BECDockArea(BECConnector, DockArea):
192
194
  if self._instructions_visible:
193
195
  self._instructions_visible = False
194
196
  self.update()
197
+ if floating:
198
+ dock.detach()
195
199
  return dock
196
200
 
197
201
  def detach_dock(self, dock_name: str) -> BECDock:
@@ -364,7 +364,7 @@ class BECWaveform(BECPlotBase):
364
364
  parent_id=self.gui_id,
365
365
  label=label,
366
366
  color=color,
367
- color_map=color_map_z,
367
+ color_map_z=color_map_z,
368
368
  source=curve_source,
369
369
  signals=Signal(
370
370
  source=curve_source,
@@ -396,7 +396,7 @@ class BECWaveform(BECPlotBase):
396
396
  Returns:
397
397
  BECCurve: The curve object.
398
398
  """
399
- curve = BECCurve(config=config, name=name, parent_item=self.plot_item)
399
+ curve = BECCurve(config=config, name=name, parent_item=self)
400
400
  self._curves_data[source][name] = curve
401
401
  self.plot_item.addItem(curve)
402
402
  self.config.curves[name] = curve.config
@@ -564,7 +564,7 @@ class BECWaveform(BECPlotBase):
564
564
  if curve.config.signals.z:
565
565
  data_z = data[z_name][z_entry].val
566
566
  color_z = self._make_z_gradient(
567
- data_z, curve.config.colormap
567
+ data_z, curve.config.color_map_z
568
568
  ) # TODO decide how to implement custom gradient
569
569
  except TypeError:
570
570
  continue
@@ -1,12 +1,16 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, Literal, Optional
3
+ from typing import TYPE_CHECKING, Any, Literal, Optional
4
4
 
5
5
  import pyqtgraph as pg
6
- from pydantic import BaseModel, Field
6
+ from pydantic import BaseModel, Field, field_validator
7
+ from pydantic_core import PydanticCustomError
7
8
  from qtpy import QtCore
8
9
 
9
- from bec_widgets.utils import BECConnector, ConnectionConfig
10
+ from bec_widgets.utils import BECConnector, Colors, ConnectionConfig
11
+
12
+ if TYPE_CHECKING:
13
+ from bec_widgets.widgets.figure.plots.waveform import BECWaveform1D
10
14
 
11
15
 
12
16
  class SignalData(BaseModel):
@@ -33,9 +37,11 @@ class Signal(BaseModel):
33
37
  class CurveConfig(ConnectionConfig):
34
38
  parent_id: Optional[str] = Field(None, description="The parent plot of the curve.")
35
39
  label: Optional[str] = Field(None, description="The label of the curve.")
36
- color: Optional[Any] = Field(None, description="The color of the curve.")
40
+ color: Optional[str | tuple] = Field(None, description="The color of the curve.")
37
41
  symbol: Optional[str] = Field("o", description="The symbol of the curve.")
38
- symbol_color: Optional[str] = Field(None, description="The color of the symbol of the curve.")
42
+ symbol_color: Optional[str | tuple] = Field(
43
+ None, description="The color of the symbol of the curve."
44
+ )
39
45
  symbol_size: Optional[int] = Field(5, description="The size of the symbol of the curve.")
40
46
  pen_width: Optional[int] = Field(2, description="The width of the pen of the curve.")
41
47
  pen_style: Optional[Literal["solid", "dash", "dot", "dashdot"]] = Field(
@@ -43,7 +49,15 @@ class CurveConfig(ConnectionConfig):
43
49
  )
44
50
  source: Optional[str] = Field(None, description="The source of the curve.")
45
51
  signals: Optional[Signal] = Field(None, description="The signal of the curve.")
46
- colormap: Optional[str] = Field("plasma", description="The colormap of the curves z gradient.")
52
+ color_map_z: Optional[str] = Field(
53
+ "plasma", description="The colormap of the curves z gradient.", validate_default=True
54
+ )
55
+
56
+ model_config: dict = {"validate_assignment": True}
57
+
58
+ _validate_color_map_z = field_validator("color_map_z")(Colors.validate_color_map)
59
+ _validate_color = field_validator("color")(Colors.validate_color)
60
+ _validate_symbol_color = field_validator("symbol_color")(Colors.validate_color)
47
61
 
48
62
 
49
63
  class BECCurve(BECConnector, pg.PlotDataItem):
@@ -54,7 +68,7 @@ class BECCurve(BECConnector, pg.PlotDataItem):
54
68
  "set",
55
69
  "set_data",
56
70
  "set_color",
57
- "set_colormap",
71
+ "set_colormap_z",
58
72
  "set_symbol",
59
73
  "set_symbol_color",
60
74
  "set_symbol_size",
@@ -68,7 +82,7 @@ class BECCurve(BECConnector, pg.PlotDataItem):
68
82
  name: Optional[str] = None,
69
83
  config: Optional[CurveConfig] = None,
70
84
  gui_id: Optional[str] = None,
71
- parent_item: Optional[pg.PlotItem] = None,
85
+ parent_item: Optional[BECWaveform1D] = None,
72
86
  **kwargs,
73
87
  ):
74
88
  if config is None:
@@ -130,7 +144,7 @@ class BECCurve(BECConnector, pg.PlotDataItem):
130
144
  # Mapping of keywords to setter methods
131
145
  method_map = {
132
146
  "color": self.set_color,
133
- "colormap": self.set_colormap,
147
+ "color_map_z": self.set_color_map_z,
134
148
  "symbol": self.set_symbol,
135
149
  "symbol_color": self.set_symbol_color,
136
150
  "symbol_size": self.set_symbol_size,
@@ -205,14 +219,16 @@ class BECCurve(BECConnector, pg.PlotDataItem):
205
219
  self.config.pen_style = pen_style
206
220
  self.apply_config()
207
221
 
208
- def set_colormap(self, colormap: str):
222
+ def set_color_map_z(self, colormap: str):
209
223
  """
210
224
  Set the colormap for the scatter plot z gradient.
211
225
 
212
226
  Args:
213
227
  colormap(str): Colormap for the scatter plot.
214
228
  """
215
- self.config.colormap = colormap
229
+ self.config.color_map_z = colormap
230
+ self.apply_config()
231
+ self.parent_item.scan_history(-1)
216
232
 
217
233
  def get_data(self) -> tuple[np.ndarray, np.ndarray]:
218
234
  """
@@ -15,7 +15,9 @@ from bec_widgets.widgets.spiral_progress_bar.ring import Ring, RingConfig
15
15
 
16
16
 
17
17
  class SpiralProgressBarConfig(ConnectionConfig):
18
- color_map: str | None = Field("magma", description="Color scheme for the progress bars.")
18
+ color_map: Optional[str] = Field(
19
+ "magma", description="Color scheme for the progress bars.", validate_default=True
20
+ )
19
21
  min_number_of_bars: int | None = Field(
20
22
  1, description="Minimum number of progress bars to display."
21
23
  )
@@ -59,16 +61,7 @@ class SpiralProgressBarConfig(ConnectionConfig):
59
61
  )
60
62
  return v
61
63
 
62
- @field_validator("color_map")
63
- def validate_color_map(cls, v, values):
64
- if v is not None and v != "":
65
- if v not in pg.colormap.listMaps():
66
- raise PydanticCustomError(
67
- "unsupported colormap",
68
- f"Colormap '{v}' not found in the current installation of pyqtgraph",
69
- {"wrong_value": v},
70
- )
71
- return v
64
+ _validate_colormap = field_validator("color_map")(Colors.validate_color_map)
72
65
 
73
66
 
74
67
  class SpiralProgressBar(BECConnector, QWidget):
@@ -368,7 +361,6 @@ class SpiralProgressBar(BECConnector, QWidget):
368
361
  colors = self._adjust_list_to_bars(colors)
369
362
  for ring, color in zip(self._rings, colors):
370
363
  ring.set_color(color)
371
- self.config.color_map = None
372
364
  self.update()
373
365
 
374
366
  def set_line_widths(self, widths: int | list[int], bar_index: int = None):
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bec_widgets"
7
- version = "0.57.7"
7
+ version = "0.58.1"
8
8
  description = "BEC Widgets"
9
9
  requires-python = ">=3.10"
10
10
  classifiers = [
@@ -0,0 +1,60 @@
1
+ import pytest
2
+ from pydantic import ValidationError
3
+
4
+ from bec_widgets.utils import Colors
5
+ from bec_widgets.widgets.figure.plots.waveform.waveform_curve import CurveConfig
6
+
7
+
8
+ def test_color_validation_CSS():
9
+ # Test valid color
10
+ color = Colors.validate_color("teal")
11
+ assert color == "teal"
12
+
13
+ # Test invalid color
14
+ with pytest.raises(ValidationError) as excinfo:
15
+ CurveConfig(color="invalid_color")
16
+
17
+ errors = excinfo.value.errors()
18
+ assert len(errors) == 1
19
+ assert errors[0]["type"] == ("unsupported color")
20
+ assert "The color must be a valid HEX string or CSS Color." in str(excinfo.value)
21
+
22
+
23
+ def test_color_validation_hex():
24
+ # Test valid color
25
+ color = Colors.validate_color("#ff0000")
26
+ assert color == "#ff0000"
27
+
28
+ # Test invalid color
29
+ with pytest.raises(ValidationError) as excinfo:
30
+ CurveConfig(color="#ff00000")
31
+
32
+ errors = excinfo.value.errors()
33
+ assert len(errors) == 1
34
+ assert errors[0]["type"] == ("unsupported color")
35
+ assert "The color must be a valid HEX string or CSS Color." in str(excinfo.value)
36
+
37
+
38
+ def test_color_validation_RGBA():
39
+ # Test valid color
40
+ color = Colors.validate_color((255, 0, 0, 255))
41
+ assert color == (255, 0, 0, 255)
42
+
43
+ # Test invalid color
44
+ with pytest.raises(ValidationError) as excinfo:
45
+ CurveConfig(color=(255, 0, 0))
46
+
47
+ errors = excinfo.value.errors()
48
+ assert len(errors) == 1
49
+ assert errors[0]["type"] == ("unsupported color")
50
+ assert "The color must be a tuple of 4 elements (R, G, B, A)." in str(excinfo.value)
51
+
52
+ with pytest.raises(ValidationError) as excinfo:
53
+ CurveConfig(color=(255, 0, 0, 355))
54
+
55
+ errors = excinfo.value.errors()
56
+ assert len(errors) == 1
57
+ assert errors[0]["type"] == ("unsupported color")
58
+ assert "The color values must be between 0 and 255 in RGBA format (R,G,B,A)" in str(
59
+ excinfo.value
60
+ )