bec-widgets 0.63.1__py3-none-any.whl → 0.64.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.
.gitlab-ci.yml CHANGED
@@ -22,6 +22,13 @@ workflow:
22
22
 
23
23
  include:
24
24
  - template: Security/Secret-Detection.gitlab-ci.yml
25
+ - project: "bec/awi_utils"
26
+ file: "/templates/check-packages-job.yml"
27
+ inputs:
28
+ stage: test
29
+ path: "."
30
+ pytest_args: "-v --random-order tests/"
31
+ exclude_packages: ""
25
32
 
26
33
  # different stages in the pipeline
27
34
  stages:
@@ -32,21 +39,21 @@ stages:
32
39
  - Deploy
33
40
 
34
41
  .install-qt-webengine-deps: &install-qt-webengine-deps
35
- - apt-get -y install libnss3 libxdamage1 libasound2 libatomic1 libxcursor1
36
- - export QTWEBENGINE_DISABLE_SANDBOX=1
42
+ - apt-get -y install libnss3 libxdamage1 libasound2 libatomic1 libxcursor1
43
+ - export QTWEBENGINE_DISABLE_SANDBOX=1
37
44
 
38
45
  .clone-repos: &clone-repos
39
- - git clone --branch $BEC_CORE_BRANCH https://gitlab.psi.ch/bec/bec.git
40
- - git clone --branch $OPHYD_DEVICES_BRANCH https://gitlab.psi.ch/bec/ophyd_devices.git
41
- - export OHPYD_DEVICES_PATH=$PWD/ophyd_devices
42
-
46
+ - git clone --branch $BEC_CORE_BRANCH https://gitlab.psi.ch/bec/bec.git
47
+ - git clone --branch $OPHYD_DEVICES_BRANCH https://gitlab.psi.ch/bec/ophyd_devices.git
48
+ - export OHPYD_DEVICES_PATH=$PWD/ophyd_devices
49
+
43
50
  .install-os-packages: &install-os-packages
44
- - apt-get update
45
- - apt-get install -y libgl1-mesa-glx libegl1-mesa x11-utils libxkbcommon-x11-0 libdbus-1-3
46
- - *install-qt-webengine-deps
51
+ - apt-get update
52
+ - apt-get install -y libgl1-mesa-glx libegl1-mesa x11-utils libxkbcommon-x11-0 libdbus-1-3
53
+ - *install-qt-webengine-deps
47
54
 
48
55
  before_script:
49
- - if [[ "$CI_PROJECT_PATH" != "bec/bec_widgets" ]]; then
56
+ - if [[ "$CI_PROJECT_PATH" != "bec/bec_widgets" ]]; then
50
57
  echo -e "\033[35;1m Using branch $CHILD_PIPELINE_BRANCH of BEC Widgets \033[0;m";
51
58
  test -d bec_widgets || git clone --branch $CHILD_PIPELINE_BRANCH https://gitlab.psi.ch/bec/bec_widgets.git; cd bec_widgets;
52
59
  fi
@@ -92,10 +99,10 @@ pylint-check:
92
99
  - git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
93
100
  # Identify changed Python files
94
101
  - if [ "$CI_PIPELINE_SOURCE" == "merge_request_event" ]; then
95
- TARGET_BRANCH_COMMIT_SHA=$(git rev-parse origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME);
96
- CHANGED_FILES=$(git diff --name-only $TARGET_BRANCH_COMMIT_SHA HEAD | grep '\.py$' || true);
102
+ TARGET_BRANCH_COMMIT_SHA=$(git rev-parse origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME);
103
+ CHANGED_FILES=$(git diff --name-only $TARGET_BRANCH_COMMIT_SHA HEAD | grep '\.py$' || true);
97
104
  else
98
- CHANGED_FILES=$(git diff --name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA | grep '\.py$' || true);
105
+ CHANGED_FILES=$(git diff --name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA | grep '\.py$' || true);
99
106
  fi
100
107
  - if [ -z "$CHANGED_FILES" ]; then echo "No Python files changed."; exit 0; fi
101
108
 
@@ -120,7 +127,7 @@ tests:
120
127
  stage: test
121
128
  needs: []
122
129
  variables:
123
- QT_QPA_PLATFORM: "offscreen"
130
+ QT_QPA_PLATFORM: "offscreen"
124
131
  script:
125
132
  - *clone-repos
126
133
  - *install-os-packages
@@ -141,21 +148,21 @@ tests:
141
148
  test-matrix:
142
149
  parallel:
143
150
  matrix:
144
- - PYTHON_VERSION:
145
- - "3.10"
146
- - "3.11"
147
- - "3.12"
148
- QT_PCKG:
149
- - "pyside6"
150
- - "pyqt5"
151
- - "pyqt6"
151
+ - PYTHON_VERSION:
152
+ - "3.10"
153
+ - "3.11"
154
+ - "3.12"
155
+ QT_PCKG:
156
+ - "pyside6"
157
+ - "pyqt5"
158
+ - "pyqt6"
152
159
 
153
160
  stage: AdditionalTests
154
161
  needs: []
155
162
  variables:
156
- QT_QPA_PLATFORM: "offscreen"
157
- PYTHON_VERSION: ""
158
- QT_PCKG: ""
163
+ QT_QPA_PLATFORM: "offscreen"
164
+ PYTHON_VERSION: ""
165
+ QT_PCKG: ""
159
166
  image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/python:$PYTHON_VERSION
160
167
  script:
161
168
  - *clone-repos
@@ -226,7 +233,7 @@ semver:
226
233
  - pip install python-semantic-release==9.* wheel build twine
227
234
  - export GL_TOKEN=$CI_UPDATES
228
235
  - semantic-release -vv version
229
-
236
+
230
237
  # check if any artifacts were created
231
238
  - if [ ! -d dist ]; then echo No release will be made; exit 0; fi
232
239
  - twine upload dist/* -u __token__ -p $CI_PYPI_TOKEN --skip-existing
@@ -242,7 +249,7 @@ pages:
242
249
  variables:
243
250
  TARGET_BRANCH: $CI_COMMIT_REF_NAME
244
251
  rules:
245
- - if: '$CI_COMMIT_TAG != null'
252
+ - if: "$CI_COMMIT_TAG != null"
246
253
  variables:
247
254
  TARGET_BRANCH: $CI_COMMIT_TAG
248
255
  - if: '$CI_COMMIT_REF_NAME == "main" && $CI_PROJECT_PATH == "bec/bec_widgets"'
CHANGELOG.md CHANGED
@@ -1,6 +1,42 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v0.64.0 (2024-06-19)
3
4
 
5
+ ### Ci
6
+
7
+ * ci: add job optional dependency check ([`27426ce`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/27426ce7a52b4cbad7f3bef114d6efe6ad73bd7f))
8
+
9
+ ### Documentation
10
+
11
+ * docs: fix links in developer section ([`9e16f2f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9e16f2faf9c59a5d36ae878512c5a910cca31e69))
12
+
13
+ * docs: refactor developer section, add widget tutorial ([`2a36d93`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/2a36d9364f242bf42e4cda4b50e6f46aa3833bbd))
14
+
15
+ ### Feature
16
+
17
+ * feat: add option to change size of the fonts ([`ea805d1`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ea805d1362fc084d3b703b6f81b0180072f0825d))
18
+
19
+ ### Fix
20
+
21
+ * fix(plot_base): font size is set with setScale which is scaling the whole legend window ([`5d66720`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5d6672069ea1cbceb62104f66c127e4e3c23e4a4))
22
+
23
+ ### Test
24
+
25
+ * test: add tests ([`140ad83`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/140ad83380808928edf7953e23c762ab72a0a1e9))
26
+
27
+ ## v0.63.2 (2024-06-14)
28
+
29
+ ### Fix
30
+
31
+ * fix: do not import "server" in client, prevents from having trouble with QApplication creation order
32
+
33
+ Like with QtWebEngine ([`6f96498`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6f96498de66358b89f3a2035627eed2e02dde5a1))
34
+
35
+ ### Unknown
36
+
37
+ * Reapply "feat: implement non-polling, interruptible waiting of gui instruction response with timeout"
38
+
39
+ This reverts commit fe04dd80e59a0e74f7fdea603e0642707ecc7c2a. ([`836b6e6`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/836b6e64f694916d6b6f909dedf11a4a6d2c86a4))
4
40
 
5
41
  ## v0.63.1 (2024-06-13)
6
42
 
@@ -11,7 +47,6 @@
11
47
  The proper finalization sequence will be executed by the remote process
12
48
  on SIGTERM ([`9263f8e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9263f8ef5c17ae7a007a1a564baf787b39061756))
13
49
 
14
-
15
50
  ## v0.63.0 (2024-06-13)
16
51
 
17
52
  ### Documentation
@@ -36,7 +71,6 @@ on SIGTERM ([`9263f8e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9263f8ef5
36
71
 
37
72
  This reverts commit abc6caa2d0b6141dfbe1f3d025f78ae14deddcb3 ([`fe04dd8`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fe04dd80e59a0e74f7fdea603e0642707ecc7c2a))
38
73
 
39
-
40
74
  ## v0.62.0 (2024-06-12)
41
75
 
42
76
  ### Feature
@@ -47,7 +81,6 @@ This reverts commit abc6caa2d0b6141dfbe1f3d025f78ae14deddcb3 ([`fe04dd8`](https:
47
81
 
48
82
  * doc: add documentation about creating custom GUI applications embedding BEC Widgets ([`17a0068`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/17a00687579f5efab1990cd83862ec0e78198633))
49
83
 
50
-
51
84
  ## v0.61.0 (2024-06-12)
52
85
 
53
86
  ### Feature
@@ -58,7 +91,6 @@ This reverts commit abc6caa2d0b6141dfbe1f3d025f78ae14deddcb3 ([`fe04dd8`](https:
58
91
 
59
92
  * refactor: improve labe of auto_update script ([`40b5688`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/40b568815893cd41af3531bb2e647ca1e2e315f4))
60
93
 
61
-
62
94
  ## v0.60.0 (2024-06-08)
63
95
 
64
96
  ### Ci
@@ -101,14 +133,12 @@ This reverts commit abc6caa2d0b6141dfbe1f3d025f78ae14deddcb3 ([`fe04dd8`](https:
101
133
 
102
134
  * test: added missing pylint statement to header ([`f662985`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/f6629852ebc2b4ee239fa560cc310a5ae2627cf7))
103
135
 
104
-
105
136
  ## v0.59.1 (2024-06-07)
106
137
 
107
138
  ### Fix
108
139
 
109
140
  * fix(curve): set_color_map_z typo fixed in user access ([`e7838b0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e7838b0f2fc23b0a232ed7d68fbd7f3493a91b9e))
110
141
 
111
-
112
142
  ## v0.59.0 (2024-06-07)
113
143
 
114
144
  ### Build
@@ -129,44 +159,10 @@ This reverts commit abc6caa2d0b6141dfbe1f3d025f78ae14deddcb3 ([`fe04dd8`](https:
129
159
 
130
160
  * feat(widget): added simple website widget with rpc ([`64abd67`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/64abd67b9b416bff9c89880b248d6e8639aa1e70))
131
161
 
132
-
133
162
  ## v0.58.1 (2024-06-07)
134
163
 
135
164
  ### Fix
136
165
 
137
166
  * fix(dock): new dock can be detached upon creation ([`02a2608`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/02a26086c4540127a11c235cba30afc4fd712007))
138
167
 
139
-
140
168
  ## v0.58.0 (2024-06-07)
141
-
142
- ### Feature
143
-
144
- * feat(utils.colors): general color validators ([`3094632`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/30946321348abc349fb4003dc39d0232dc19606c))
145
-
146
- ### Fix
147
-
148
- * fix: bar colormap dynamic setting ([`67fd5e8`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/67fd5e8581f60fe64027ac57f1f12cefa4d28343))
149
-
150
- * fix: formatting isort ([`bf699ec`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/bf699ec1fbe2aacd31854e84fb0438c336840fcf))
151
-
152
- * fix(curve): 2D scatter updated if color_map_z is changed ([`6985ff0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6985ff0fcef9791b53198206ec8cbccd1d65ef99))
153
-
154
- * fix(curve): color_map_z setting works ([`33f7be4`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/33f7be42c512402dab3fdd9781a8234e3ec5f4ba))
155
-
156
- ### Test
157
-
158
- * test(color): validation tests added ([`c0ddece`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c0ddeceeeabacbf33019a8f24b18821926dc17ac))
159
-
160
-
161
- ## v0.57.7 (2024-06-07)
162
-
163
- ### Documentation
164
-
165
- * docs: added schema of BECDockArea and BECFigure ([`828067f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/828067f486a905eb4678538df58e2bdd6c770de1))
166
-
167
- ### Fix
168
-
169
- * fix: add model_config to pydantic models to allow runtime checks after creation ([`ca5e8d2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ca5e8d2fbbffbf221cc5472710fef81a33ee29d6))
170
-
171
-
172
- ## v0.57.6 (2024-06-06)
PKG-INFO CHANGED
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.63.1
3
+ Version: 0.64.0
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
bec_widgets/cli/client.py CHANGED
@@ -1044,33 +1044,37 @@ class BECImageShow(RPCBase):
1044
1044
  - y_scale: Literal["linear", "log"]
1045
1045
  - x_lim: tuple
1046
1046
  - y_lim: tuple
1047
+ - legend_label_size: int
1047
1048
  """
1048
1049
 
1049
1050
  @rpc_call
1050
- def set_title(self, title: "str"):
1051
+ def set_title(self, title: "str", size: "int" = None):
1051
1052
  """
1052
1053
  Set the title of the plot widget.
1053
1054
 
1054
1055
  Args:
1055
1056
  title(str): Title of the plot widget.
1057
+ size(int): Font size of the title.
1056
1058
  """
1057
1059
 
1058
1060
  @rpc_call
1059
- def set_x_label(self, label: "str"):
1061
+ def set_x_label(self, label: "str", size: "int" = None):
1060
1062
  """
1061
1063
  Set the label of the x-axis.
1062
1064
 
1063
1065
  Args:
1064
1066
  label(str): Label of the x-axis.
1067
+ size(int): Font size of the label.
1065
1068
  """
1066
1069
 
1067
1070
  @rpc_call
1068
- def set_y_label(self, label: "str"):
1071
+ def set_y_label(self, label: "str", size: "int" = None):
1069
1072
  """
1070
1073
  Set the label of the y-axis.
1071
1074
 
1072
1075
  Args:
1073
1076
  label(str): Label of the y-axis.
1077
+ size(int): Font size of the label.
1074
1078
  """
1075
1079
 
1076
1080
  @rpc_call
@@ -1268,33 +1272,37 @@ class BECPlotBase(RPCBase):
1268
1272
  - y_scale: Literal["linear", "log"]
1269
1273
  - x_lim: tuple
1270
1274
  - y_lim: tuple
1275
+ - legend_label_size: int
1271
1276
  """
1272
1277
 
1273
1278
  @rpc_call
1274
- def set_title(self, title: "str"):
1279
+ def set_title(self, title: "str", size: "int" = None):
1275
1280
  """
1276
1281
  Set the title of the plot widget.
1277
1282
 
1278
1283
  Args:
1279
1284
  title(str): Title of the plot widget.
1285
+ size(int): Font size of the title.
1280
1286
  """
1281
1287
 
1282
1288
  @rpc_call
1283
- def set_x_label(self, label: "str"):
1289
+ def set_x_label(self, label: "str", size: "int" = None):
1284
1290
  """
1285
1291
  Set the label of the x-axis.
1286
1292
 
1287
1293
  Args:
1288
1294
  label(str): Label of the x-axis.
1295
+ size(int): Font size of the label.
1289
1296
  """
1290
1297
 
1291
1298
  @rpc_call
1292
- def set_y_label(self, label: "str"):
1299
+ def set_y_label(self, label: "str", size: "int" = None):
1293
1300
  """
1294
1301
  Set the label of the y-axis.
1295
1302
 
1296
1303
  Args:
1297
1304
  label(str): Label of the y-axis.
1305
+ size(int): Font size of the label.
1298
1306
  """
1299
1307
 
1300
1308
  @rpc_call
@@ -1370,6 +1378,15 @@ class BECPlotBase(RPCBase):
1370
1378
  Remove the plot widget from the figure.
1371
1379
  """
1372
1380
 
1381
+ @rpc_call
1382
+ def set_legend_label_size(self, size: "int" = None):
1383
+ """
1384
+ Set the font size of the legend.
1385
+
1386
+ Args:
1387
+ size(int): Font size of the legend.
1388
+ """
1389
+
1373
1390
 
1374
1391
  class BECWaveform(RPCBase):
1375
1392
  @property
@@ -1516,33 +1533,37 @@ class BECWaveform(RPCBase):
1516
1533
  - y_scale: Literal["linear", "log"]
1517
1534
  - x_lim: tuple
1518
1535
  - y_lim: tuple
1536
+ - legend_label_size: int
1519
1537
  """
1520
1538
 
1521
1539
  @rpc_call
1522
- def set_title(self, title: "str"):
1540
+ def set_title(self, title: "str", size: "int" = None):
1523
1541
  """
1524
1542
  Set the title of the plot widget.
1525
1543
 
1526
1544
  Args:
1527
1545
  title(str): Title of the plot widget.
1546
+ size(int): Font size of the title.
1528
1547
  """
1529
1548
 
1530
1549
  @rpc_call
1531
- def set_x_label(self, label: "str"):
1550
+ def set_x_label(self, label: "str", size: "int" = None):
1532
1551
  """
1533
1552
  Set the label of the x-axis.
1534
1553
 
1535
1554
  Args:
1536
1555
  label(str): Label of the x-axis.
1556
+ size(int): Font size of the label.
1537
1557
  """
1538
1558
 
1539
1559
  @rpc_call
1540
- def set_y_label(self, label: "str"):
1560
+ def set_y_label(self, label: "str", size: "int" = None):
1541
1561
  """
1542
1562
  Set the label of the y-axis.
1543
1563
 
1544
1564
  Args:
1545
1565
  label(str): Label of the y-axis.
1566
+ size(int): Font size of the label.
1546
1567
  """
1547
1568
 
1548
1569
  @rpc_call
@@ -1618,6 +1639,15 @@ class BECWaveform(RPCBase):
1618
1639
  Remove the plot widget from the figure.
1619
1640
  """
1620
1641
 
1642
+ @rpc_call
1643
+ def set_legend_label_size(self, size: "int" = None):
1644
+ """
1645
+ Set the font size of the legend.
1646
+
1647
+ Args:
1648
+ size(int): Font size of the legend.
1649
+ """
1650
+
1621
1651
 
1622
1652
  class Ring(RPCBase):
1623
1653
  @rpc_call
@@ -14,7 +14,7 @@ from typing import TYPE_CHECKING
14
14
 
15
15
  from bec_lib.endpoints import MessageEndpoints
16
16
  from bec_lib.utils.import_utils import isinstance_based_on_class_name, lazy_import, lazy_import_from
17
- from qtpy.QtCore import QCoreApplication
17
+ from qtpy.QtCore import QEventLoop, QSocketNotifier, QTimer
18
18
 
19
19
  import bec_widgets.cli.client as client
20
20
  from bec_widgets.cli.auto_updates import AutoUpdates
@@ -24,6 +24,8 @@ if TYPE_CHECKING:
24
24
 
25
25
  from bec_widgets.cli.client import BECDockArea, BECFigure
26
26
 
27
+ from bec_lib.serialization import MsgpackSerialization
28
+
27
29
  messages = lazy_import("bec_lib.messages")
28
30
  # from bec_lib.connector import MessageObject
29
31
  MessageObject = lazy_import_from("bec_lib.connector", ("MessageObject",))
@@ -84,13 +86,8 @@ def _start_plot_process(gui_id, gui_class, config) -> None:
84
86
  Start the plot in a new process.
85
87
  """
86
88
  # pylint: disable=subprocess-run-check
87
- monitor_module = importlib.import_module("bec_widgets.cli.server")
88
- monitor_path = monitor_module.__file__
89
-
90
89
  command = [
91
- sys.executable,
92
- "-u",
93
- monitor_path,
90
+ "bec-gui-server",
94
91
  "--id",
95
92
  gui_id,
96
93
  "--config",
@@ -98,7 +95,11 @@ def _start_plot_process(gui_id, gui_class, config) -> None:
98
95
  "--gui_class",
99
96
  gui_class.__name__,
100
97
  ]
101
- process = subprocess.Popen(command, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
98
+ env_dict = os.environ.copy()
99
+ env_dict["PYTHONUNBUFFERED"] = "1"
100
+ process = subprocess.Popen(
101
+ command, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env_dict
102
+ )
102
103
  process_output_processing_thread = threading.Thread(target=_get_output, args=(process,))
103
104
  process_output_processing_thread.start()
104
105
  return process, process_output_processing_thread
@@ -200,6 +201,48 @@ class RPCResponseTimeoutError(Exception):
200
201
  )
201
202
 
202
203
 
204
+ class QtRedisMessageWaiter:
205
+ def __init__(self, redis_connector, message_to_wait):
206
+ self.ev_loop = QEventLoop()
207
+ self.response = None
208
+ self.connector = redis_connector
209
+ self.message_to_wait = message_to_wait
210
+ self.pubsub = redis_connector._redis_conn.pubsub()
211
+ self.pubsub.subscribe(self.message_to_wait.endpoint)
212
+ fd = self.pubsub.connection._sock.fileno()
213
+ self.notifier = QSocketNotifier(fd, QSocketNotifier.Read)
214
+ self.notifier.activated.connect(self._pubsub_readable)
215
+
216
+ def _msg_received(self, msg_obj):
217
+ self.response = msg_obj.value
218
+ self.ev_loop.quit()
219
+
220
+ def wait(self, timeout=1):
221
+ timer = QTimer()
222
+ timer.singleShot(timeout * 1000, self.ev_loop.quit)
223
+ self.ev_loop.exec_()
224
+ timer.stop()
225
+ self.notifier.setEnabled(False)
226
+ self.pubsub.close()
227
+ return self.response
228
+
229
+ def _pubsub_readable(self, fd):
230
+ while True:
231
+ msg = self.pubsub.get_message()
232
+ if msg:
233
+ if msg["type"] == "subscribe":
234
+ # get_message buffers, so we may already have the answer
235
+ # let's check...
236
+ continue
237
+ else:
238
+ break
239
+ else:
240
+ return
241
+ channel = msg["channel"].decode()
242
+ msg = MessageObject(topic=channel, value=MsgpackSerialization.loads(msg["data"]))
243
+ self.connector._execute_callback(self._msg_received, msg, {})
244
+
245
+
203
246
  class RPCBase:
204
247
  def __init__(self, gui_id: str = None, config: dict = None, parent=None) -> None:
205
248
  self._client = BECDispatcher().client
@@ -226,7 +269,7 @@ class RPCBase:
226
269
  parent = parent._parent
227
270
  return parent
228
271
 
229
- def _run_rpc(self, method, *args, wait_for_rpc_response=True, **kwargs):
272
+ def _run_rpc(self, method, *args, wait_for_rpc_response=True, timeout=3, **kwargs):
230
273
  """
231
274
  Run the RPC call.
232
275
 
@@ -248,16 +291,24 @@ class RPCBase:
248
291
 
249
292
  # pylint: disable=protected-access
250
293
  receiver = self._root._gui_id
294
+ if wait_for_rpc_response:
295
+ redis_msg = QtRedisMessageWaiter(
296
+ self._client.connector, MessageEndpoints.gui_instruction_response(request_id)
297
+ )
298
+
251
299
  self._client.connector.set_and_publish(MessageEndpoints.gui_instructions(receiver), rpc_msg)
252
300
 
253
- if not wait_for_rpc_response:
254
- return None
255
- response = self._wait_for_response(request_id)
256
- # get class name
257
- if not response.content["accepted"]:
258
- raise ValueError(response.content["message"]["error"])
259
- msg_result = response.content["message"].get("result")
260
- return self._create_widget_from_msg_result(msg_result)
301
+ if wait_for_rpc_response:
302
+ response = redis_msg.wait(timeout)
303
+
304
+ if response is None:
305
+ raise RPCResponseTimeoutError(request_id, timeout)
306
+
307
+ # get class name
308
+ if not response.accepted:
309
+ raise ValueError(response.message["error"])
310
+ msg_result = response.message.get("result")
311
+ return self._create_widget_from_msg_result(msg_result)
261
312
 
262
313
  def _create_widget_from_msg_result(self, msg_result):
263
314
  if msg_result is None:
@@ -280,30 +331,6 @@ class RPCBase:
280
331
  return cls(parent=self, **msg_result)
281
332
  return msg_result
282
333
 
283
- def _wait_for_response(self, request_id: str, timeout: int = 5):
284
- """
285
- Wait for the response from the server.
286
-
287
- Args:
288
- request_id(str): The request ID.
289
- timeout(int): The timeout in seconds.
290
-
291
- Returns:
292
- The response from the server.
293
- """
294
- start_time = time.time()
295
- response = None
296
-
297
- while response is None and self.gui_is_alive() and (time.time() - start_time) < timeout:
298
- response = self._client.connector.get(
299
- MessageEndpoints.gui_instruction_response(request_id)
300
- )
301
- QCoreApplication.processEvents() # keep UI responsive (and execute signals/slots)
302
- if response is None and (time.time() - start_time) >= timeout:
303
- raise RPCResponseTimeoutError(request_id, timeout)
304
-
305
- return response
306
-
307
334
  def gui_is_alive(self):
308
335
  """
309
336
  Check if the GUI is alive.
bec_widgets/cli/server.py CHANGED
@@ -114,7 +114,7 @@ class BECWidgetsCLIServer:
114
114
  self.client.shutdown()
115
115
 
116
116
 
117
- if __name__ == "__main__": # pragma: no cover
117
+ def main():
118
118
  import argparse
119
119
  import os
120
120
  import sys
@@ -166,3 +166,7 @@ if __name__ == "__main__": # pragma: no cover
166
166
 
167
167
  app.aboutToQuit.connect(server.shutdown)
168
168
  sys.exit(app.exec())
169
+
170
+
171
+ if __name__ == "__main__": # pragma: no cover
172
+ main()
@@ -136,17 +136,18 @@ if __name__ == "__main__": # pragma: no cover
136
136
 
137
137
  module_path = os.path.dirname(bec_widgets.__file__)
138
138
 
139
- bec_dispatcher = BECDispatcher()
140
- client = bec_dispatcher.client
141
- client.start()
142
-
143
139
  app = QApplication(sys.argv)
144
140
  app.setApplicationName("Jupyter Console")
145
141
  app.setApplicationDisplayName("Jupyter Console")
146
- # qdarktheme.setup_theme("auto")
142
+ qdarktheme.setup_theme("auto")
147
143
  icon = QIcon()
148
144
  icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
149
145
  app.setWindowIcon(icon)
146
+
147
+ bec_dispatcher = BECDispatcher()
148
+ client = bec_dispatcher.client
149
+ client.start()
150
+
150
151
  win = JupyterConsoleWindow()
151
152
  win.show()
152
153
 
@@ -9,7 +9,7 @@ import redis
9
9
  from bec_lib.client import BECClient
10
10
  from bec_lib.redis_connector import MessageObject, RedisConnector
11
11
  from bec_lib.service_config import ServiceConfig
12
- from qtpy.QtCore import QObject
12
+ from qtpy.QtCore import QCoreApplication, QObject
13
13
  from qtpy.QtCore import Signal as pyqtSignal
14
14
 
15
15
  if TYPE_CHECKING:
@@ -71,6 +71,7 @@ class BECDispatcher:
71
71
 
72
72
  _instance = None
73
73
  _initialized = False
74
+ qapp = None
74
75
 
75
76
  def __new__(cls, client=None, config: str = None, *args, **kwargs):
76
77
  if cls._instance is None:
@@ -82,6 +83,9 @@ class BECDispatcher:
82
83
  if self._initialized:
83
84
  return
84
85
 
86
+ if not QCoreApplication.instance():
87
+ BECDispatcher.qapp = QCoreApplication([])
88
+
85
89
  self._slots = collections.defaultdict(set)
86
90
  self.client = client
87
91
 
@@ -711,6 +711,12 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
711
711
  qdarktheme.setup_theme(theme)
712
712
  self.setBackground("k" if theme == "dark" else "w")
713
713
  self.config.theme = theme
714
+ for plot in self.widget_list:
715
+ plot.set_x_label(plot.plot_item.getAxis("bottom").label.toPlainText())
716
+ plot.set_y_label(plot.plot_item.getAxis("left").label.toPlainText())
717
+ if plot.plot_item.titleLabel.text:
718
+ plot.set_title(plot.plot_item.titleLabel.text)
719
+ plot.set_legend_label_size()
714
720
 
715
721
  def _remove_by_coordinates(self, row: int, col: int) -> None:
716
722
  """
@@ -5,6 +5,8 @@ from typing import Literal, Optional
5
5
  import numpy as np
6
6
  import pyqtgraph as pg
7
7
  from pydantic import BaseModel, Field
8
+ from qtpy import QT_VERSION
9
+ from qtpy.QtGui import QFont, QFontDatabase, QFontInfo
8
10
  from qtpy.QtWidgets import QWidget
9
11
 
10
12
  from bec_widgets.utils import BECConnector, ConnectionConfig
@@ -12,8 +14,14 @@ from bec_widgets.utils import BECConnector, ConnectionConfig
12
14
 
13
15
  class AxisConfig(BaseModel):
14
16
  title: Optional[str] = Field(None, description="The title of the axes.")
17
+ title_size: Optional[int] = Field(None, description="The font size of the title.")
15
18
  x_label: Optional[str] = Field(None, description="The label for the x-axis.")
19
+ x_label_size: Optional[int] = Field(None, description="The font size of the x-axis label.")
16
20
  y_label: Optional[str] = Field(None, description="The label for the y-axis.")
21
+ y_label_size: Optional[int] = Field(None, description="The font size of the y-axis label.")
22
+ legend_label_size: Optional[int] = Field(
23
+ None, description="The font size of the legend labels."
24
+ )
17
25
  x_scale: Literal["linear", "log"] = Field("linear", description="The scale of the x-axis.")
18
26
  y_scale: Literal["linear", "log"] = Field("linear", description="The scale of the y-axis.")
19
27
  x_lim: Optional[tuple] = Field(None, description="The limits of the x-axis.")
@@ -50,6 +58,7 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
50
58
  "set_grid",
51
59
  "lock_aspect_ratio",
52
60
  "remove",
61
+ "set_legend_label_size",
53
62
  ]
54
63
 
55
64
  def __init__(
@@ -85,6 +94,7 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
85
94
  - y_scale: Literal["linear", "log"]
86
95
  - x_lim: tuple
87
96
  - y_lim: tuple
97
+ - legend_label_size: int
88
98
  """
89
99
  # Mapping of keywords to setter methods
90
100
  method_map = {
@@ -95,6 +105,7 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
95
105
  "y_scale": self.set_y_scale,
96
106
  "x_lim": self.set_x_lim,
97
107
  "y_lim": self.set_y_lim,
108
+ "legend_label_size": self.set_legend_label_size,
98
109
  }
99
110
  for key, value in kwargs.items():
100
111
  if key in method_map:
@@ -116,34 +127,79 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
116
127
 
117
128
  self.set(**{k: v for k, v in config_mappings.items() if v is not None})
118
129
 
119
- def set_title(self, title: str):
130
+ def set_legend_label_size(self, size: int = None):
131
+ """
132
+ Set the font size of the legend.
133
+
134
+ Args:
135
+ size(int): Font size of the legend.
136
+ """
137
+ if not self.plot_item.legend:
138
+ return
139
+ if self.config.axis.legend_label_size or size:
140
+ if size:
141
+ self.config.axis.legend_label_size = size
142
+ scale = (
143
+ size / 9
144
+ ) # 9 is the default font size of the legend, so we always scale it against 9
145
+ self.plot_item.legend.setScale(scale)
146
+
147
+ def get_text_color(self):
148
+ return "#FFF" if self.figure.config.theme == "dark" else "#000"
149
+
150
+ def set_title(self, title: str, size: int = None):
120
151
  """
121
152
  Set the title of the plot widget.
122
153
 
123
154
  Args:
124
155
  title(str): Title of the plot widget.
156
+ size(int): Font size of the title.
125
157
  """
126
- self.plot_item.setTitle(title)
158
+ if self.config.axis.title_size or size:
159
+ if size:
160
+ self.config.axis.title_size = size
161
+ style = {"color": self.get_text_color(), "size": f"{self.config.axis.title_size}pt"}
162
+ else:
163
+ style = {}
164
+ self.plot_item.setTitle(title, **style)
127
165
  self.config.axis.title = title
128
166
 
129
- def set_x_label(self, label: str):
167
+ def set_x_label(self, label: str, size: int = None):
130
168
  """
131
169
  Set the label of the x-axis.
132
170
 
133
171
  Args:
134
172
  label(str): Label of the x-axis.
173
+ size(int): Font size of the label.
135
174
  """
136
- self.plot_item.setLabel("bottom", label)
175
+ if self.config.axis.x_label_size or size:
176
+ if size:
177
+ self.config.axis.x_label_size = size
178
+ style = {
179
+ "color": self.get_text_color(),
180
+ "font-size": f"{self.config.axis.x_label_size}pt",
181
+ }
182
+ else:
183
+ style = {}
184
+ self.plot_item.setLabel("bottom", label, **style)
137
185
  self.config.axis.x_label = label
138
186
 
139
- def set_y_label(self, label: str):
187
+ def set_y_label(self, label: str, size: int = None):
140
188
  """
141
189
  Set the label of the y-axis.
142
190
 
143
191
  Args:
144
192
  label(str): Label of the y-axis.
193
+ size(int): Font size of the label.
145
194
  """
146
- self.plot_item.setLabel("left", label)
195
+ if self.config.axis.y_label_size or size:
196
+ if size:
197
+ self.config.axis.y_label_size = size
198
+ color = self.get_text_color()
199
+ style = {"color": color, "font-size": f"{self.config.axis.y_label_size}pt"}
200
+ else:
201
+ style = {}
202
+ self.plot_item.setLabel("left", label, **style)
147
203
  self.config.axis.y_label = label
148
204
 
149
205
  def set_x_scale(self, scale: Literal["linear", "log"] = "linear"):
@@ -54,6 +54,7 @@ class BECWaveform(BECPlotBase):
54
54
  "set_grid",
55
55
  "lock_aspect_ratio",
56
56
  "remove",
57
+ "set_legend_label_size",
57
58
  ]
58
59
  scan_signal_update = pyqtSignal()
59
60
 
@@ -401,6 +402,7 @@ class BECWaveform(BECPlotBase):
401
402
  self.config.curves[name] = curve.config
402
403
  if data is not None:
403
404
  curve.setData(data[0], data[1])
405
+ self.set_legend_label_size()
404
406
  return curve
405
407
 
406
408
  def _validate_signal_entries(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.63.1
3
+ Version: 0.64.0
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
@@ -1,12 +1,12 @@
1
1
  .gitignore,sha256=cMQ1MLmnoR88aMCCJwUyfoTnufzl4-ckmHtlFUqHcT4,3253
2
- .gitlab-ci.yml,sha256=3PU2LONUl10zIOD4UCPQgA6vVBtniabww1MQkTMce7I,7995
2
+ .gitlab-ci.yml,sha256=RnYDz4zKXjlqltTryprlB1s5vLXxI2-seW-Vb70NNF0,8162
3
3
  .pylintrc,sha256=OstrgmEyP0smNFBKoIN5_26-UmNZgMHnbjvAWX0UrLs,18535
4
4
  .readthedocs.yaml,sha256=aSOc277LqXcsTI6lgvm_JY80lMlr69GbPKgivua2cS0,603
5
- CHANGELOG.md,sha256=2guAV_VW9TfxaJIOGzjUg0l968nM8kwFLtXNUkop-jY,6936
5
+ CHANGELOG.md,sha256=oJUOSheyA1XXVuJQbOh90mASfayceKUL5vyRuCGVFz8,7168
6
6
  LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
7
- PKG-INFO,sha256=MNvEiOQ0tVlzDg9MrZ4Jq1HjSIb0l2Lg14-2kN9IgqQ,1302
7
+ PKG-INFO,sha256=8_5TOAKvNZUR-EyOtHmnfsMxHs9APbANd9lT0KJDKuA,1302
8
8
  README.md,sha256=y4jB6wvArS7N8_iTbKWnSM_oRAqLA2GqgzUR-FMh5sU,2645
9
- pyproject.toml,sha256=oJZwUnqVMwN3MDK_gvSWFIVyGvKEidp-NyAgJwB_LUQ,2115
9
+ pyproject.toml,sha256=ehF68kmg-x2Wu2rZ9_D1U7PlbezNVz9n-bX07RJyl48,2162
10
10
  .git_hooks/pre-commit,sha256=n3RofIZHJl8zfJJIUomcMyYGFi_rwq4CC19z0snz3FI,286
11
11
  .gitlab/issue_templates/bug_report_template.md,sha256=gAuyEwl7XlnebBrkiJ9AqffSNOywmr8vygUFWKTuQeI,386
12
12
  .gitlab/issue_templates/documentation_update_template.md,sha256=FHLdb3TS_D9aL4CYZCjyXSulbaW5mrN2CmwTaeLPbNw,860
@@ -17,22 +17,22 @@ bec_widgets/assets/bec_widgets_icon.png,sha256=K8dgGwIjalDh9PRHUsSQBqgdX7a00nM3i
17
17
  bec_widgets/assets/terminal_icon.png,sha256=bJl7Tft4Fi2uxvuXI8o14uMHnI9eAWKSU2uftXCH9ws,3889
18
18
  bec_widgets/cli/__init__.py,sha256=d0Q6Fn44e7wFfLabDOBxpcJ1DPKWlFunGYDUBmO-4hA,22
19
19
  bec_widgets/cli/auto_updates.py,sha256=DyBV3HnjMSH-cvVkYNcDiYKVf0Xut4Qy2qGQqkW47Bw,4833
20
- bec_widgets/cli/client.py,sha256=PkKPeR4KJjJP-DOPTq3yYJIuWlwXLHjTyZunCYSsU1I,55332
21
- bec_widgets/cli/client_utils.py,sha256=tGfe3OKCDxgPHWKbJsM8myHooDwKNa-e5bjqGrtwwLg,10464
20
+ bec_widgets/cli/client.py,sha256=GJRzys0DVHQp8X9QxociTrshPm4CvaPtEprxWEpEKCs,56446
21
+ bec_widgets/cli/client_utils.py,sha256=ttEE3iyMpK-yEbIAJsI8rXGVn27UT4GYzyrAEZIqFks,11400
22
22
  bec_widgets/cli/generate_cli.py,sha256=DIaGz7nhwef3ebIaP4LtiUC3q7MoM1swJ_e0SgAO2jo,6901
23
23
  bec_widgets/cli/rpc_register.py,sha256=QxXUZu5XNg00Yf5O3UHWOXg3-f_pzKjjoZYMOa-MOJc,2216
24
24
  bec_widgets/cli/rpc_wigdet_handler.py,sha256=1oE2TSbwQdfLEaZiscyDX2eExHsenp2BF5Lwy8PE6LA,1118
25
- bec_widgets/cli/server.py,sha256=rsj31Vsx6ayThNe4PQelQFahGjYXFZjfrNyB2fnm6Ro,5737
25
+ bec_widgets/cli/server.py,sha256=1iHDbYxNcsUz-HxFEJ2aM1z4sut-quaftyp4EFeGLkw,5762
26
26
  bec_widgets/examples/__init__.py,sha256=WWQ0cu7m8sA4Ehy-DWdTIqSISjaHsbxhsNmNrMnhDZU,202
27
27
  bec_widgets/examples/jupyter_console/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- bec_widgets/examples/jupyter_console/jupyter_console_window.py,sha256=lViKNC3TOh6_-SztcKaRnYkf-V_EQ9T1cuyORskVX6c,5339
28
+ bec_widgets/examples/jupyter_console/jupyter_console_window.py,sha256=AKIlwcOMBJ8UAIBEhPipc9lDwA25UmmBDEYAfC0L7kU,5338
29
29
  bec_widgets/examples/jupyter_console/jupyter_console_window.ui,sha256=2A2mNTUMZBYygz8K4qWzrcjnNqZBMVyeHm26iLZVRWI,1473
30
30
  bec_widgets/examples/motor_movement/__init__.py,sha256=LzPJkxLAxOsZCbXR-fRCPmeYobp7Yqds6tDxW4W1gSw,214
31
31
  bec_widgets/examples/motor_movement/motor_control_compilations.py,sha256=8rpA7a2xVZTDMrx7YQIj3IJew78J1gcVMkHvloS0U_Q,9055
32
32
  bec_widgets/examples/motor_movement/motor_controller.ui,sha256=83XX6NGILwntoUIghvzWnMuGf80O8khK3SduVKTAEFM,29105
33
33
  bec_widgets/utils/__init__.py,sha256=B7OZ2ArjyFaGNh4XYIbk49agnYCz704ltuFSalLCjSA,481
34
34
  bec_widgets/utils/bec_connector.py,sha256=RxHJNF7JjtY5pRbTMu2eQTiRXvoyJ53QuTYxHjZba38,5357
35
- bec_widgets/utils/bec_dispatcher.py,sha256=nLdcj2u4dy8-ZR03XioCzr7hBg9Wq4Kw58OU6sDorT4,5593
35
+ bec_widgets/utils/bec_dispatcher.py,sha256=3zzf7LXCWtxiroUuSdObGexuYfRoq0QY1i3hJ7GmbBE,5726
36
36
  bec_widgets/utils/bec_table.py,sha256=nA2b8ukSeUfquFMAxGrUVOqdrzMoDYD6O_4EYbOG2zk,717
37
37
  bec_widgets/utils/colors.py,sha256=GYSDe0ZxsJSwxvuy-yG2BH17qlf_Sjq8dhDcyp9IhBI,8532
38
38
  bec_widgets/utils/container_utils.py,sha256=m3VUyAYmSWkEwApP9tBvKxPYVtc2kHw4toxIpMryJy4,1495
@@ -54,9 +54,9 @@ bec_widgets/widgets/dock/__init__.py,sha256=B7foHt02gnhM7mFksa7GJVwT7n0j_JvYDCt6
54
54
  bec_widgets/widgets/dock/dock.py,sha256=WPanKj6nodVP6PiEFkRTCj5Lf0pUupmM7i-5qZA_ATY,7596
55
55
  bec_widgets/widgets/dock/dock_area.py,sha256=9c_tLzyBRllLfc4H5o9-4bvasWp5hWe1NWg4mupXVtU,7911
56
56
  bec_widgets/widgets/figure/__init__.py,sha256=3hGx_KOV7QHCYAV06aNuUgKq4QIYCjUTad-DrwkUaBM,44
57
- bec_widgets/widgets/figure/figure.py,sha256=O--r3dyeOPXndV2400wpE9lPdBezzd0ZUt7yA2u2n0A,31468
57
+ bec_widgets/widgets/figure/figure.py,sha256=3bf1TyzIE8kVRDgjLqdlvCoE4wrozyfbeCWLjCo1Fwo,31821
58
58
  bec_widgets/widgets/figure/plots/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- bec_widgets/widgets/figure/plots/plot_base.py,sha256=XfOQaQUHA0qZheGiDs0CYdJswUAgQjBzjQM1XSdjo8k,8049
59
+ bec_widgets/widgets/figure/plots/plot_base.py,sha256=QdDMMuWwTK0f6kNN8aAPBM7jah7TpUbYrMrRTdb2EZY,10419
60
60
  bec_widgets/widgets/figure/plots/image/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
61
  bec_widgets/widgets/figure/plots/image/image.py,sha256=-rxCt1IXmS2XQu0dS0SSXAF8VaxacSmQ-_kDsFxbPm4,19653
62
62
  bec_widgets/widgets/figure/plots/image/image_item.py,sha256=1oytCY2IIgRbtS3GRrp9JV02KOif78O2-iaK0qYuHFU,9058
@@ -64,7 +64,7 @@ bec_widgets/widgets/figure/plots/image/image_processor.py,sha256=TOnHbdq9rK5--L5
64
64
  bec_widgets/widgets/figure/plots/motor_map/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
65
  bec_widgets/widgets/figure/plots/motor_map/motor_map.py,sha256=Ff2WoNHxO_A3ggsbSd_AVUP1JeOWMuJs-0GLskxn-94,15267
66
66
  bec_widgets/widgets/figure/plots/waveform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
- bec_widgets/widgets/figure/plots/waveform/waveform.py,sha256=f9YpsNufcICvZyDgcVujzdszdsh0_9gzvnRbpwZroLA,23490
67
+ bec_widgets/widgets/figure/plots/waveform/waveform.py,sha256=Z0cgQitW4SvBnQHvhsTJvx-2yoOW231GulhrM4o0hbA,23560
68
68
  bec_widgets/widgets/figure/plots/waveform/waveform_curve.py,sha256=lTyeCydzvrcdvQXc89jEjoor-Uvo54i197-_M4VtqX8,7970
69
69
  bec_widgets/widgets/jupyter_console/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
70
  bec_widgets/widgets/jupyter_console/jupyter_console.py,sha256=ioLYJL31RdBoAOGFSS8PVSnUhkWPWmLC3tiKp7CouO8,2251
@@ -109,7 +109,10 @@ docs/assets/index_contribute.svg,sha256=OCjvYBw_JhcY_D5Zd7f1MctQvq1YNalYlqPNwB1X
109
109
  docs/assets/index_getting_started.svg,sha256=Www1OXmauYlouZD51AR6-VG2vxrEig8-jjuDPhzkNxc,3977
110
110
  docs/assets/index_user_guide.svg,sha256=sRjKwOHVJStBYIQUFVcnfmbeXd2qAp0HYjleSp66XCI,6429
111
111
  docs/assets/rocket_launch_48dp.svg,sha256=pdrPrBcKWUa5OlgWKM0B6TA6qAW7E57d7C7YW2r1OT8,1070
112
- docs/developer/developer.md,sha256=7Z6sfkk_7BgwZ2vaX4z5_cJrs0miyeAYSGpqMbyBmOI,415
112
+ docs/developer/developer.md,sha256=VUdMnQBsSRCawYMFCe0vya5oj1MimLML7Pd58kY6fYY,765
113
+ docs/developer/getting_started/development.md,sha256=aYLmuLMYpp5FcIXeDUqCfcStIV8veuiMBjOt5bTW_30,1406
114
+ docs/developer/getting_started/getting_started.md,sha256=My_K_6O7LLaXVB_eINrRku5o-jVx95lsmGgHxgZhT7A,378
115
+ docs/developer/widgets/widgets.md,sha256=O7v0DsgCr-IULxl0TJ7NIGN68wd5kouKz1Y5ZuEvaEU,529
113
116
  docs/introduction/introduction.md,sha256=wp7jmhkUtJnSnEnmIAZGUcau_3-5e5-FohvZb63khw4,1432
114
117
  docs/user/customisation.md,sha256=MXqbljqokDXF3VhCeia1PITZe1mx1J3FfLTJ66TlaUA,3172
115
118
  docs/user/user.md,sha256=uCTcjclIi6rdjYRQebko6bWFEVsjyfshsVU3BDYrC-Y,1403
@@ -119,7 +122,7 @@ docs/user/getting_started/BECDockArea.png,sha256=t3vSm_rVRk371J5LOutbolETuEjStNc
119
122
  docs/user/getting_started/auto_updates.md,sha256=Gicx3lplI6JRBlnPj_VL6IhqOIcsWjYF4_EdZSCje2A,3754
120
123
  docs/user/getting_started/getting_started.md,sha256=lxZXCr6HAkM61oo5Bu-YjINSKo4wihWhAPJdotEAAVQ,358
121
124
  docs/user/getting_started/gui_complex_gui.gif,sha256=ovv9u371BGG5GqhzyBMl4mvqMHLfJS0ylr-dR0Ydwtw,6550393
122
- docs/user/getting_started/installation.md,sha256=nBl2Hfvo6ua3-tVZn1B-UG0hCTlrFY6_ibXHWnXeegs,1135
125
+ docs/user/getting_started/installation.md,sha256=gqMV44lh9-wkKtAtDckvnyX_d8oTBNinQxvriFQ9Sk4,1145
123
126
  docs/user/getting_started/quick_start.md,sha256=VGU880GwamcIZcBE8tjxuqX2syE-71jqZedtskCoBbA,9405
124
127
  docs/user/widgets/BECFigure.png,sha256=8dQr4u0uk_y0VV-R1Jh9yTR3Vidd9HDEno_07R0swaE,1605920
125
128
  docs/user/widgets/bec_figure.md,sha256=BwcumbhZd6a2zKmoHTvwKr8kG8WxBx9lS_QwxNiBMpQ,5155
@@ -129,7 +132,7 @@ docs/user/widgets/motor.gif,sha256=FtaWdRHx4UZaGJPpq8LNhMMgX4PFcAB6IZ93JCMEh_w,2
129
132
  docs/user/widgets/progress_bar.gif,sha256=5jh0Zw2BBGPuNxszV1DBLJCb4_6glIRX-U2ABjnsK2k,5263592
130
133
  docs/user/widgets/scatter_2D.gif,sha256=yHpsuAUseMafJjI_J5BcOhmE3nu9VFn_Xm9XHzJaH5I,13188862
131
134
  docs/user/widgets/spiral_progress_bar.md,sha256=QTgUDIl6XPuK_HwSfB6sNijZ4bss26biDg6B_mJ8Pxk,2208
132
- docs/user/widgets/text_box.md,sha256=i40AxKJP0PxrYW0x0up1VIovPFvemsaZoosGjOn4iZE,931
135
+ docs/user/widgets/text_box.md,sha256=_ST7RQWXl67MKLm6dTa995GjoughPUyK_hLnF8SPZcM,925
133
136
  docs/user/widgets/w1D.gif,sha256=tuHbleJpl6bJFNNC2OdndF5LF7IyfvlkFCMGZajrQPs,622773
134
137
  docs/user/widgets/website.md,sha256=wfudAupdtHX-Sfritg0xMWXZLLczJ4XwMLNWvu6ww-w,705
135
138
  docs/user/widgets/widgets.md,sha256=NzRfrgd4LWmZHa2Cs_1G59LeY5uAlFdy5aP00AtGAjk,380
@@ -152,13 +155,13 @@ tests/unit_tests/test_color_validation.py,sha256=csdvVKAohENZIRY-JQ97Hv-TShb1erj
152
155
  tests/unit_tests/test_crosshair.py,sha256=3OMAJ2ZaISYXMOtkXf1rPdy94vCr8njeLi6uHblBL9Q,5045
153
156
  tests/unit_tests/test_generate_cli_client.py,sha256=GmCLpyRWx5aREb66Api9T-OUpYE1wKgI4hhjUepYrvg,3408
154
157
  tests/unit_tests/test_motor_control.py,sha256=NBekcGALo5mYkuyBJvBhvJkWiQDV82hI4GmsobRzjTI,20770
155
- tests/unit_tests/test_plot_base.py,sha256=bOdlgAxh9oKk5PwiQ_MSFmzr44uJ61Tlg242RCIhl5c,2610
158
+ tests/unit_tests/test_plot_base.py,sha256=Akr_JgglUCrtERtdtsMqWko_MLUYoAYRGzV2sum-YHo,3836
156
159
  tests/unit_tests/test_rpc_register.py,sha256=hECjZEimd440mwRrO0rg7L3PKN7__3DgjmESN6wx3bo,1179
157
160
  tests/unit_tests/test_scan_control.py,sha256=7dtGpE0g4FqUhhQeCkyJl-9o7NH3DFZJgEaqDmBYbBc,7551
158
161
  tests/unit_tests/test_spiral_progress_bar.py,sha256=yak3N9-TmEM3lQZPSROL4cAx9mior__se1XADlMScks,12418
159
162
  tests/unit_tests/test_stop_button.py,sha256=hOoWO0emkvd5bR_EExxCnKsiZgXKqf_uIGTwzWLxhDw,704
160
163
  tests/unit_tests/test_text_box_widget.py,sha256=cT0uEHt_6d-FwST0A_wE9sFW9E3F_nJbKhuBAeU4yHg,1862
161
- tests/unit_tests/test_waveform1d.py,sha256=j9-CCE0BkFVI3Gnv8pjV1gc9HwA5PYG0_ox1oZ60F6w,15272
164
+ tests/unit_tests/test_waveform1d.py,sha256=I3_pF0ieltcTWtweOBjICaOxJ8NCQ0-NWxpKg8Pas3E,15893
162
165
  tests/unit_tests/test_website_widget.py,sha256=fBADIJJBAHU4Ro7u95kdemFVNv196UOcuO9oLHuHt8A,761
163
166
  tests/unit_tests/test_widget_io.py,sha256=FeL3ZYSBQnRt6jxj8VGYw1cmcicRQyHKleahw7XIyR0,3475
164
167
  tests/unit_tests/test_yaml_dialog.py,sha256=HNrqferkdg02-9ieOhhI2mr2Qvt7GrYgXmQ061YCTbg,5794
@@ -167,8 +170,8 @@ tests/unit_tests/test_configs/config_device_no_entry.yaml,sha256=hdvue9KLc_kfNzG
167
170
  tests/unit_tests/test_configs/config_scan.yaml,sha256=vo484BbWOjA_e-h6bTjSV9k7QaQHrlAvx-z8wtY-P4E,1915
168
171
  tests/unit_tests/test_msgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
169
172
  tests/unit_tests/test_msgs/available_scans_message.py,sha256=m_z97hIrjHXXMa2Ex-UvsPmTxOYXfjxyJaGkIY6StTY,46532
170
- bec_widgets-0.63.1.dist-info/METADATA,sha256=MNvEiOQ0tVlzDg9MrZ4Jq1HjSIb0l2Lg14-2kN9IgqQ,1302
171
- bec_widgets-0.63.1.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
172
- bec_widgets-0.63.1.dist-info/entry_points.txt,sha256=80s2YKCNziN2ROUYbpDRyEmiejMf_dshmiYCdN7qNsU,70
173
- bec_widgets-0.63.1.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
174
- bec_widgets-0.63.1.dist-info/RECORD,,
173
+ bec_widgets-0.64.0.dist-info/METADATA,sha256=8_5TOAKvNZUR-EyOtHmnfsMxHs9APbANd9lT0KJDKuA,1302
174
+ bec_widgets-0.64.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
175
+ bec_widgets-0.64.0.dist-info/entry_points.txt,sha256=OvoqiNzNF9bizFQNhbAmmdc_njHrnVewLE-Kl-u9sh0,115
176
+ bec_widgets-0.64.0.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
177
+ bec_widgets-0.64.0.dist-info/RECORD,,
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
+ bec-gui-server = bec_widgets.cli.server:main
2
3
  bw-generate-cli = bec_widgets.cli.generate_cli:main
@@ -1,18 +1,46 @@
1
1
  (developer)=
2
- # Development
2
+ # Developer
3
3
 
4
- To contribute to the development of BEC Widgets, start by setting up the development environment:
4
+ Welcome to the BEC Widgets developer guide! This section is intended for developers who want to contribute to the development of BEC Widgets.
5
5
 
6
- 1. **Clone the Repository**:
7
- ```bash
8
- git clone https://gitlab.psi.ch/bec/bec_widgets
9
- cd bec_widgets
6
+ ```{toctree}
7
+ ---
8
+ maxdepth: 2
9
+ hidden: true
10
+ ---
11
+
12
+ getting_started/getting_started.md
13
+ widgets/widgets.md
14
+ api_reference/api_reference.md
15
+ ```
16
+
17
+
18
+ ***
19
+
20
+ ````{grid} 2
21
+ :gutter: 5
22
+
23
+ ```{grid-item-card}
24
+ :link: developer.getting_started
25
+ :link-type: ref
26
+ :img-top: /assets/rocket_launch_48dp.svg
27
+ :text-align: center
28
+
29
+ ## Getting Started
30
+
31
+ Learn how to install BEC Widgets and get started with the framework.
10
32
  ```
11
- 2. **Install in Editable Mode**:
12
33
 
13
- Installing the package in editable mode allows you to make changes to the code and test them in real-time.
14
- ```bash
15
- pip install -e .[dev,pyqt6]
34
+ ```{grid-item-card}
35
+ :link: developer.widgets
36
+ :link-type: ref
37
+ :img-top: /assets/apps_48dp.svg
38
+ :text-align: center
39
+
40
+ ## Widgets
41
+
42
+ Learn about the building blocks of larger applications: widgets.
16
43
  ```
44
+ ````
17
45
 
18
46
 
@@ -0,0 +1,27 @@
1
+ (developer.development)=
2
+ # Development
3
+
4
+ If you like to contribute to the development of BEC Widgets, you can follow the steps below to set up your development environment.
5
+ BEC Widgets works in conjunction with [BEC](https://bec.readthedocs.io/en/latest/).
6
+ Therefore, we recommend that you install BEC first following the [developer instructions](https://bec.readthedocs.io/en/latest/developer/getting_started/install_developer_env.html) and include BEC Widgets.
7
+
8
+ If you already have a BEC environment set up, you can install BEC Widgets in editable mode into your BEC Python environment.
9
+
10
+ **Prerequisites**
11
+ 1. **Python Version:** BEC Widgets requires Python version 3.10 or higher. Verify your Python version to ensure compatibility.
12
+ 2. **BEC Installation:** BEC Widgets works in conjunction with BEC. While BEC is a dependency and will be installed automatically, you can find more information about BEC and its installation process in the [BEC documentation](https://beamline-experiment-control.readthedocs.io/en/latest/).
13
+
14
+ **Clone the Repository**:
15
+ ```bash
16
+ git clone https://gitlab.psi.ch/bec/bec_widgets
17
+ cd bec_widgets
18
+ ```
19
+ **Install in Editable Mode**:
20
+
21
+ Please install the package in editable mode into your BEC Python environemnt.
22
+ ```bash
23
+ pip install -e '.[dev,pyqt6]'
24
+ ```
25
+ This installs the package together with [PyQT6](https://www.riverbankcomputing.com/static/Docs/PyQt6/introduction.html).
26
+
27
+
@@ -0,0 +1,12 @@
1
+ (developer.getting_started)=
2
+ # Getting Started
3
+ This section provides valuable information for developers who want to contribute to the development of BEC Widgets. The guide will help you set up the development environment, understand the modular development concept of BEC Widgets, and contribute to the project.
4
+
5
+ ```{toctree}
6
+ ---
7
+ maxdepth: 2
8
+ hidden: false
9
+ ---
10
+
11
+ development/
12
+ ```
@@ -0,0 +1,12 @@
1
+ (developer.widgets)=
2
+ # Widgets
3
+ This section provides an introduction to the building blocks of BEC Widgets: widgets. Widgets are the basic components of the graphical user interface (GUI) and are used to create larger applications. We will cover key topics such as how to develop new widgets or how to customise existing widgets. For details on the already available widgets and their usage, please refer to user section about [widgets](#user.widgets)
4
+
5
+ ```{toctree}
6
+ ---
7
+ maxdepth: 2
8
+ hidden: false
9
+ ---
10
+
11
+ how_to_develop_a_widget/
12
+ ```
@@ -9,7 +9,7 @@ Before installing BEC Widgets, please ensure the following requirements are met:
9
9
 
10
10
  **Standard Installation**
11
11
 
12
- To install BEC Widgets using the pip package manager, execute the following command in your terminal for getting the default PyQT6 version in your python environment:
12
+ To install BEC Widgets using the pip package manager, execute the following command in your terminal for getting the default PyQT6 version into your python environment for BEC:
13
13
 
14
14
 
15
15
  ```bash
@@ -1,5 +1,5 @@
1
1
  (user.widgets.text_box)=
2
- # [Text Box Widget](/api_reference/_autosummary/bec_widgets.cli.client.TextBoxWidget)
2
+ # [Text Box Widget](/api_reference/_autosummary/bec_widgets.cli.client.TextBox)
3
3
  **Purpose:**
4
4
 
5
5
  The Text Box Widget is a widget that allows you to display text within the BEC GUI. The widget can be used to display plain text or HTML text.
pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bec_widgets"
7
- version = "0.63.1"
7
+ version = "0.64.0"
8
8
  description = "BEC Widgets"
9
9
  requires-python = ">=3.10"
10
10
  classifiers = [
@@ -48,6 +48,7 @@ Homepage = "https://gitlab.psi.ch/bec/bec_widgets"
48
48
 
49
49
  [project.scripts]
50
50
  bw-generate-cli = "bec_widgets.cli.generate_cli:main"
51
+ bec-gui-server = "bec_widgets.cli.server:main"
51
52
 
52
53
  [tool.hatch.build.targets.wheel]
53
54
  include = ["*"]
@@ -1,5 +1,8 @@
1
1
  # pylint: disable=missing-function-docstring, missing-module-docstring, unused-import
2
+ from unittest import mock
3
+
2
4
  import pytest
5
+ from qtpy.QtGui import QFontInfo
3
6
 
4
7
  from .client_mocks import mocked_client
5
8
  from .test_bec_figure import bec_figure
@@ -37,6 +40,30 @@ def test_plot_base_axes_by_separate_methods(bec_figure):
37
40
  assert plot_base.plot_item.ctrl.logXCheck.isChecked() == True
38
41
  assert plot_base.plot_item.ctrl.logYCheck.isChecked() == True
39
42
 
43
+ # Check the font size by mocking the set functions
44
+ # I struggled retrieving it from the QFont object directly
45
+ # thus I mocked the set functions to check internally the functionality
46
+ with (
47
+ mock.patch.object(plot_base.plot_item, "setLabel") as mock_set_label,
48
+ mock.patch.object(plot_base.plot_item, "setTitle") as mock_set_title,
49
+ ):
50
+ plot_base.set_x_label("Test x Label", 20)
51
+ plot_base.set_y_label("Test y Label", 16)
52
+ assert mock_set_label.call_count == 2
53
+ assert plot_base.config.axis.x_label_size == 20
54
+ assert plot_base.config.axis.y_label_size == 16
55
+ col = plot_base.get_text_color()
56
+ calls = []
57
+ style = {"color": col, "font-size": "20pt"}
58
+ calls.append(mock.call("bottom", "Test x Label", **style))
59
+ style = {"color": col, "font-size": "16pt"}
60
+ calls.append(mock.call("left", "Test y Label", **style))
61
+ assert mock_set_label.call_args_list == calls
62
+ plot_base.set_title("Test Title", 16)
63
+ style = {"color": col, "size": "16pt"}
64
+ call = mock.call("Test Title", **style)
65
+ assert mock_set_title.call_args == call
66
+
40
67
 
41
68
  def test_plot_base_axes_added_by_kwargs(bec_figure):
42
69
  plot_base = bec_figure.add_widget(widget_type="PlotBase", widget_id="test_plot")
@@ -1,5 +1,5 @@
1
1
  # pylint: disable=missing-function-docstring, missing-module-docstring, unused-import
2
- from unittest.mock import MagicMock
2
+ from unittest import mock
3
3
 
4
4
  import numpy as np
5
5
  import pytest
@@ -56,8 +56,12 @@ def test_create_waveform1D_by_config(bec_figure):
56
56
  "col": 0,
57
57
  "axis": {
58
58
  "title": "Widget 1",
59
+ "title_size": None,
59
60
  "x_label": None,
61
+ "x_label_size": None,
60
62
  "y_label": None,
63
+ "y_label_size": None,
64
+ "legend_label_size": None,
61
65
  "x_scale": "linear",
62
66
  "y_scale": "linear",
63
67
  "x_lim": (1, 10),
@@ -193,6 +197,18 @@ def test_add_curve(bec_figure):
193
197
  assert c1.config.source == "scan_segment"
194
198
 
195
199
 
200
+ def test_change_legend_font_size(bec_figure):
201
+ plot = bec_figure.add_plot()
202
+
203
+ w1 = plot.add_curve_scan(x_name="samx", y_name="bpm4i")
204
+ my_func = plot.plot_item.legend
205
+ with mock.patch.object(my_func, "setScale") as mock_set_scale:
206
+ plot.set_legend_label_size(18)
207
+ assert plot.config.axis.legend_label_size == 18
208
+ assert mock_set_scale.call_count == 1
209
+ assert mock_set_scale.call_args == mock.call(2)
210
+
211
+
196
212
  def test_remove_curve(bec_figure):
197
213
  w1 = bec_figure.add_plot()
198
214
 
@@ -406,10 +422,10 @@ def test_scan_update(bec_figure, qtbot):
406
422
  "scan_id": 1,
407
423
  }
408
424
  # Mock scan_storage.find_scan_by_ID
409
- mock_scan_data_waveform = MagicMock()
425
+ mock_scan_data_waveform = mock.MagicMock()
410
426
  mock_scan_data_waveform.data = {
411
427
  device_name: {
412
- entry: MagicMock(val=[msg_waveform["data"][device_name][entry]["value"]])
428
+ entry: mock.MagicMock(val=[msg_waveform["data"][device_name][entry]["value"]])
413
429
  for entry in msg_waveform["data"][device_name]
414
430
  }
415
431
  for device_name in msg_waveform["data"]
@@ -430,12 +446,12 @@ def test_scan_history_with_val_access(bec_figure, qtbot):
430
446
  c1 = w1.add_curve_scan(x_name="samx", y_name="bpm4i")
431
447
 
432
448
  mock_scan_data = {
433
- "samx": {"samx": MagicMock(val=np.array([1, 2, 3]))}, # Use MagicMock for .val
434
- "bpm4i": {"bpm4i": MagicMock(val=np.array([4, 5, 6]))}, # Use MagicMock for .val
449
+ "samx": {"samx": mock.MagicMock(val=np.array([1, 2, 3]))}, # Use mock.MagicMock for .val
450
+ "bpm4i": {"bpm4i": mock.MagicMock(val=np.array([4, 5, 6]))}, # Use mock.MagicMock for .val
435
451
  }
436
452
 
437
- mock_scan_storage = MagicMock()
438
- mock_scan_storage.find_scan_by_ID.return_value = MagicMock(data=mock_scan_data)
453
+ mock_scan_storage = mock.MagicMock()
454
+ mock_scan_storage.find_scan_by_ID.return_value = mock.MagicMock(data=mock_scan_data)
439
455
  w1.queue.scan_storage = mock_scan_storage
440
456
 
441
457
  fake_scan_id = "fake_scan_id"
@@ -464,10 +480,10 @@ def test_scatter_2d_update(bec_figure, qtbot):
464
480
  }
465
481
  msg_metadata = {"scan_name": "line_scan"}
466
482
 
467
- mock_scan_data = MagicMock()
483
+ mock_scan_data = mock.MagicMock()
468
484
  mock_scan_data.data = {
469
485
  device_name: {
470
- entry: MagicMock(val=msg["data"][device_name][entry]["value"])
486
+ entry: mock.MagicMock(val=msg["data"][device_name][entry]["value"])
471
487
  for entry in msg["data"][device_name]
472
488
  }
473
489
  for device_name in msg["data"]