pyobs-gui 2.5.0__tar.gz → 2.5.2__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.
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/PKG-INFO +1 -1
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/base.py +10 -2
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/camerawidget.py +1 -1
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/spectrographwidget.py +1 -1
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/videograbwidget.py +1 -1
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyproject.toml +1 -1
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/specs/index.md +4 -0
- pyobs_gui-2.5.2/tests/test_basewidget_discard.py +44 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/uv.lock +28 -28
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/.claude/skills/verify/SKILL.md +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/.github/dependabot.yml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/.github/workflows/dependabot-automerge.yml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/.github/workflows/pypi.yml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/.github/workflows/pyrefly.yml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/.github/workflows/ruff.yml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/.gitignore +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/.pre-commit-config.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/.readthedocs.yml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/CHANGELOG.rst +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/CLAUDE.md +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/LICENSE +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/README.md +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/bin/mypyuic5 +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/docs/Makefile +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/docs/make.bat +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/docs/requirements.txt +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/docs/source/_static/pyobs.gif +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/docs/source/conf.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/docs/source/index.rst +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/mypy.ini +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/__init__.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/__main__.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/_nuitka_astropy_patch.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/accounts.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/acquisitionwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/autofocuswidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/autoguidingwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/commandinputwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/compassmovewidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/coolingwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/datadisplaywidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/eventswidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/filterwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/fitsheaderswidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/focuswidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/gui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/login.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/loginwindow.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/logmodel.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/mainwindow.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/modewidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/modifiedmixin.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/modulegui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/movestack.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/nowheelfilter.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/__init__.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/acquisitionwidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/acquisitionwidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/autofocuswidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/autofocuswidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/autoguidingwidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/autoguidingwidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/camerawidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/camerawidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/compassmoveplugin.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/compassmovewidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/compassmovewidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/compassmovewidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/compile.sh +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/coolingwidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/coolingwidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/datadisplayplugin.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/datadisplaywidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/datadisplaywidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/designer.sh +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/eventswidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/eventswidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/filterwidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/filterwidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/fitsheaderswidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/fitsheaderswidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/focuswidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/focuswidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/mainwindow.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/mainwindow_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/modewidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/modewidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/arrow-alt-circle-down-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/arrow-alt-circle-left-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/arrow-alt-circle-right-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/arrow-alt-circle-up-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/arrow-up-right-from-square-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/arrows-to-eye-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/chart-line-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/circle-question-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/cloud-sun-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/edit-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/search-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/undo-solid.svg +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources.qrc +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources_rc.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/roboticwidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/roboticwidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/roofwidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/roofwidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/schedulewidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/schedulewidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/shellwidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/shellwidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/spectrographwidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/spectrographwidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/telescopewidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/telescopewidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/temperaturesplotwidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/temperaturesplotwidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/temperatureswidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/temperatureswidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/videograbwidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/videograbwidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/videowidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/videowidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/weatherwidget.ui +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/weatherwidget_ui.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/roboticwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/roofwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/schedulewidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/shellwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/statuswidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/structuredconfigwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/telescopewidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/temperaturesplotwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/temperatureswidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/utils.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/videowidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/watchedlabel.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/weatherwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pysidedeploy.spec +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/specs/2026-08-20-gui-remote-call-error-handling.md +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/specs/2026-08-21-gui-widget-startup-responsiveness.md +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/specs/2026-08-28-gui-main-vs-sidebar-widgets.md +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/specs/2026-08-28-structuredconfig-widget.md +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/specs/2026-08-31-irobotic-widgets.md +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/specs/2026-09-01-gui-video-widget-split.md +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/specs/2026-09-14-fitswidget-toolbar-overflow.md +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/specs/2026-09-14-stacked-widget-scroll-fallback.md +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/spike_standalone/main.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/spike_standalone/pysidedeploy.spec +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/acquisition.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/autofocus.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/camera.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/full.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/guiding.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/mode.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/robotic.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/roof.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/spectrograph.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/structuredconfig.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/telescope.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/telescope_acl.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/telescope_acl_denied.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/test/video.yaml +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/__init__.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/conftest.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_accounts.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_camerawidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_loginwindow.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_mainwindow_startup.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_modewidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_multiwidget_pages.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_roboticwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_schedulewidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_spectrographwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_structuredconfigwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_videograbwidget.py +0 -0
- {pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/tests/test_videowidget.py +0 -0
|
@@ -61,6 +61,9 @@ class BaseWindow:
|
|
|
61
61
|
self.vfs: VirtualFileSystem | dict[str, Any] | None = None
|
|
62
62
|
self._base_widgets: list[BaseWidget] = []
|
|
63
63
|
|
|
64
|
+
# every child widget opened via _open_child(), so BaseWidget.discard() can discard them too
|
|
65
|
+
self._opened_children: list[BaseWidget] = []
|
|
66
|
+
|
|
64
67
|
@property
|
|
65
68
|
def comm(self) -> Comm:
|
|
66
69
|
if self._comm is None:
|
|
@@ -142,6 +145,8 @@ class BaseWindow:
|
|
|
142
145
|
await self._open_child(widget)
|
|
143
146
|
|
|
144
147
|
async def _open_child(self, widget: BaseWidget) -> None:
|
|
148
|
+
# track before opening, so a child failing halfway through open() still gets discarded
|
|
149
|
+
self._opened_children.append(widget)
|
|
145
150
|
await widget.open(modules=self.modules, vfs=self.vfs, comm=self.comm, observer=self.observer)
|
|
146
151
|
|
|
147
152
|
|
|
@@ -269,7 +274,8 @@ class BaseWidget(BaseWindow, QtWidgets.QWidget): # type: ignore
|
|
|
269
274
|
|
|
270
275
|
async def discard(self) -> None:
|
|
271
276
|
"""Tear down everything this widget registered with comm, and recursively discard
|
|
272
|
-
its sidebar widgets.
|
|
277
|
+
its child widgets: sidebar widgets and everything opened via _open_child(), e.g. an
|
|
278
|
+
embedded DataDisplayWidget. Safe to call more than once.
|
|
273
279
|
|
|
274
280
|
Must be called (e.g. from mainwindow._client_disconnected) whenever a widget is
|
|
275
281
|
removed from the UI -- otherwise a handler registered via register_event() lingers
|
|
@@ -289,7 +295,9 @@ class BaseWidget(BaseWindow, QtWidgets.QWidget): # type: ignore
|
|
|
289
295
|
await self.comm.unregister_event(event_class, handler)
|
|
290
296
|
self._registered_event_handlers.clear()
|
|
291
297
|
|
|
292
|
-
|
|
298
|
+
# sidebar widgets are opened via _open_child() as well, so skip duplicates
|
|
299
|
+
children = list(dict.fromkeys([*self._opened_children, *self.sidebar_widgets]))
|
|
300
|
+
for widget in children:
|
|
293
301
|
await widget.discard()
|
|
294
302
|
|
|
295
303
|
def showEvent(self, event: QtGui.QShowEvent) -> None:
|
|
@@ -85,7 +85,7 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
|
|
|
85
85
|
) -> None:
|
|
86
86
|
"""Open module."""
|
|
87
87
|
await BaseWidget.open(self, modules=modules, comm=comm, observer=observer, vfs=vfs)
|
|
88
|
-
await self.datadisplay
|
|
88
|
+
await self._open_child(self.datadisplay)
|
|
89
89
|
|
|
90
90
|
# set exposure types
|
|
91
91
|
image_types = sorted([it.name for it in ImageType])
|
|
@@ -47,7 +47,7 @@ class SpectrographWidget(BaseWidget, Ui_SpectrographWidget):
|
|
|
47
47
|
) -> None:
|
|
48
48
|
"""Open module."""
|
|
49
49
|
await BaseWidget.open(self, modules=modules, comm=comm, observer=observer, vfs=vfs)
|
|
50
|
-
await self.datadisplay
|
|
50
|
+
await self._open_child(self.datadisplay)
|
|
51
51
|
|
|
52
52
|
self.butAbort.setVisible(await self.comm.has_proxy(self.module, IAbortable))
|
|
53
53
|
|
|
@@ -59,7 +59,7 @@ class VideoGrabWidget(BaseWidget, Ui_VideoGrabWidget):
|
|
|
59
59
|
) -> None:
|
|
60
60
|
"""Open module."""
|
|
61
61
|
await BaseWidget.open(self, modules=modules, comm=comm, observer=observer, vfs=vfs)
|
|
62
|
-
await self.datadisplay
|
|
62
|
+
await self._open_child(self.datadisplay)
|
|
63
63
|
|
|
64
64
|
async def _init(self) -> None:
|
|
65
65
|
# get interfaces for visibility checks
|
|
@@ -92,3 +92,7 @@ ADRs that concern `pyobs-gui` live in `pyobs-core`'s `specs/` tree instead (`spe
|
|
|
92
92
|
- `pyobs-core/specs/plans/2026-08-21-basevideo-http-token-auth.md` — **proposed**. Shared-token
|
|
93
93
|
auth + browser login for `BaseVideo` (pyobs-core side); pyobs-gui side is a one-header change
|
|
94
94
|
in `VideoWidget`'s raw-socket GET (design: `pyobs-core/specs/design/basevideo-http-auth.md`).
|
|
95
|
+
- `pyobs-core/specs/design/basevideo-live-view.md`: **proposed** (2026-09-29). User-selectable
|
|
96
|
+
live view in `VideoWidget`: MJPEG with server-side stretch for slow links, or `/video.raw` with
|
|
97
|
+
client-side stretch/cuts and crop on zoom. Plan: `pyobs-core/specs/plans/2026-09-29-basevideo-frame-buffer-redesign.md`
|
|
98
|
+
(phase 6).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from unittest.mock import AsyncMock, MagicMock
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
from pyobs.events import NewImageEvent
|
|
6
|
+
|
|
7
|
+
from pyobs_gui.base import BaseWidget
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ChildWidget(BaseWidget):
|
|
11
|
+
async def open(self, **kwargs: Any) -> None:
|
|
12
|
+
await BaseWidget.open(self, **kwargs)
|
|
13
|
+
await self.register_event(NewImageEvent, self._on_new_image)
|
|
14
|
+
|
|
15
|
+
async def _on_new_image(self, event: Any, sender: str) -> bool:
|
|
16
|
+
return True
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ParentWidget(BaseWidget):
|
|
20
|
+
def __init__(self, **kwargs: Any):
|
|
21
|
+
BaseWidget.__init__(self, **kwargs)
|
|
22
|
+
# like CameraWidget.datadisplay: an embedded child, not a sidebar widget
|
|
23
|
+
self.child = ChildWidget()
|
|
24
|
+
|
|
25
|
+
async def open(self, **kwargs: Any) -> None:
|
|
26
|
+
await BaseWidget.open(self, **kwargs)
|
|
27
|
+
await self._open_child(self.child)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.mark.asyncio
|
|
31
|
+
async def test_discard_unregisters_handlers_of_embedded_children() -> None:
|
|
32
|
+
comm = MagicMock()
|
|
33
|
+
comm.register_event = AsyncMock()
|
|
34
|
+
comm.unregister_event = AsyncMock()
|
|
35
|
+
widget = ParentWidget()
|
|
36
|
+
await widget.open(modules=["camera"], comm=comm)
|
|
37
|
+
|
|
38
|
+
await widget.discard()
|
|
39
|
+
|
|
40
|
+
comm.unregister_event.assert_awaited_once_with(NewImageEvent, widget.child._on_new_image)
|
|
41
|
+
|
|
42
|
+
# discarding again doesn't unregister twice
|
|
43
|
+
await widget.discard()
|
|
44
|
+
assert comm.unregister_event.await_count == 1
|
|
@@ -2623,15 +2623,15 @@ wheels = [
|
|
|
2623
2623
|
|
|
2624
2624
|
[[package]]
|
|
2625
2625
|
name = "pandas-stubs"
|
|
2626
|
-
version = "3.0.5.
|
|
2626
|
+
version = "3.0.5.260914"
|
|
2627
2627
|
source = { registry = "https://pypi.org/simple" }
|
|
2628
2628
|
dependencies = [
|
|
2629
2629
|
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
|
|
2630
2630
|
{ name = "numpy", version = "2.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
|
|
2631
2631
|
]
|
|
2632
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
2632
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c1/93/8948ae6c1e1e3d6833596fd266f7be2d27c1451b8be094975ad42c5e842e/pandas_stubs-3.0.5.260914.tar.gz", hash = "sha256:3f6fc1f147f68fd89c007105e7c94a948acb4ecd7eb20dc1c02e153c4ed5c250", size = 117622, upload-time = "2026-09-14T16:42:35.065Z" }
|
|
2633
2633
|
wheels = [
|
|
2634
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
2634
|
+
{ url = "https://files.pythonhosted.org/packages/9a/cb/5ad79e02a556cc23fed5816de0109fa8af660c66cfa5f4af74c3e8d4cd26/pandas_stubs-3.0.5.260914-py3-none-any.whl", hash = "sha256:39a1300c5c5c55fdf609e3476805decce5d5015539a4dcb683449f8feaeee2fb", size = 177344, upload-time = "2026-09-14T16:42:33.771Z" },
|
|
2635
2635
|
]
|
|
2636
2636
|
|
|
2637
2637
|
[[package]]
|
|
@@ -3263,7 +3263,7 @@ wheels = [
|
|
|
3263
3263
|
|
|
3264
3264
|
[[package]]
|
|
3265
3265
|
name = "pyobs-core"
|
|
3266
|
-
version = "2.
|
|
3266
|
+
version = "2.10.7"
|
|
3267
3267
|
source = { registry = "https://pypi.org/simple" }
|
|
3268
3268
|
dependencies = [
|
|
3269
3269
|
{ name = "aiohttp" },
|
|
@@ -3295,14 +3295,14 @@ dependencies = [
|
|
|
3295
3295
|
{ name = "tenacity" },
|
|
3296
3296
|
{ name = "typing-extensions" },
|
|
3297
3297
|
]
|
|
3298
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
3298
|
+
sdist = { url = "https://files.pythonhosted.org/packages/7e/db/b197375974c8436095fdfa53db228e1e8b323f12183433ee960c99e96cef/pyobs_core-2.10.7.tar.gz", hash = "sha256:2bd17b1ea609692c6f8925f2d80afc515ac2209b807205ffaa9129730321116e", size = 424175, upload-time = "2026-09-23T18:20:53.969Z" }
|
|
3299
3299
|
wheels = [
|
|
3300
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3300
|
+
{ url = "https://files.pythonhosted.org/packages/52/4e/ebdb9836eae127a70ab9fd618eb7782394158592cb35b5a97ff133cfa757/pyobs_core-2.10.7-py3-none-any.whl", hash = "sha256:14cfea0a0633ba31593323ff0bff919d9510b987369e0cc3f758a948f9dd396e", size = 656647, upload-time = "2026-09-23T18:20:52.624Z" },
|
|
3301
3301
|
]
|
|
3302
3302
|
|
|
3303
3303
|
[[package]]
|
|
3304
3304
|
name = "pyobs-gui"
|
|
3305
|
-
version = "2.5.
|
|
3305
|
+
version = "2.5.2"
|
|
3306
3306
|
source = { editable = "." }
|
|
3307
3307
|
dependencies = [
|
|
3308
3308
|
{ name = "astroplan" },
|
|
@@ -3788,27 +3788,27 @@ wheels = [
|
|
|
3788
3788
|
|
|
3789
3789
|
[[package]]
|
|
3790
3790
|
name = "ruff"
|
|
3791
|
-
version = "0.16.
|
|
3792
|
-
source = { registry = "https://pypi.org/simple" }
|
|
3793
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
3794
|
-
wheels = [
|
|
3795
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3796
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3797
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3798
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3799
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3800
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3801
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3802
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3803
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3804
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3805
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3806
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3807
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3808
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3809
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3810
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3811
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
3791
|
+
version = "0.16.9"
|
|
3792
|
+
source = { registry = "https://pypi.org/simple" }
|
|
3793
|
+
sdist = { url = "https://files.pythonhosted.org/packages/96/bf/c935ca98e73fe8ce65b87ef08a280c0c1e85295d569228c15e87d8fdfaf1/ruff-0.16.9.tar.gz", hash = "sha256:12b625c6cfba78d285d9f48eda5f053374f1e53cb10ef17342a383750db99161", size = 4948764, upload-time = "2026-09-24T20:37:49.416Z" }
|
|
3794
|
+
wheels = [
|
|
3795
|
+
{ url = "https://files.pythonhosted.org/packages/0d/26/df51322b52ee1ada7eff2d071ea09d11d5c2d1dcc9f02594f5785c4d1635/ruff-0.16.9-py3-none-linux_armv6l.whl", hash = "sha256:95e6f022090368ab3b824c36276839c53b2adf1a3f4c09fefc33dfc400f6da96", size = 10082922, upload-time = "2026-09-24T20:37:13.045Z" },
|
|
3796
|
+
{ url = "https://files.pythonhosted.org/packages/a5/27/7bf51f5a7aa375e9f339280a303aab44ca75dc1525f1cdc5991761685b0f/ruff-0.16.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a5f27be168556594a86d2f415db0cf43f5291917849318f873c7e2791f7a8c67", size = 10236360, upload-time = "2026-09-24T20:37:16.049Z" },
|
|
3797
|
+
{ url = "https://files.pythonhosted.org/packages/b6/63/09659283f92f02dff45809da194a70da2f688d87c55d8875c4fae3536072/ruff-0.16.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1632eb1d6197f33bd00b1acbc5b71009e89a8895c158e2d2b03a834fac964ab6", size = 9892940, upload-time = "2026-09-24T20:37:17.957Z" },
|
|
3798
|
+
{ url = "https://files.pythonhosted.org/packages/24/58/98de1b72ec172f5f8f1731236fe21585b3998bf7dfe9fcc44ae9ba626012/ruff-0.16.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3f951b14d865d5952c89d40a5ca07e87abe24fa5453299878411e127748fb1c", size = 10032114, upload-time = "2026-09-24T20:37:19.942Z" },
|
|
3799
|
+
{ url = "https://files.pythonhosted.org/packages/c8/7d/f1e17c54ab59d4bad1dce8ee3e22a7a1d0ef4745240decacdcf3832b5bb2/ruff-0.16.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:447fc07e1573afff7cb02803462b12b6c8ece7cf10e2cd78565fa6d7a1c0bf8d", size = 9910227, upload-time = "2026-09-24T20:37:21.872Z" },
|
|
3800
|
+
{ url = "https://files.pythonhosted.org/packages/34/19/436f647a65075bbd3bab2668b3bdaa5120559b294694018cdcefabbbf30b/ruff-0.16.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a3e039a6a40ed976c491722b60e0ae4a4aa1a86057f540ee7a37a5d19ae9120", size = 10547484, upload-time = "2026-09-24T20:37:24.229Z" },
|
|
3801
|
+
{ url = "https://files.pythonhosted.org/packages/03/59/38430a6bc2f6d8095447ac39625cf8b6e9344a47e6c26225c8ba1bff3ffb/ruff-0.16.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4684dded7db60aa57cb118fa158630f5feade4af5782903b6053484bdf9bd129", size = 11412367, upload-time = "2026-09-24T20:37:26.307Z" },
|
|
3802
|
+
{ url = "https://files.pythonhosted.org/packages/c8/bd/bbb6d7fc7f208c8b8c50dd5dc8206e4cfdb1e7a8fb852606a3adf370c880/ruff-0.16.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d29c934357e45642fda2f34c0b1f4025b4a6c01e15e4bf0016879d60078a142c", size = 10869787, upload-time = "2026-09-24T20:37:28.35Z" },
|
|
3803
|
+
{ url = "https://files.pythonhosted.org/packages/bc/b8/9c543074918061abbefc3bd139bee22de35abedb00dde0f2d27288838962/ruff-0.16.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a21713e629d3e5bdb2f5c2def1cc7f04f47fa8e1a7eb0571b4a28e1da64bc728", size = 10406494, upload-time = "2026-09-24T20:37:30.624Z" },
|
|
3804
|
+
{ url = "https://files.pythonhosted.org/packages/35/7a/5a8851bd146e7ccf8fd4b003f6c75c11f8fbdb0e60673b45097986b6bf41/ruff-0.16.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:7baa24ef5fc8e77aa93879e1d3f43754a01ae488e869f1ae30cf431afd4d2452", size = 10590083, upload-time = "2026-09-24T20:37:32.439Z" },
|
|
3805
|
+
{ url = "https://files.pythonhosted.org/packages/87/f0/4c3467188f23f806960b46fa76575a7cd0514c9ba90562650b71efc96980/ruff-0.16.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a41aac6230aadfaa133bdfa1614488531ffa3e0837567ae04c0da2058a9c0f9e", size = 10119151, upload-time = "2026-09-24T20:37:34.581Z" },
|
|
3806
|
+
{ url = "https://files.pythonhosted.org/packages/15/34/5a4def5adea572ce6aea0bb64f21f928ee317b80e0db747d7979b01d7261/ruff-0.16.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:c2529fb5896d49115b0e9aa8f887490b34bbe76baf879ec2264ac59406869ce7", size = 9911544, upload-time = "2026-09-24T20:37:36.796Z" },
|
|
3807
|
+
{ url = "https://files.pythonhosted.org/packages/62/5d/d15ebea7499eef9373318c0ee6ca127832927c6529731f6d48e18dce7ca9/ruff-0.16.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:41e3870277694177429b56406d65dfbdb2c2802c52b715edaf6a0b829c69d4ee", size = 10269884, upload-time = "2026-09-24T20:37:38.857Z" },
|
|
3808
|
+
{ url = "https://files.pythonhosted.org/packages/d1/56/c5d3cd119ded7a3c7aba0e961b69cb3df701c91662c98ad694467d060ce1/ruff-0.16.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8adbe4e58af167f767d7b2ba5e83c42e878350796cf78c2f5e14ab9903a92588", size = 10749366, upload-time = "2026-09-24T20:37:41.042Z" },
|
|
3809
|
+
{ url = "https://files.pythonhosted.org/packages/ac/fe/734ec7527029ac757ecf821f143c9f3fcf69149c21f53a044a899b430f5a/ruff-0.16.9-py3-none-win32.whl", hash = "sha256:0e1dbc2073624dee6618d41d0098690a7244654af746704b64759e12b6b6b385", size = 10152355, upload-time = "2026-09-24T20:37:43.025Z" },
|
|
3810
|
+
{ url = "https://files.pythonhosted.org/packages/14/21/26e4643629b3ebb44f0a06f9c9a53058d63d989415f63a9a3c28e2ee7f22/ruff-0.16.9-py3-none-win_amd64.whl", hash = "sha256:6bd40fec8cd4c8a3d4dd589bd8ad4e6320c13c29234159bfd959a40d529d597b", size = 10592965, upload-time = "2026-09-24T20:37:44.944Z" },
|
|
3811
|
+
{ url = "https://files.pythonhosted.org/packages/51/60/5fb1a39dbb5ae314d5f59bc7348a63c1d5c20f3cd83914c4b5cb0be31d2d/ruff-0.16.9-py3-none-win_arm64.whl", hash = "sha256:ed1a252039200f57a59eebc063b54beabea67bfbaaca0eeaa7f54b5fbcda2284", size = 10458649, upload-time = "2026-09-24T20:37:46.882Z" },
|
|
3812
3812
|
]
|
|
3813
3813
|
|
|
3814
3814
|
[[package]]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyobs_gui-2.5.0 → pyobs_gui-2.5.2}/pyobs_gui/qt/resources/arrow-up-right-from-square-solid.svg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|