pyobs-core 2.20.0__tar.gz → 2.22.0__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 (480) hide show
  1. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/PKG-INFO +1 -1
  2. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/application.py +18 -2
  3. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/comm.py +7 -4
  4. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/rpc.py +31 -10
  5. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/__init__.py +2 -0
  6. pyobs_core-2.22.0/pyobs/events/newdata.py +47 -0
  7. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/newimage.py +7 -10
  8. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/newspectrum.py +7 -14
  9. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IMotion.py +2 -0
  10. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/fitsheader.py +1 -1
  11. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/follow.py +1 -1
  12. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/__init__.py +2 -0
  13. pyobs_core-2.22.0/pyobs/modules/camera/basedata.py +73 -0
  14. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/basespectrograph.py +5 -0
  15. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/module.py +7 -4
  16. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/mastermind.py +37 -24
  17. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/pointing.py +1 -1
  18. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/basetelescope.py +116 -5
  19. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/exceptions.py +12 -0
  20. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/shellcommand.py +1 -1
  21. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyproject.toml +1 -1
  22. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/.gitignore +0 -0
  23. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/LICENSE +0 -0
  24. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/README.md +0 -0
  25. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/__init__.py +0 -0
  26. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/background_task.py +0 -0
  27. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/cli/__init__.py +0 -0
  28. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/cli/_cli.py +0 -0
  29. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/cli/pyobs.py +0 -0
  30. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/cli/pyobsd.py +0 -0
  31. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/cli/pyobsw.py +0 -0
  32. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/__init__.py +0 -0
  33. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/commlogging.py +0 -0
  34. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/dummy/__init__.py +0 -0
  35. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/dummy/dummycomm.py +0 -0
  36. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/local/__init__.py +0 -0
  37. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/local/localcomm.py +0 -0
  38. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/local/localnetwork.py +0 -0
  39. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/proxy.py +0 -0
  40. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/__init__.py +0 -0
  41. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/serializer.py +0 -0
  42. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
  43. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
  44. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
  45. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
  46. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
  47. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
  48. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
  49. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xmppclient.py +0 -0
  50. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xmppcomm.py +0 -0
  51. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/badweather.py +0 -0
  52. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/event.py +0 -0
  53. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/exposurestatuschanged.py +0 -0
  54. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/filewritten.py +0 -0
  55. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/filterchanged.py +0 -0
  56. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/focusfound.py +0 -0
  57. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/goodweather.py +0 -0
  58. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/log.py +0 -0
  59. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/modechanged.py +0 -0
  60. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/moduleclosed.py +0 -0
  61. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/moduleopened.py +0 -0
  62. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/motionstatuschanged.py +0 -0
  63. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/move.py +0 -0
  64. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/offsets.py +0 -0
  65. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/roofclosing.py +0 -0
  66. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/roofopened.py +0 -0
  67. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/taskfailed.py +0 -0
  68. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/taskfinished.py +0 -0
  69. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/taskskipped.py +0 -0
  70. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/taskstarted.py +0 -0
  71. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/testevent.py +0 -0
  72. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/__init__.py +0 -0
  73. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/image.py +0 -0
  74. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/__init__.py +0 -0
  75. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/altazoffsets.py +0 -0
  76. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/datapipeline.py +0 -0
  77. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/exptime.py +0 -0
  78. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/genericoffset.py +0 -0
  79. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/onskydistance.py +0 -0
  80. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/pixeloffsets.py +0 -0
  81. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/radecoffsets.py +0 -0
  82. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/skyoffsets.py +0 -0
  83. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processor.py +0 -0
  84. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/__init__.py +0 -0
  85. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/_daobackgroundremover.py +0 -0
  86. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/annotation/__init__.py +0 -0
  87. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/annotation/_pillow.py +0 -0
  88. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/annotation/circle.py +0 -0
  89. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/annotation/crosshair.py +0 -0
  90. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/annotation/text.py +0 -0
  91. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/__init__.py +0 -0
  92. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
  93. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
  94. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
  95. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
  96. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/astrometry.py +0 -0
  97. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/dotnet.py +0 -0
  98. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/calibration/__init__.py +0 -0
  99. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
  100. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
  101. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/calibration/calibration.py +0 -0
  102. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/__init__.py +0 -0
  103. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
  104. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/_source_catalog.py +0 -0
  105. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/daophot.py +0 -0
  106. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/pysep.py +0 -0
  107. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/simpledisk.py +0 -0
  108. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/sourcedetection.py +0 -0
  109. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/exptime/__init__.py +0 -0
  110. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/exptime/exptime.py +0 -0
  111. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/exptime/star.py +0 -0
  112. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/__init__.py +0 -0
  113. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/addfitsheaders.py +0 -0
  114. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/download.py +0 -0
  115. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/flip.py +0 -0
  116. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/grayscale.py +0 -0
  117. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/httpserver.py +0 -0
  118. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/normalize.py +0 -0
  119. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/save.py +0 -0
  120. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/saveimage.py +0 -0
  121. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/smooth.py +0 -0
  122. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/softbin.py +0 -0
  123. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/__init__.py +0 -0
  124. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/addmask.py +0 -0
  125. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
  126. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/circularmask.py +0 -0
  127. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/createfilename.py +0 -0
  128. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
  129. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/removebackground.py +0 -0
  130. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/modules/__init__.py +0 -0
  131. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/modules/getfitsheaders.py +0 -0
  132. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/__init__.py +0 -0
  133. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/astrometry.py +0 -0
  134. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/brighteststar.py +0 -0
  135. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
  136. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
  137. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
  138. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/fitsheader.py +0 -0
  139. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/offsets.py +0 -0
  140. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
  141. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/projected.py +0 -0
  142. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/spilled_light.py +0 -0
  143. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/__init__.py +0 -0
  144. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
  145. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
  146. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
  147. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
  148. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/photometry.py +0 -0
  149. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/photutil.py +0 -0
  150. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/pysep.py +0 -0
  151. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/__init__.py +0 -0
  152. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/combinestack.py +0 -0
  153. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/mean.py +0 -0
  154. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/median.py +0 -0
  155. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/sigmaclip.py +0 -0
  156. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/sum.py +0 -0
  157. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/wcs/__init__.py +0 -0
  158. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
  159. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IAbortable.py +0 -0
  160. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IAcquisition.py +0 -0
  161. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IAutoFocus.py +0 -0
  162. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IAutoGuiding.py +0 -0
  163. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IAutonomous.py +0 -0
  164. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IBinning.py +0 -0
  165. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ICalibrate.py +0 -0
  166. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ICamera.py +0 -0
  167. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IConfig.py +0 -0
  168. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ICooling.py +0 -0
  169. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IData.py +0 -0
  170. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IDataPipeline.py +0 -0
  171. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IDataSequence.py +0 -0
  172. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IDataStack.py +0 -0
  173. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IDome.py +0 -0
  174. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IExposure.py +0 -0
  175. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IExposureTime.py +0 -0
  176. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFilters.py +0 -0
  177. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
  178. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
  179. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFlatField.py +0 -0
  180. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFocusModel.py +0 -0
  181. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFocuser.py +0 -0
  182. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IGain.py +0 -0
  183. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IImageFormat.py +0 -0
  184. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IImageType.py +0 -0
  185. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IMode.py +0 -0
  186. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IModule.py +0 -0
  187. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IMultiFiber.py +0 -0
  188. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IOffsetsAltAz.py +0 -0
  189. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IOffsetsRaDec.py +0 -0
  190. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingAltAz.py +0 -0
  191. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingBody.py +0 -0
  192. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingHeliocentricPolar.py +0 -0
  193. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingHeliographicStonyhurst.py +0 -0
  194. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingHelioprojective.py +0 -0
  195. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingOrbitalElements.py +0 -0
  196. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingRaDec.py +0 -0
  197. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingSeries.py +0 -0
  198. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPushNotifications.py +0 -0
  199. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IReady.py +0 -0
  200. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IResettable.py +0 -0
  201. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRobotic.py +0 -0
  202. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRoboticScheduler.py +0 -0
  203. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRoof.py +0 -0
  204. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRotation.py +0 -0
  205. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRunnable.py +0 -0
  206. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRunning.py +0 -0
  207. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IScriptRunner.py +0 -0
  208. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ISpectrograph.py +0 -0
  209. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IStartStop.py +0 -0
  210. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IStructuredConfig.py +0 -0
  211. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ISyncTarget.py +0 -0
  212. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ITelescope.py +0 -0
  213. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ITemperatures.py +0 -0
  214. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ITrackingMode.py +0 -0
  215. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ITrackingRate.py +0 -0
  216. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IVideo.py +0 -0
  217. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IWeather.py +0 -0
  218. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IWindow.py +0 -0
  219. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/__init__.py +0 -0
  220. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/interface.py +0 -0
  221. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/__init__.py +0 -0
  222. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/camerasettings.py +0 -0
  223. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/datapipeline.py +0 -0
  224. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/datasequence.py +0 -0
  225. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/fitsnamespace.py +0 -0
  226. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/motionstatus.py +0 -0
  227. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/pipeline.py +0 -0
  228. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/waitformotion.py +0 -0
  229. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/weatheraware.py +0 -0
  230. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/__init__.py +0 -0
  231. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/adaptive.py +0 -0
  232. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/basecamera.py +0 -0
  233. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/basevideo.py +0 -0
  234. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/dummycamera.py +0 -0
  235. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/dummyspectrograph.py +0 -0
  236. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/dummyvideo.py +0 -0
  237. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/pipelinecamera.py +0 -0
  238. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/videoframes.py +0 -0
  239. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/flatfield/__init__.py +0 -0
  240. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/flatfield/flatfield.py +0 -0
  241. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/flatfield/pointing.py +0 -0
  242. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/flatfield/scheduler.py +0 -0
  243. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/focus/__init__.py +0 -0
  244. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/focus/dummyautofocus.py +0 -0
  245. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/focus/focusmodel.py +0 -0
  246. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/focus/focusseries.py +0 -0
  247. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/image/__init__.py +0 -0
  248. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/image/imagewatcher.py +0 -0
  249. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/image/imagewriter.py +0 -0
  250. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/image/pipeline.py +0 -0
  251. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/image/seeing.py +0 -0
  252. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/__init__.py +0 -0
  253. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/_base.py +0 -0
  254. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/_baseguiding.py +0 -0
  255. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/acquisition.py +0 -0
  256. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/autoguiding.py +0 -0
  257. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/dummyacquisition.py +0 -0
  258. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/dummyguiding.py +0 -0
  259. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingsource.py +0 -0
  260. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
  261. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
  262. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
  263. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
  264. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
  265. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/scienceframeguiding.py +0 -0
  266. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/__init__.py +0 -0
  267. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/dummymastermind.py +0 -0
  268. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/dummyscheduler.py +0 -0
  269. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/scheduler.py +0 -0
  270. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/scriptrunner.py +0 -0
  271. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/roof/__init__.py +0 -0
  272. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/roof/basedome.py +0 -0
  273. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/roof/baseroof.py +0 -0
  274. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/roof/dummyroof.py +0 -0
  275. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/__init__.py +0 -0
  276. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/_dummytelescopebase.py +0 -0
  277. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/dummyaltaztelescope.py +0 -0
  278. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/dummyradectelescope.py +0 -0
  279. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/dummysolartelescope.py +0 -0
  280. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/test/__init__.py +0 -0
  281. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/test/standalone.py +0 -0
  282. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/__init__.py +0 -0
  283. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/dummymode.py +0 -0
  284. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/dummystructuredconfig.py +0 -0
  285. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/fluentlogger.py +0 -0
  286. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/httpfilecache.py +0 -0
  287. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/kiosk.py +0 -0
  288. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/matrix.py +0 -0
  289. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/pushnotifier.py +0 -0
  290. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/stellarium.py +0 -0
  291. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/telegram.py +0 -0
  292. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/trigger.py +0 -0
  293. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/weather/__init__.py +0 -0
  294. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/weather/mockweather.py +0 -0
  295. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/weather/weather.py +0 -0
  296. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/weather/weather_api.py +0 -0
  297. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/weather/weather_state.py +0 -0
  298. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/object.py +0 -0
  299. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/py.typed +0 -0
  300. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/__init__.py +0 -0
  301. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/instruments.py +0 -0
  302. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/observation.py +0 -0
  303. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/__init__.py +0 -0
  304. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/_executor.py +0 -0
  305. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
  306. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
  307. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
  308. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
  309. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +0 -0
  310. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +0 -0
  311. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +0 -0
  312. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
  313. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/dataprovider.py +0 -0
  314. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
  315. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
  316. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
  317. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/constant.py +0 -0
  318. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/follow.py +0 -0
  319. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/interval.py +0 -0
  320. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/merit.py +0 -0
  321. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
  322. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/random.py +0 -0
  323. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
  324. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/transit.py +0 -0
  325. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
  326. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/observingperiod.py +0 -0
  327. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/ondemandscheduler.py +0 -0
  328. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
  329. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
  330. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/heliocentricpolartarget.py +0 -0
  331. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/helioprojectivetarget.py +0 -0
  332. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
  333. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
  334. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
  335. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
  336. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/target.py +0 -0
  337. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
  338. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/__init__.py +0 -0
  339. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
  340. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/calibration/darkbias.py +0 -0
  341. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/calibration/pointing.py +0 -0
  342. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/calibration/skyflats.py +0 -0
  343. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/__init__.py +0 -0
  344. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/cases.py +0 -0
  345. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/conditional.py +0 -0
  346. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/parallel.py +0 -0
  347. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/selector.py +0 -0
  348. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/sequential.py +0 -0
  349. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/exceptions.py +0 -0
  350. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
  351. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/imaging/autofocus.py +0 -0
  352. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/imaging/imaging.py +0 -0
  353. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
  354. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/script.py +0 -0
  355. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/utils/__init__.py +0 -0
  356. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/utils/callmodule.py +0 -0
  357. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
  358. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/utils/log.py +0 -0
  359. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/__init__.py +0 -0
  360. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
  361. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
  362. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
  363. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/__init__.py +0 -0
  364. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/_portal.py +0 -0
  365. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
  366. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
  367. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/configdb.py +0 -0
  368. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
  369. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
  370. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
  371. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/scripts/autofocus.py +0 -0
  372. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/scripts/default.py +0 -0
  373. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
  374. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/task.py +0 -0
  375. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
  376. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
  377. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/memory/__init__.py +0 -0
  378. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
  379. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
  380. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/observationarchive.py +0 -0
  381. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/portal/__init__.py +0 -0
  382. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/portal/observationarchive.py +0 -0
  383. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/portal/taskarchive.py +0 -0
  384. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/taskarchive.py +0 -0
  385. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/task.py +0 -0
  386. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/taskrunner.py +0 -0
  387. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/__init__.py +0 -0
  388. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/archive/__init__.py +0 -0
  389. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/archive/archive.py +0 -0
  390. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/archive/local_archive.py +0 -0
  391. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
  392. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/calibration.py +0 -0
  393. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/exptime/__init__.py +0 -0
  394. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/exptime/exptime.py +0 -0
  395. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/exptime/stellarexptime.py +0 -0
  396. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
  397. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
  398. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/flatfielder.py +0 -0
  399. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
  400. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
  401. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
  402. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
  403. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
  404. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
  405. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
  406. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
  407. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/__init__.py +0 -0
  408. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/average.py +0 -0
  409. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/cache.py +0 -0
  410. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/config.py +0 -0
  411. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/config_schema.py +0 -0
  412. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/coordinates.py +0 -0
  413. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/curvefit.py +0 -0
  414. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/enums.py +0 -0
  415. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/exptime_grouping.py +0 -0
  416. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/fits.py +0 -0
  417. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/focusseries/__init__.py +0 -0
  418. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/focusseries/base.py +0 -0
  419. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/focusseries/photometry.py +0 -0
  420. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/focusseries/projection.py +0 -0
  421. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/grids/__init__.py +0 -0
  422. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/grids/filters.py +0 -0
  423. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/grids/grid.py +0 -0
  424. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/grids/gridnode.py +0 -0
  425. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/grids/pipeline.py +0 -0
  426. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/__init__.py +0 -0
  427. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/__init__.py +0 -0
  428. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/binningwidget.py +0 -0
  429. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
  430. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/exposewidget.py +0 -0
  431. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
  432. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
  433. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
  434. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
  435. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/http.py +0 -0
  436. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/influxdb.py +0 -0
  437. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/logger.py +0 -0
  438. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/logging/__init__.py +0 -0
  439. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/logging/context.py +0 -0
  440. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/logging/resolvableerror.py +0 -0
  441. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/modulegui.py +0 -0
  442. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/offsets/__init__.py +0 -0
  443. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
  444. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/offsets/applyoffsets.py +0 -0
  445. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
  446. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/parallel.py +0 -0
  447. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/pipeline/__init__.py +0 -0
  448. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/pipeline/pipeline.py +0 -0
  449. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/pipeline/progress.py +0 -0
  450. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/pipeline/reduction.py +0 -0
  451. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/pipeline/reduction_base.py +0 -0
  452. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/__init__.py +0 -0
  453. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/csv.py +0 -0
  454. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/http.py +0 -0
  455. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/log.py +0 -0
  456. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/multi.py +0 -0
  457. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/publisher.py +0 -0
  458. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/serialization.py +0 -0
  459. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/stretch.py +0 -0
  460. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/threads/__init__.py +0 -0
  461. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/threads/lockwithabort.py +0 -0
  462. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/time.py +0 -0
  463. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/units.py +0 -0
  464. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/versions.py +0 -0
  465. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/version.py +0 -0
  466. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/__init__.py +0 -0
  467. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/archivefile.py +0 -0
  468. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/bufferedfile.py +0 -0
  469. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/file.py +0 -0
  470. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/filelists/__init__.py +0 -0
  471. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/filelists/filelist.py +0 -0
  472. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/filelists/testing.py +0 -0
  473. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/httpfile.py +0 -0
  474. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/localfile.py +0 -0
  475. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/memfile.py +0 -0
  476. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/sftpfile.py +0 -0
  477. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/smbfile.py +0 -0
  478. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/sshfile.py +0 -0
  479. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/tempfile.py +0 -0
  480. {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/vfs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyobs-core
3
- Version: 2.20.0
3
+ Version: 2.22.0
4
4
  Summary: robotic telescope software
5
5
  Project-URL: Homepage, https://www.pyobs.org
6
6
  Project-URL: Documentation, https://docs.pyobs.org
@@ -65,14 +65,30 @@ def _warm_iers_cache() -> None:
65
65
  conversion needs it -- update_leap_seconds() (not the lower-level LeapSeconds.auto_open())
66
66
  is the call that also installs the result into erfa so real usage later doesn't re-fetch.
67
67
 
68
+ If the refresh fails, auto-download is disabled for the process and the error re-raised.
69
+
68
70
  Meant to run inside an executor thread (see Application._main) -- calling this directly
69
71
  on the event loop would defeat the point.
70
72
  """
73
+ from astropy.time import Time
71
74
  from astropy.time.core import update_leap_seconds
72
75
  from astropy.utils.iers import IERS_Auto
73
76
 
74
- IERS_Auto.open()
75
- update_leap_seconds()
77
+ try:
78
+ table = IERS_Auto.open()
79
+ # open() alone does not refresh a stale table: that only happens on the first lookup
80
+ # for an actual time (IERS_Auto._interpolate -> _refresh_table_as_needed), which would
81
+ # otherwise be the first alt/az on the event loop. Do that lookup here, covering both
82
+ # UT1-UTC and polar motion.
83
+ now = Time.now()
84
+ table.ut1_utc(now)
85
+ table.pm_xy(now)
86
+ update_leap_seconds()
87
+ except Exception:
88
+ # refresh failed (e.g. offline): astropy would otherwise raise (or retry the download)
89
+ # on every later alt/az, so fall back to the bundled table for this process
90
+ _disable_iers_auto_download()
91
+ raise
76
92
 
77
93
 
78
94
  class InfluxLogConfig(TypedDict):
@@ -423,16 +423,19 @@ class Comm:
423
423
 
424
424
  async def register_event(self, event_class: type[Event], handler: EventHandler | None = None) -> None:
425
425
  """Register an event type. If a handler is given, we also receive those events, otherwise we just
426
- send them. Event classes derived from the given one are registered, too, but only those that have been
427
- imported (and therefore registered) by now.
426
+ send them.
427
+
428
+ With a handler, event classes derived from the given one are subscribed, too, but only those that have
429
+ been imported (and therefore registered) by now. Without a handler, only the given class itself is
430
+ declared as sent: a module that sends several related events registers each of them.
428
431
 
429
432
  Args:
430
433
  event_class: Class of event to register.
431
434
  handler: Event handler method.
432
435
  """
433
436
 
434
- # we also want to register all events derived from the given one
435
- event_classes = self._get_derived_events(event_class)
437
+ # a handler also covers derived events, but we only declare to send exactly the given class
438
+ event_classes = self._get_derived_events(event_class) if handler else [event_class]
436
439
 
437
440
  # do we have a handler? then we subscribe, otherwise we just declare that we send it
438
441
  if handler:
@@ -135,17 +135,38 @@ def fault_to_xml(exception: Exception) -> ET.Element:
135
135
  return fault
136
136
 
137
137
 
138
+ def _pyobs_fault(fault_elem: ET.Element) -> ET.Element | None:
139
+ """Return the <pyobs:fault> element inside a <fault><value>, or None."""
140
+ value_elem = fault_elem.find(f"{{{_NS}}}value")
141
+ if value_elem is None:
142
+ return None
143
+ return value_elem.find(f"{{{_PYOBS_NS}}}fault")
144
+
145
+
146
+ def _fault_child(parent: ET.Element, name: str) -> ET.Element | None:
147
+ """Find a child of a fault element, with or without the pyobs namespace.
148
+
149
+ Depending on the sender's slixmpp version, the children of <pyobs:fault> go over the wire either with
150
+ an explicit xmlns="" (slixmpp >= 1.17, parsed without namespace) or without it, in which case they
151
+ inherit urn:pyobs:rpc:1 from their parent when parsed (slixmpp <= 1.16). Both forms must be accepted (#1030).
152
+ """
153
+ child = parent.find(f"{{{_PYOBS_NS}}}{name}")
154
+ return child if child is not None else parent.find(name)
155
+
156
+
138
157
  def xml_to_fault(fault_elem: ET.Element) -> tuple[str, str]:
139
158
  """Parse <fault> and return (exception_qualified_name, message)."""
140
159
  _fallback_name = f"{exc.RemoteError.__module__}.{exc.RemoteError.__qualname__}"
141
- value_elem = fault_elem.find(f"{{{_NS}}}value")
142
- if value_elem is None:
160
+ if fault_elem.find(f"{{{_NS}}}value") is None:
143
161
  return _fallback_name, "Unknown error"
144
- pyobs_fault = value_elem.find(f"{{{_PYOBS_NS}}}fault")
162
+ pyobs_fault = _pyobs_fault(fault_elem)
145
163
  if pyobs_fault is None:
146
164
  return _fallback_name, "Unknown error"
147
- exc_el = pyobs_fault.find("exception")
148
- msg_el = pyobs_fault.find("message")
165
+ exc_el = _fault_child(pyobs_fault, "exception")
166
+ msg_el = _fault_child(pyobs_fault, "message")
167
+ if exc_el is None:
168
+ # would otherwise silently become an empty RemoteError, which is how #1030 stayed hidden
169
+ log.warning("Received fault without exception element: %s", ET.tostring(fault_elem, encoding="unicode"))
149
170
  exc_name = (exc_el.text if exc_el is not None else None) or _fallback_name
150
171
  msg = (msg_el.text if msg_el is not None else None) or ""
151
172
  return exc_name, msg
@@ -156,13 +177,13 @@ def xml_to_fault_bases(fault_elem: ET.Element) -> list[str]:
156
177
 
157
178
  Empty if the fault has none, e.g. when it comes from a peer that does not send them.
158
179
  """
159
- value_elem = fault_elem.find(f"{{{_NS}}}value")
160
- if value_elem is None:
161
- return []
162
- pyobs_fault = value_elem.find(f"{{{_PYOBS_NS}}}fault")
180
+ pyobs_fault = _pyobs_fault(fault_elem)
163
181
  if pyobs_fault is None:
164
182
  return []
165
- return [b.text for b in pyobs_fault.iterfind("bases/base") if b.text]
183
+ bases_elem = _fault_child(pyobs_fault, "bases")
184
+ if bases_elem is None:
185
+ return []
186
+ return [b.text for b in bases_elem if b.tag.split("}")[-1] == "base" and b.text]
166
187
 
167
188
 
168
189
  def reconstruct_fault(name: str, message: str, bases: list[str], remote_module: str) -> exc.PyobsError:
@@ -17,6 +17,7 @@ from .moduleclosed import ModuleClosedEvent
17
17
  from .moduleopened import ModuleOpenedEvent
18
18
  from .motionstatuschanged import MotionStatusChangedEvent
19
19
  from .move import MoveAltAzEvent, MoveEvent, MoveRaDecEvent
20
+ from .newdata import NewDataEvent
20
21
  from .newimage import NewImageEvent
21
22
  from .newspectrum import NewSpectrumEvent
22
23
  from .offsets import OffsetsAltAzEvent, OffsetsEvent, OffsetsRaDecEvent
@@ -47,6 +48,7 @@ __all__ = [
47
48
  "MoveEvent",
48
49
  "MoveRaDecEvent",
49
50
  "MoveAltAzEvent",
51
+ "NewDataEvent",
50
52
  "NewImageEvent",
51
53
  "NewSpectrumEvent",
52
54
  "RoofClosingEvent",
@@ -0,0 +1,47 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, TypedDict
4
+
5
+ from pyobs.events.event import Event
6
+
7
+
8
+ class DataType(TypedDict):
9
+ filename: str
10
+
11
+
12
+ class NewDataEvent(Event):
13
+ """Event to be sent on new data, e.g. a file that is neither an image nor a spectrum.
14
+
15
+ ``filename`` is a VFS path. :class:`NewImageEvent` and :class:`NewSpectrumEvent` derive from this class, so a
16
+ handler registered for ``NewDataEvent`` also receives those; use ``type(event) is NewDataEvent`` to select only
17
+ generic data.
18
+ Registering ``NewDataEvent`` without a handler declares only this class as sent, not the derived events.
19
+ """
20
+
21
+ __module__ = "pyobs.events"
22
+
23
+ def __init__(self, filename: str, **kwargs: Any):
24
+ """Initializes new NewDataEvent.
25
+
26
+ Args:
27
+ filename: Name of new data file.
28
+ """
29
+ Event.__init__(self)
30
+ self.data: DataType = {"filename": filename}
31
+
32
+ @classmethod
33
+ def from_dict(cls, d: dict[str, Any]) -> Event:
34
+ # get filename
35
+ if "filename" not in d or not isinstance(d["filename"], str):
36
+ raise ValueError("Invalid type for filename.")
37
+ filename: str = d["filename"]
38
+
39
+ # return object
40
+ return cls(filename)
41
+
42
+ @property
43
+ def filename(self) -> str:
44
+ return self.data["filename"]
45
+
46
+
47
+ __all__ = ["NewDataEvent"]
@@ -1,18 +1,19 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, TypedDict
3
+ from typing import Any
4
4
 
5
5
  from pyobs.events.event import Event
6
+ from pyobs.events.newdata import DataType as NewDataType
7
+ from pyobs.events.newdata import NewDataEvent
6
8
  from pyobs.utils.enums import ImageType
7
9
 
8
10
 
9
- class DataType(TypedDict):
10
- filename: str
11
+ class DataType(NewDataType):
11
12
  image_type: str | None
12
13
  raw: str | None
13
14
 
14
15
 
15
- class NewImageEvent(Event):
16
+ class NewImageEvent(NewDataEvent):
16
17
  """Event to be sent on a new image."""
17
18
 
18
19
  __module__ = "pyobs.events"
@@ -25,7 +26,7 @@ class NewImageEvent(Event):
25
26
  image_type: Type of image.
26
27
  raw: Only for reduced images, references raw frame.
27
28
  """
28
- Event.__init__(self)
29
+ NewDataEvent.__init__(self, filename)
29
30
  self.data: DataType = {
30
31
  "filename": filename,
31
32
  "image_type": image_type if image_type is not None else None,
@@ -50,11 +51,7 @@ class NewImageEvent(Event):
50
51
  raw = d["raw"]
51
52
 
52
53
  # return object
53
- return NewImageEvent(filename, image_type, raw)
54
-
55
- @property
56
- def filename(self) -> str:
57
- return self.data["filename"]
54
+ return cls(filename, image_type, raw)
58
55
 
59
56
  @property
60
57
  def image_type(self) -> ImageType | None:
@@ -1,16 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, TypedDict
3
+ from typing import Any
4
4
 
5
5
  from pyobs.events.event import Event
6
+ from pyobs.events.newdata import DataType, NewDataEvent
6
7
 
7
8
 
8
- class DataType(TypedDict):
9
- filename: str
10
-
11
-
12
- class NewSpectrumEvent(Event):
13
- """Event to be sent on a new image."""
9
+ class NewSpectrumEvent(NewDataEvent):
10
+ """Event to be sent on a new spectrum."""
14
11
 
15
12
  __module__ = "pyobs.events"
16
13
 
@@ -18,9 +15,9 @@ class NewSpectrumEvent(Event):
18
15
  """Initializes new NewSpectrumEvent.
19
16
 
20
17
  Args:
21
- filename: Name of new image file.
18
+ filename: Name of new spectrum file.
22
19
  """
23
- Event.__init__(self)
20
+ NewDataEvent.__init__(self, filename)
24
21
  self.data: DataType = {"filename": filename}
25
22
 
26
23
  @classmethod
@@ -31,11 +28,7 @@ class NewSpectrumEvent(Event):
31
28
  filename: str = d["filename"]
32
29
 
33
30
  # return object
34
- return NewSpectrumEvent(filename)
35
-
36
- @property
37
- def filename(self) -> str:
38
- return self.data["filename"]
31
+ return cls(filename)
39
32
 
40
33
 
41
34
  __all__ = ["NewSpectrumEvent"]
@@ -36,6 +36,8 @@ class IMotion(IReady, metaclass=ABCMeta):
36
36
 
37
37
  Raises:
38
38
  InitError: If device could not be initialized.
39
+ InitAbortedError: If initialization was interrupted on purpose (e.g. by park() or stop_motion()); not a
40
+ device fault.
39
41
  """
40
42
  ...
41
43
 
@@ -103,7 +103,7 @@ async def add_requested_fits_headers(
103
103
 
104
104
  try:
105
105
  headers = future.result()
106
- except exc.RemoteError as e:
106
+ except exc.PyobsError as e:
107
107
  log.warning("Could not fetch FITS headers from %s: %s.", client, str(e))
108
108
  continue
109
109
  except Exception as e:
@@ -173,7 +173,7 @@ class FollowMixin:
173
173
  continue
174
174
  other_coords = build_skycoord(xy_coords, this.__follow_mode)
175
175
  connected = True
176
- except (ValueError, exc.RemoteError):
176
+ except (ValueError, exc.PyobsError):
177
177
  if connected:
178
178
  log.warning("Could not fetch coordinates.")
179
179
  connected = False
@@ -6,6 +6,7 @@ TODO: write doc
6
6
  __title__ = "Cameras"
7
7
 
8
8
  from .basecamera import BaseCamera
9
+ from .basedata import BaseData
9
10
  from .basespectrograph import BaseSpectrograph
10
11
  from .basevideo import BaseVideo
11
12
  from .dummycamera import DummyCamera
@@ -15,6 +16,7 @@ from .videoframes import Frame, FrameRecord, StartSource
15
16
 
16
17
  __all__ = [
17
18
  "BaseCamera",
19
+ "BaseData",
18
20
  "BaseVideo",
19
21
  "BaseSpectrograph",
20
22
  "DummyCamera",
@@ -0,0 +1,73 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from abc import ABCMeta
5
+ from typing import Any
6
+
7
+ from pyobs.events import NewDataEvent
8
+ from pyobs.interfaces import IData
9
+ from pyobs.mixins.datasequence import DataSequenceMixin
10
+ from pyobs.mixins.fitsheader import FitsHeaderMixin
11
+ from pyobs.modules import Module
12
+
13
+ log = logging.getLogger(__name__)
14
+
15
+
16
+ class BaseData(Module, FitsHeaderMixin, IData, DataSequenceMixin, metaclass=ABCMeta):
17
+ """Base class for modules that grab data that is neither an image nor a spectrum.
18
+
19
+ Provides the FITS header handling and file naming of :class:`~pyobs.mixins.FitsHeaderMixin`, grab sequences
20
+ via :class:`~pyobs.mixins.DataSequenceMixin`, and sends a :class:`~pyobs.events.NewDataEvent` for new data.
21
+ Derived classes implement ``grab_data()`` and ``_sequence_busy()``, call :meth:`_send_new_data` once the data
22
+ is stored, and extend :meth:`abort` with the actual hardware abort.
23
+ """
24
+
25
+ __module__ = "pyobs.modules.camera"
26
+
27
+ def __init__(
28
+ self,
29
+ fits_headers: dict[str, Any] | None = None,
30
+ filenames: str = "/cache/pyobs-{DAY-OBS|date:}-{FRAMENUM|string:04d}.fits.gz",
31
+ fits_namespaces: list[str] | None = None,
32
+ **kwargs: Any,
33
+ ):
34
+ """Creates a new BaseData.
35
+
36
+ Args:
37
+ fits_headers: Additional FITS headers.
38
+ filenames: Template for file naming.
39
+ fits_namespaces: List of namespaces for FITS headers that this module should request.
40
+ """
41
+ super().__init__(fits_namespaces=fits_namespaces, fits_headers=fits_headers, filenames=filenames, **kwargs)
42
+
43
+ if self._comm is None:
44
+ log.warning("No comm module given, will not be able to signal new data!")
45
+
46
+ async def open(self) -> None:
47
+ """Open module."""
48
+ await Module.open(self)
49
+
50
+ # declare the event we send, exactly this class (NewImageEvent and NewSpectrumEvent are not sent)
51
+ if self._comm:
52
+ await self.comm.register_event(NewDataEvent)
53
+
54
+ # publish initial state
55
+ await self._datasequence_open()
56
+
57
+ async def _send_new_data(self, filename: str, broadcast: bool = True) -> None:
58
+ """Send a NewDataEvent for stored data.
59
+
60
+ Args:
61
+ filename: VFS path of the stored data.
62
+ broadcast: Whether to send the event at all.
63
+ """
64
+ if broadcast and self._comm:
65
+ await self.comm.send_event(NewDataEvent(filename))
66
+
67
+ async def abort(self, **kwargs: Any) -> None:
68
+ """Aborts the current grab and sequence. Derived classes must implement the actual hardware abort and
69
+ call this."""
70
+ self._abort_data_sequence()
71
+
72
+
73
+ __all__ = ["BaseData"]
@@ -65,6 +65,11 @@ class BaseSpectrograph(
65
65
  """Open module."""
66
66
  await Module.open(self)
67
67
 
68
+ # declare the events we send
69
+ if self._comm:
70
+ await self.comm.register_event(NewSpectrumEvent)
71
+ await self.comm.register_event(ExposureStatusChangedEvent)
72
+
68
73
  # publish initial state
69
74
  await self.comm.set_state(
70
75
  IExposure, ExposureState(status=self._spectrograph_status, progress=0.0, exposure_time_left=0.0)
@@ -251,7 +251,8 @@ class Module(Object, IModule, IConfig):
251
251
 
252
252
  Args:
253
253
  exc_type: Exception type (or a shared ancestor) to watch for. RemoteError also
254
- counts remote domain faults, except expected PointingLimitError rejections.
254
+ counts remote domain faults, except expected PointingLimitError and
255
+ InitAbortedError rejections.
255
256
  limit: Number of occurrences that triggers the callback.
256
257
  timespan: If given, only count occurrences within the last timespan seconds.
257
258
  module: If given, only count occurrences tagged as coming from this remote module
@@ -281,17 +282,19 @@ class Module(Object, IModule, IConfig):
281
282
 
282
283
  @staticmethod
283
284
  def _counts_as_remote_error(exception: Exception) -> bool:
284
- """Classify remote domain failures for broad handlers, excluding expected pointing rejections.
285
+ """Classify remote domain failures for broad handlers, excluding expected rejections.
286
+
287
+ Expected rejections are PointingLimitError and InitAbortedError.
285
288
 
286
289
  Actual RemoteError inheritance and explicit domain handlers are handled separately.
287
290
  """
288
291
  return getattr(exception, "remote_module", None) is not None and not isinstance(
289
- exception, exc.PointingLimitError
292
+ exception, exc.PointingLimitError | exc.InitAbortedError
290
293
  )
291
294
 
292
295
  def _store_exception(self, exception: exc.PyobsError, module: str | None) -> None:
293
296
  # Preserve actual ancestors and classify eligible remote domain faults as RemoteError
294
- # for broad severity handlers. Expected pointing rejections retain their domain buckets.
297
+ # for broad severity handlers. Expected rejections (pointing limits, aborted init) retain their domain buckets.
295
298
  classes: list[type] = list(type(exception).__mro__)
296
299
  if self._counts_as_remote_error(exception) and exc.RemoteError not in classes:
297
300
  classes.append(exc.RemoteError)
@@ -43,7 +43,7 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
43
43
  runner: TaskRunner | dict[str, Any],
44
44
  tasks: TaskArchive | dict[str, Any] | None = None,
45
45
  allowed_late_start: int = 300,
46
- allowed_overrun: int = 300,
46
+ allowed_overrun: int | None = 300,
47
47
  after_task_sleep: int = 0,
48
48
  **kwargs: Any,
49
49
  ):
@@ -52,7 +52,8 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
52
52
  Args:
53
53
  schedule: Object that can return schedule.
54
54
  allowed_late_start: Allowed seconds to start late.
55
- allowed_overrun: Allowed time for a task to exceed it's window in seconds
55
+ allowed_overrun: Allowed time for a task to exceed its window in seconds, after which it is aborted.
56
+ None disables the check.
56
57
  """
57
58
  Module.__init__(self, **kwargs)
58
59
 
@@ -119,6 +120,7 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
119
120
  # subscribe to events
120
121
  if self._comm:
121
122
  await self.comm.register_event(TaskStartedEvent)
123
+ await self.comm.register_event(TaskFailedEvent)
122
124
  await self.comm.register_event(TaskFinishedEvent)
123
125
  await self.comm.register_event(TaskSkippedEvent)
124
126
 
@@ -141,6 +143,17 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
141
143
  await self.comm.set_state(IRunning, RunningState(running=self._running))
142
144
  await self._publish_robotic_state()
143
145
 
146
+ async def _clear_current_task(self) -> None:
147
+ """Forget the current task and publish the state."""
148
+ self._task = None
149
+ self._project_priority = None
150
+ self._observation = None
151
+ self._task_target = None
152
+ self._obsnum = None
153
+ self._task_start = None
154
+ self._task_eta = None
155
+ await self._publish_robotic_state()
156
+
144
157
  async def _publish_robotic_state(self) -> None:
145
158
  """Publish IRobotic state: current task (from self._task/...), and self._next_observation
146
159
  / self._cant_run_reason as last updated by _run_thread."""
@@ -268,6 +281,7 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
268
281
  # ETA
269
282
  now = Time.now()
270
283
  eta = now + self._task.duration * u.second
284
+ window_end = observation.end # scheduled end, observation.end is overwritten below
271
285
  self._task_start = now
272
286
  self._task_eta = eta
273
287
 
@@ -282,31 +296,37 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
282
296
  await self._observation_archive.update_observation(observation)
283
297
  await self._publish_robotic_state()
284
298
 
285
- # run task in thread
299
+ # run task, abort if it exceeds its window by more than allowed_overrun
286
300
  log.info("Running task %s...", self._task.name)
301
+ deadline: float | None = None
302
+ if self._allowed_overrun is not None:
303
+ deadline = (window_end + self._allowed_overrun * u.second - Time.now()).to_value("second")
287
304
  try:
288
- await self._task_runner.run_task(self._task, self._task_target)
305
+ async with asyncio.timeout(deadline) as timeout:
306
+ await self._task_runner.run_task(self._task, self._task_target)
289
307
  except Exception as e:
308
+ if isinstance(e, TimeoutError) and timeout.expired():
309
+ log.warning(
310
+ "Task %s exceeded its window by more than %d s, aborted.",
311
+ self._task.name,
312
+ self._allowed_overrun,
313
+ )
314
+ state = ObservationState.ABORTED
290
315
  # a PyobsError is an expected/domain failure (e.g. acquisition out of tolerance) --
291
316
  # quiet INFO line, no traceback. Anything else is unexpected and needs a full
292
317
  # traceback to debug. e.log() also skips re-logging if some deeper layer (e.g. the
293
318
  # module's own execute()) already logged this same exception.
294
- if isinstance(e, exc.PyobsError):
295
- e.log(log, "INFO", f"Task {self._task.name} failed: {e}")
296
319
  else:
297
- log.exception("Task %s failed.", self._task.name)
320
+ if isinstance(e, exc.PyobsError):
321
+ e.log(log, "INFO", f"Task {self._task.name} failed: {e}")
322
+ else:
323
+ log.exception("Task %s failed.", self._task.name)
324
+ state = ObservationState.FAILED
298
325
  observation.end = Time.now()
299
- observation.state = ObservationState.FAILED
326
+ observation.state = state
300
327
  await self._observation_archive.update_observation(observation)
301
328
  await self.comm.send_event(TaskFailedEvent(name=self._task.name, id=self._task.id, obsnum=self._obsnum))
302
- self._task = None
303
- self._project_priority = None
304
- self._observation = None
305
- self._task_target = None
306
- self._obsnum = None
307
- self._task_start = None
308
- self._task_eta = None
309
- await self._publish_robotic_state()
329
+ await self._clear_current_task()
310
330
  continue
311
331
 
312
332
  # send event and change state
@@ -317,14 +337,7 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
317
337
 
318
338
  # finish
319
339
  log.info("Finished task %s.", self._task.name)
320
- self._task = None
321
- self._project_priority = None
322
- self._observation = None
323
- self._task_target = None
324
- self._obsnum = None
325
- self._task_start = None
326
- self._task_eta = None
327
- await self._publish_robotic_state()
340
+ await self._clear_current_task()
328
341
 
329
342
  # sleep?
330
343
  await asyncio.sleep(self._after_task_sleep)
@@ -122,7 +122,7 @@ class PointingSeries(Module, IAutonomous):
122
122
 
123
123
  return True
124
124
 
125
- except (ValueError, exc.RemoteError):
125
+ except (ValueError, exc.PyobsError):
126
126
  log.info("Could not acquire position.")
127
127
  return False
128
128