pyobs-gui 2.0.0.dev12__tar.gz → 2.0.0.dev14__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 (141) hide show
  1. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/PKG-INFO +2 -2
  2. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/datadisplaywidget.py +3 -3
  3. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/spectrographwidget.ui +22 -0
  4. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/spectrographwidget_ui.py +22 -2
  5. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/spectrographwidget.py +18 -1
  6. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/weatherwidget.py +4 -4
  7. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyproject.toml +2 -2
  8. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/tests/test_camerawidget.py +1 -1
  9. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/uv.lock +905 -24
  10. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/.claude/skills/verify/SKILL.md +0 -0
  11. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/.github/dependabot.yml +0 -0
  12. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/.github/workflows/pypi.yml +0 -0
  13. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/.github/workflows/pyrefly.yml +0 -0
  14. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/.github/workflows/ruff.yml +0 -0
  15. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/.gitignore +0 -0
  16. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/.pre-commit-config.yaml +0 -0
  17. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/.readthedocs.yml +0 -0
  18. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/CHANGELOG.rst +0 -0
  19. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/LICENSE +0 -0
  20. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/README.md +0 -0
  21. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/bin/mypyuic5 +0 -0
  22. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/docs/Makefile +0 -0
  23. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/docs/make.bat +0 -0
  24. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/docs/requirements.txt +0 -0
  25. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/docs/source/_static/pyobs.gif +0 -0
  26. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/docs/source/conf.py +0 -0
  27. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/docs/source/index.rst +0 -0
  28. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/mypy.ini +0 -0
  29. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/__init__.py +0 -0
  30. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/__main__.py +0 -0
  31. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/_nuitka_astropy_patch.py +0 -0
  32. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/accounts.py +0 -0
  33. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/acquisitionwidget.py +0 -0
  34. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/autofocuswidget.py +0 -0
  35. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/autoguidingwidget.py +0 -0
  36. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/base.py +0 -0
  37. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/camerawidget.py +0 -0
  38. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/commandinputwidget.py +0 -0
  39. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/compassmovewidget.py +0 -0
  40. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/coolingwidget.py +0 -0
  41. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/eventswidget.py +0 -0
  42. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/filterwidget.py +0 -0
  43. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/fitsheaderswidget.py +0 -0
  44. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/focuswidget.py +0 -0
  45. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/gui.py +0 -0
  46. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/login.py +0 -0
  47. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/loginwindow.py +0 -0
  48. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/logmodel.py +0 -0
  49. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/mainwindow.py +0 -0
  50. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/modewidget.py +0 -0
  51. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/modifiedmixin.py +0 -0
  52. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/modulegui.py +0 -0
  53. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/__init__.py +0 -0
  54. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/acquisitionwidget.ui +0 -0
  55. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/acquisitionwidget_ui.py +0 -0
  56. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/autofocuswidget.ui +0 -0
  57. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/autofocuswidget_ui.py +0 -0
  58. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/autoguidingwidget.ui +0 -0
  59. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/autoguidingwidget_ui.py +0 -0
  60. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/camerawidget.ui +0 -0
  61. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/camerawidget_ui.py +0 -0
  62. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/compassmoveplugin.py +0 -0
  63. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/compassmovewidget.py +0 -0
  64. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/compassmovewidget.ui +0 -0
  65. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/compassmovewidget_ui.py +0 -0
  66. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/compile.sh +0 -0
  67. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/coolingwidget.ui +0 -0
  68. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/coolingwidget_ui.py +0 -0
  69. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/datadisplayplugin.py +0 -0
  70. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/datadisplaywidget.ui +0 -0
  71. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/datadisplaywidget_ui.py +0 -0
  72. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/designer.sh +0 -0
  73. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/eventswidget.ui +0 -0
  74. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/eventswidget_ui.py +0 -0
  75. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/filterwidget.ui +0 -0
  76. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/filterwidget_ui.py +0 -0
  77. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/fitsheaderswidget.ui +0 -0
  78. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/fitsheaderswidget_ui.py +0 -0
  79. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/focuswidget.ui +0 -0
  80. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/focuswidget_ui.py +0 -0
  81. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/mainwindow.ui +0 -0
  82. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/mainwindow_ui.py +0 -0
  83. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/modewidget.ui +0 -0
  84. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/modewidget_ui.py +0 -0
  85. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/arrow-alt-circle-down-solid.svg +0 -0
  86. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/arrow-alt-circle-left-solid.svg +0 -0
  87. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/arrow-alt-circle-right-solid.svg +0 -0
  88. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/arrow-alt-circle-up-solid.svg +0 -0
  89. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/arrow-up-right-from-square-solid.svg +0 -0
  90. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/arrows-to-eye-solid.svg +0 -0
  91. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/chart-line-solid.svg +0 -0
  92. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/circle-question-solid.svg +0 -0
  93. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/cloud-sun-solid.svg +0 -0
  94. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/edit-solid.svg +0 -0
  95. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/search-solid.svg +0 -0
  96. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources/undo-solid.svg +0 -0
  97. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources.qrc +0 -0
  98. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/resources_rc.py +0 -0
  99. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/roofwidget.ui +0 -0
  100. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/roofwidget_ui.py +0 -0
  101. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/shellwidget.ui +0 -0
  102. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/shellwidget_ui.py +0 -0
  103. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/telescopewidget.ui +0 -0
  104. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/telescopewidget_ui.py +0 -0
  105. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/temperaturesplotwidget.ui +0 -0
  106. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/temperaturesplotwidget_ui.py +0 -0
  107. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/temperatureswidget.ui +0 -0
  108. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/temperatureswidget_ui.py +0 -0
  109. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/videowidget.ui +0 -0
  110. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/videowidget_ui.py +0 -0
  111. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/weatherwidget.ui +0 -0
  112. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/qt/weatherwidget_ui.py +0 -0
  113. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/roofwidget.py +0 -0
  114. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/shellwidget.py +0 -0
  115. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/statuswidget.py +0 -0
  116. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/telescopewidget.py +0 -0
  117. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/temperaturesplotwidget.py +0 -0
  118. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/temperatureswidget.py +0 -0
  119. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/utils.py +0 -0
  120. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/videowidget.py +0 -0
  121. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pyobs_gui/watchedlabel.py +0 -0
  122. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/pysidedeploy.spec +0 -0
  123. /pyobs_gui-2.0.0.dev12/specs/README.md → /pyobs_gui-2.0.0.dev14/specs/index.md +0 -0
  124. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/spike_standalone/main.py +0 -0
  125. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/spike_standalone/pysidedeploy.spec +0 -0
  126. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/acquisition.yaml +0 -0
  127. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/autofocus.yaml +0 -0
  128. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/camera.yaml +0 -0
  129. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/full.yaml +0 -0
  130. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/guiding.yaml +0 -0
  131. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/mode.yaml +0 -0
  132. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/roof.yaml +0 -0
  133. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/spectrograph.yaml +0 -0
  134. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/telescope.yaml +0 -0
  135. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/telescope_acl.yaml +0 -0
  136. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/telescope_acl_denied.yaml +0 -0
  137. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/test/video.yaml +0 -0
  138. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/tests/__init__.py +0 -0
  139. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/tests/conftest.py +0 -0
  140. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/tests/test_accounts.py +0 -0
  141. {pyobs_gui-2.0.0.dev12 → pyobs_gui-2.0.0.dev14}/tests/test_loginwindow.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyobs-gui
3
- Version: 2.0.0.dev12
3
+ Version: 2.0.0.dev14
4
4
  Summary: A remote GUI for pyobs
5
5
  Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>
6
6
  License-Expression: MIT
7
7
  License-File: LICENSE
8
- Requires-Python: <3.14,>=3.11
8
+ Requires-Python: >=3.11
9
9
  Requires-Dist: astroplan>=0.10.1
10
10
  Requires-Dist: astropy<8,>=7.0.1
11
11
  Requires-Dist: colour<0.2,>=0.1.5
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import logging
4
4
  import os
5
- from typing import Any, cast, TYPE_CHECKING
5
+ from typing import Any, TYPE_CHECKING
6
6
  import numpy as np
7
7
  from PySide6 import QtWidgets, QtCore # type: ignore
8
8
  from matplotlib import pyplot as plt
@@ -93,9 +93,9 @@ class DataDisplayWidget(BaseWidget, Ui_DataDisplayWidget):
93
93
  # if we're not broadcasting the filename, we need to signal it manually
94
94
  if not broadcast:
95
95
  if await self.comm.has_proxy(module, ISpectrograph):
96
- await self._on_new_data(NewSpectrumEvent(filename), cast("Proxy", cast("object", module)).name)
96
+ await self._on_new_data(NewSpectrumEvent(filename), module)
97
97
  else:
98
- await self._on_new_data(NewImageEvent(filename, None), cast("Proxy", cast("object", module)).name)
98
+ await self._on_new_data(NewImageEvent(filename, None), module)
99
99
 
100
100
  # signal GUI update
101
101
  self.signal_update_gui.emit()
@@ -66,6 +66,27 @@
66
66
  </property>
67
67
  </widget>
68
68
  </item>
69
+ <item>
70
+ <layout class="QHBoxLayout" name="horizontalLayoutCount">
71
+ <item>
72
+ <widget class="QLabel" name="labelCount">
73
+ <property name="text">
74
+ <string>Count:</string>
75
+ </property>
76
+ </widget>
77
+ </item>
78
+ <item>
79
+ <widget class="QSpinBox" name="spinCount">
80
+ <property name="minimum">
81
+ <number>1</number>
82
+ </property>
83
+ <property name="maximum">
84
+ <number>9999</number>
85
+ </property>
86
+ </widget>
87
+ </item>
88
+ </layout>
89
+ </item>
69
90
  <item>
70
91
  <widget class="QPushButton" name="butExpose">
71
92
  <property name="palette">
@@ -1035,6 +1056,7 @@
1035
1056
  <tabstops>
1036
1057
  <tabstop>scrollArea</tabstop>
1037
1058
  <tabstop>checkBroadcast</tabstop>
1059
+ <tabstop>spinCount</tabstop>
1038
1060
  <tabstop>butExpose</tabstop>
1039
1061
  <tabstop>butAbort</tabstop>
1040
1062
  </tabstops>
@@ -17,7 +17,8 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
17
17
  QPalette, QPixmap, QRadialGradient, QTransform)
18
18
  from PySide6.QtWidgets import (QApplication, QCheckBox, QGroupBox, QHBoxLayout,
19
19
  QLabel, QProgressBar, QPushButton, QScrollArea,
20
- QSizePolicy, QSpacerItem, QVBoxLayout, QWidget)
20
+ QSizePolicy, QSpacerItem, QSpinBox, QVBoxLayout,
21
+ QWidget)
21
22
 
22
23
  from ..datadisplaywidget import DataDisplayWidget
23
24
  from . import resources_rc
@@ -60,6 +61,23 @@ class Ui_SpectrographWidget(object):
60
61
 
61
62
  self.verticalLayout_3.addWidget(self.checkBroadcast)
62
63
 
64
+ self.horizontalLayoutCount = QHBoxLayout()
65
+ self.horizontalLayoutCount.setObjectName(u"horizontalLayoutCount")
66
+ self.labelCount = QLabel(self.groupExposure)
67
+ self.labelCount.setObjectName(u"labelCount")
68
+
69
+ self.horizontalLayoutCount.addWidget(self.labelCount)
70
+
71
+ self.spinCount = QSpinBox(self.groupExposure)
72
+ self.spinCount.setObjectName(u"spinCount")
73
+ self.spinCount.setMinimum(1)
74
+ self.spinCount.setMaximum(9999)
75
+
76
+ self.horizontalLayoutCount.addWidget(self.spinCount)
77
+
78
+
79
+ self.verticalLayout_3.addLayout(self.horizontalLayoutCount)
80
+
63
81
  self.butExpose = QPushButton(self.groupExposure)
64
82
  self.butExpose.setObjectName(u"butExpose")
65
83
  palette = QPalette()
@@ -265,7 +283,8 @@ class Ui_SpectrographWidget(object):
265
283
 
266
284
  self.horizontalLayout_2.setStretch(1, 1)
267
285
  QWidget.setTabOrder(self.scrollArea, self.checkBroadcast)
268
- QWidget.setTabOrder(self.checkBroadcast, self.butExpose)
286
+ QWidget.setTabOrder(self.checkBroadcast, self.spinCount)
287
+ QWidget.setTabOrder(self.spinCount, self.butExpose)
269
288
  QWidget.setTabOrder(self.butExpose, self.butAbort)
270
289
 
271
290
  self.retranslateUi(SpectrographWidget)
@@ -277,6 +296,7 @@ class Ui_SpectrographWidget(object):
277
296
  SpectrographWidget.setWindowTitle(QCoreApplication.translate("SpectrographWidget", u"Form", None))
278
297
  self.groupExposure.setTitle(QCoreApplication.translate("SpectrographWidget", u"Exposure", None))
279
298
  self.checkBroadcast.setText(QCoreApplication.translate("SpectrographWidget", u"Broadcast", None))
299
+ self.labelCount.setText(QCoreApplication.translate("SpectrographWidget", u"Count:", None))
280
300
  self.butExpose.setText(QCoreApplication.translate("SpectrographWidget", u"Expose", None))
281
301
  self.butAbort.setText(QCoreApplication.translate("SpectrographWidget", u"Abort", None))
282
302
  self.labelStatus.setText(QCoreApplication.translate("SpectrographWidget", u"IDLE", None))
@@ -29,6 +29,7 @@ class SpectrographWidget(BaseWidget, Ui_SpectrographWidget):
29
29
 
30
30
  # cached state
31
31
  self.exposure_status = ExposureStatus.IDLE
32
+ self.exposures_left = 0
32
33
 
33
34
  # before first update, disable myself
34
35
  self.setEnabled(False)
@@ -61,11 +62,20 @@ class SpectrographWidget(BaseWidget, Ui_SpectrographWidget):
61
62
  @qasync.asyncSlot() # type: ignore
62
63
  async def grab_spectrum(self) -> None:
63
64
  broadcast = self.checkBroadcast.isChecked()
64
- await self.datadisplay.grab_data(broadcast)
65
+
66
+ # take the requested number of spectra; an exception (e.g. from a failed exposure,
67
+ # or abort() zeroing exposures_left mid-loop) stops the sequence
68
+ self.exposures_left = self.spinCount.value()
65
69
  self.signal_update_gui.emit()
70
+ while self.exposures_left > 0:
71
+ await self.datadisplay.grab_data(broadcast)
72
+ self.exposures_left -= 1
73
+ self.signal_update_gui.emit()
66
74
 
67
75
  @qasync.asyncSlot() # type: ignore
68
76
  async def abort(self) -> None:
77
+ # stop the sequence after the current spectrum finishes aborting
78
+ self.exposures_left = 0
69
79
  async with self.comm.proxy(self.module, IAbortable) as proxy:
70
80
  await proxy.abort()
71
81
 
@@ -75,6 +85,13 @@ class SpectrographWidget(BaseWidget, Ui_SpectrographWidget):
75
85
  self.butExpose.setEnabled(self.exposure_status == ExposureStatus.IDLE)
76
86
  self.butAbort.setEnabled(self.exposure_status != ExposureStatus.IDLE)
77
87
 
88
+ self.butAbort.setText("Abort sequence" if self.exposures_left > 1 else "Abort")
89
+
90
+ if self.exposures_left > 0:
91
+ self.labelExposuresLeft.setText(f"{self.exposures_left} spectrum/spectra left")
92
+ else:
93
+ self.labelExposuresLeft.setText("")
94
+
78
95
  msg = ""
79
96
  if self.exposure_status == ExposureStatus.IDLE:
80
97
  self.progressExposure.setValue(0)
@@ -1,6 +1,6 @@
1
1
  import os
2
2
  from collections import deque
3
- from typing import Any, Deque, Dict, Tuple, TYPE_CHECKING
3
+ from typing import Any, cast, Deque, Dict, Tuple, TYPE_CHECKING
4
4
  from PySide6 import QtWidgets, QtGui, QtCore # type: ignore
5
5
  import logging
6
6
 
@@ -16,6 +16,7 @@ from .base import BaseWidget
16
16
 
17
17
  if TYPE_CHECKING:
18
18
  from pyobs.utils.time import Time
19
+ from matplotlib.axes import Axes
19
20
 
20
21
 
21
22
  log = logging.getLogger(__name__)
@@ -186,9 +187,8 @@ class WeatherWidget(BaseWidget, Ui_WeatherWidget):
186
187
  self.canvas.draw()
187
188
  return
188
189
 
189
- axes = self.figure.subplots(len(sensors), 1, sharex=True)
190
- if len(sensors) == 1:
191
- axes = [axes]
190
+ subplots = self.figure.subplots(len(sensors), 1, sharex=True)
191
+ axes = cast("list[Axes]", [subplots] if len(sensors) == 1 else list(subplots))
192
192
  for ax, sensor in zip(axes, sensors, strict=True):
193
193
  times, values = zip(*self._history[sensor], strict=True)
194
194
  ax.plot([t.to_datetime() for t in times], values, color="tab:blue")
@@ -1,9 +1,9 @@
1
1
  [project]
2
2
  name = "pyobs-gui"
3
- version = "2.0.0.dev12"
3
+ version = "2.0.0.dev14"
4
4
  description = "A remote GUI for pyobs"
5
5
  authors = [{ name = "Tim-Oliver Husser", email = "thusser@uni-goettingen.de" }]
6
- requires-python = ">=3.11,<3.14"
6
+ requires-python = ">=3.11"
7
7
  license = "MIT"
8
8
  dependencies = [
9
9
  "colour>=0.1.5,<0.2",
@@ -35,7 +35,7 @@ class FakeComm:
35
35
  def make_widget(data_sequence_proxy) -> CameraWidget:
36
36
  widget = CameraWidget()
37
37
  widget.modules = ["camera"]
38
- widget._comm = FakeComm(data_sequence_proxy=data_sequence_proxy)
38
+ widget._comm = FakeComm(data_sequence_proxy=data_sequence_proxy) # pyrefly: ignore [bad-assignment]
39
39
  widget.datadisplay.grab_data = AsyncMock()
40
40
  return widget
41
41