pyobs-core 2.0.0.dev28__tar.gz → 2.0.0.dev29__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 (445) hide show
  1. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/PKG-INFO +1 -1
  2. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/application.py +1 -1
  3. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/comm.py +15 -0
  4. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xmppclient.py +30 -0
  5. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xmppcomm.py +32 -0
  6. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/mixins/fitsnamespace.py +1 -1
  7. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/module.py +38 -3
  8. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/enums.py +2 -0
  9. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/exceptions.py +9 -0
  10. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyproject.toml +1 -1
  11. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/.gitignore +0 -0
  12. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/LICENSE +0 -0
  13. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/__init__.py +0 -0
  14. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/background_task.py +0 -0
  15. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/cli/__init__.py +0 -0
  16. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/cli/_cli.py +0 -0
  17. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/cli/pyobs.py +0 -0
  18. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/cli/pyobsd.py +0 -0
  19. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/cli/pyobsw.py +0 -0
  20. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/__init__.py +0 -0
  21. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/commlogging.py +0 -0
  22. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/dummy/__init__.py +0 -0
  23. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/dummy/dummycomm.py +0 -0
  24. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/local/__init__.py +0 -0
  25. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/local/localcomm.py +0 -0
  26. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/local/localnetwork.py +0 -0
  27. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/proxy.py +0 -0
  28. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/__init__.py +0 -0
  29. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/rpc.py +0 -0
  30. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/serializer.py +0 -0
  31. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
  32. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
  33. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
  34. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
  35. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
  36. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
  37. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
  38. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/__init__.py +0 -0
  39. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/badweather.py +0 -0
  40. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/event.py +0 -0
  41. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/exposurestatuschanged.py +0 -0
  42. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/filterchanged.py +0 -0
  43. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/focusfound.py +0 -0
  44. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/goodweather.py +0 -0
  45. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/log.py +0 -0
  46. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/modechanged.py +0 -0
  47. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/moduleclosed.py +0 -0
  48. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/moduleopened.py +0 -0
  49. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/motionstatuschanged.py +0 -0
  50. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/move.py +0 -0
  51. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/newimage.py +0 -0
  52. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/newspectrum.py +0 -0
  53. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/offsets.py +0 -0
  54. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/roofclosing.py +0 -0
  55. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/roofopened.py +0 -0
  56. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/taskfailed.py +0 -0
  57. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/taskfinished.py +0 -0
  58. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/taskstarted.py +0 -0
  59. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/events/testevent.py +0 -0
  60. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/__init__.py +0 -0
  61. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/image.py +0 -0
  62. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/__init__.py +0 -0
  63. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/altazoffsets.py +0 -0
  64. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/exptime.py +0 -0
  65. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/genericoffset.py +0 -0
  66. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/onskydistance.py +0 -0
  67. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/pixeloffsets.py +0 -0
  68. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/radecoffsets.py +0 -0
  69. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/skyoffsets.py +0 -0
  70. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processor.py +0 -0
  71. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/__init__.py +0 -0
  72. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/_daobackgroundremover.py +0 -0
  73. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/annotation/__init__.py +0 -0
  74. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/annotation/_pillow.py +0 -0
  75. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/annotation/circle.py +0 -0
  76. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/annotation/crosshair.py +0 -0
  77. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/annotation/text.py +0 -0
  78. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/__init__.py +0 -0
  79. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
  80. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
  81. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
  82. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
  83. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/astrometry.py +0 -0
  84. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/dotnet.py +0 -0
  85. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/calibration/__init__.py +0 -0
  86. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
  87. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
  88. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/calibration/calibration.py +0 -0
  89. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/__init__.py +0 -0
  90. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
  91. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/_source_catalog.py +0 -0
  92. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/daophot.py +0 -0
  93. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/pysep.py +0 -0
  94. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/simpledisk.py +0 -0
  95. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/sourcedetection.py +0 -0
  96. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/exptime/__init__.py +0 -0
  97. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/exptime/exptime.py +0 -0
  98. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/exptime/star.py +0 -0
  99. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/__init__.py +0 -0
  100. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/addfitsheaders.py +0 -0
  101. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/download.py +0 -0
  102. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/flip.py +0 -0
  103. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/grayscale.py +0 -0
  104. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/httpserver.py +0 -0
  105. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/normalize.py +0 -0
  106. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/save.py +0 -0
  107. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/saveimage.py +0 -0
  108. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/smooth.py +0 -0
  109. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/softbin.py +0 -0
  110. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/__init__.py +0 -0
  111. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/addmask.py +0 -0
  112. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
  113. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/circularmask.py +0 -0
  114. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/createfilename.py +0 -0
  115. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
  116. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/removebackground.py +0 -0
  117. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/modules/__init__.py +0 -0
  118. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/modules/getfitsheaders.py +0 -0
  119. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/__init__.py +0 -0
  120. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/astrometry.py +0 -0
  121. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/brighteststar.py +0 -0
  122. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
  123. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
  124. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
  125. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/fitsheader.py +0 -0
  126. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/offsets.py +0 -0
  127. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
  128. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/projected.py +0 -0
  129. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/spilled_light.py +0 -0
  130. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/__init__.py +0 -0
  131. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
  132. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
  133. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
  134. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
  135. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/photometry.py +0 -0
  136. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/photutil.py +0 -0
  137. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/pysep.py +0 -0
  138. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/wcs/__init__.py +0 -0
  139. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
  140. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IAbortable.py +0 -0
  141. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IAcquisition.py +0 -0
  142. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IAutoFocus.py +0 -0
  143. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IAutoGuiding.py +0 -0
  144. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IAutonomous.py +0 -0
  145. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IBinning.py +0 -0
  146. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ICalibrate.py +0 -0
  147. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ICamera.py +0 -0
  148. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IConfig.py +0 -0
  149. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ICooling.py +0 -0
  150. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IData.py +0 -0
  151. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IDataSequence.py +0 -0
  152. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IDome.py +0 -0
  153. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IExposure.py +0 -0
  154. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IExposureTime.py +0 -0
  155. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFilters.py +0 -0
  156. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
  157. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
  158. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFlatField.py +0 -0
  159. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFocusModel.py +0 -0
  160. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFocuser.py +0 -0
  161. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IGain.py +0 -0
  162. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IImageFormat.py +0 -0
  163. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IImageType.py +0 -0
  164. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IMode.py +0 -0
  165. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IModule.py +0 -0
  166. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IMotion.py +0 -0
  167. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IMultiFiber.py +0 -0
  168. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IOffsetsAltAz.py +0 -0
  169. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IOffsetsRaDec.py +0 -0
  170. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingAltAz.py +0 -0
  171. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingBody.py +0 -0
  172. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingHeliocentricPolar.py +0 -0
  173. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingHeliographicStonyhurst.py +0 -0
  174. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingHelioprojective.py +0 -0
  175. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingOrbitalElements.py +0 -0
  176. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingRaDec.py +0 -0
  177. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingSeries.py +0 -0
  178. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IReady.py +0 -0
  179. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IRoof.py +0 -0
  180. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IRotation.py +0 -0
  181. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IRunnable.py +0 -0
  182. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IRunning.py +0 -0
  183. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IScriptRunner.py +0 -0
  184. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ISpectrograph.py +0 -0
  185. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IStartStop.py +0 -0
  186. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IStructuredConfig.py +0 -0
  187. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ISyncTarget.py +0 -0
  188. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ITelescope.py +0 -0
  189. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ITemperatures.py +0 -0
  190. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ITrackingMode.py +0 -0
  191. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ITrackingRate.py +0 -0
  192. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IVideo.py +0 -0
  193. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IWeather.py +0 -0
  194. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IWindow.py +0 -0
  195. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/__init__.py +0 -0
  196. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/interface.py +0 -0
  197. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/mixins/__init__.py +0 -0
  198. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/mixins/camerasettings.py +0 -0
  199. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/mixins/fitsheader.py +0 -0
  200. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/mixins/follow.py +0 -0
  201. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/mixins/motionstatus.py +0 -0
  202. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/mixins/pipeline.py +0 -0
  203. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/mixins/waitformotion.py +0 -0
  204. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/mixins/weatheraware.py +0 -0
  205. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/__init__.py +0 -0
  206. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/__init__.py +0 -0
  207. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/adaptive.py +0 -0
  208. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/basecamera.py +0 -0
  209. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/basespectrograph.py +0 -0
  210. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/basevideo.py +0 -0
  211. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/dummycamera.py +0 -0
  212. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/dummyspectrograph.py +0 -0
  213. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/dummyvideo.py +0 -0
  214. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/pipelinecamera.py +0 -0
  215. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/flatfield/__init__.py +0 -0
  216. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/flatfield/flatfield.py +0 -0
  217. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/flatfield/pointing.py +0 -0
  218. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/flatfield/scheduler.py +0 -0
  219. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/focus/__init__.py +0 -0
  220. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/focus/dummyautofocus.py +0 -0
  221. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/focus/focusmodel.py +0 -0
  222. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/focus/focusseries.py +0 -0
  223. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/image/__init__.py +0 -0
  224. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/image/imagewatcher.py +0 -0
  225. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/image/imagewriter.py +0 -0
  226. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/image/pipeline.py +0 -0
  227. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/image/seeing.py +0 -0
  228. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/__init__.py +0 -0
  229. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/_base.py +0 -0
  230. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/_baseguiding.py +0 -0
  231. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/acquisition.py +0 -0
  232. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/autoguiding.py +0 -0
  233. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/dummyacquisition.py +0 -0
  234. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/dummyguiding.py +0 -0
  235. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
  236. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
  237. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
  238. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
  239. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
  240. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/scienceframeguiding.py +0 -0
  241. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/robotic/__init__.py +0 -0
  242. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/robotic/mastermind.py +0 -0
  243. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/robotic/pointing.py +0 -0
  244. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/robotic/scheduler.py +0 -0
  245. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/robotic/scriptrunner.py +0 -0
  246. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/roof/__init__.py +0 -0
  247. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/roof/basedome.py +0 -0
  248. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/roof/baseroof.py +0 -0
  249. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/roof/dummyroof.py +0 -0
  250. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/__init__.py +0 -0
  251. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/_dummytelescopebase.py +0 -0
  252. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/basetelescope.py +0 -0
  253. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/dummyaltaztelescope.py +0 -0
  254. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/dummyradectelescope.py +0 -0
  255. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/dummysolartelescope.py +0 -0
  256. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/test/__init__.py +0 -0
  257. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/test/standalone.py +0 -0
  258. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/__init__.py +0 -0
  259. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/dummymode.py +0 -0
  260. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/fluentlogger.py +0 -0
  261. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/httpfilecache.py +0 -0
  262. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/kiosk.py +0 -0
  263. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/matrix.py +0 -0
  264. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/stellarium.py +0 -0
  265. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/telegram.py +0 -0
  266. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/trigger.py +0 -0
  267. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/weather/__init__.py +0 -0
  268. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/weather/mockweather.py +0 -0
  269. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/weather/weather.py +0 -0
  270. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/weather/weather_api.py +0 -0
  271. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/modules/weather/weather_state.py +0 -0
  272. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/object.py +0 -0
  273. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/py.typed +0 -0
  274. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/__init__.py +0 -0
  275. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/observation.py +0 -0
  276. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/__init__.py +0 -0
  277. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
  278. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
  279. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
  280. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
  281. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +0 -0
  282. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +0 -0
  283. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +0 -0
  284. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
  285. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/dataprovider.py +0 -0
  286. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
  287. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
  288. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
  289. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/constant.py +0 -0
  290. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/follow.py +0 -0
  291. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/interval.py +0 -0
  292. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/merit.py +0 -0
  293. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
  294. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/random.py +0 -0
  295. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
  296. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/transit.py +0 -0
  297. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
  298. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/ondemandscheduler.py +0 -0
  299. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
  300. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
  301. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/heliocentricpolartarget.py +0 -0
  302. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/helioprojectivetarget.py +0 -0
  303. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
  304. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
  305. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
  306. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
  307. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/target.py +0 -0
  308. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
  309. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/__init__.py +0 -0
  310. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
  311. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/calibration/darkbias.py +0 -0
  312. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/calibration/pointing.py +0 -0
  313. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/calibration/skyflats.py +0 -0
  314. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/__init__.py +0 -0
  315. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/cases.py +0 -0
  316. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/conditional.py +0 -0
  317. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/parallel.py +0 -0
  318. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/selector.py +0 -0
  319. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/sequential.py +0 -0
  320. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/exceptions.py +0 -0
  321. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
  322. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/imaging/autofocus.py +0 -0
  323. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/imaging/imaging.py +0 -0
  324. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
  325. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/script.py +0 -0
  326. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/utils/__init__.py +0 -0
  327. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/utils/callmodule.py +0 -0
  328. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
  329. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/utils/log.py +0 -0
  330. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/__init__.py +0 -0
  331. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/backend/__init__.py +0 -0
  332. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/backend/observationarchive.py +0 -0
  333. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/backend/taskarchive.py +0 -0
  334. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
  335. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
  336. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
  337. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/__init__.py +0 -0
  338. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/_portal.py +0 -0
  339. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
  340. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
  341. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/configdb.py +0 -0
  342. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
  343. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
  344. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
  345. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/scripts/autofocus.py +0 -0
  346. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/scripts/default.py +0 -0
  347. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
  348. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/task.py +0 -0
  349. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
  350. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
  351. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/memory/__init__.py +0 -0
  352. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
  353. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
  354. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/observationarchive.py +0 -0
  355. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/taskarchive.py +0 -0
  356. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/task.py +0 -0
  357. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/taskrunner.py +0 -0
  358. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/__init__.py +0 -0
  359. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/archive/__init__.py +0 -0
  360. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/archive/archive.py +0 -0
  361. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/archive/local_archive.py +0 -0
  362. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
  363. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/exptime/__init__.py +0 -0
  364. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/exptime/exptime.py +0 -0
  365. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/exptime/stellarexptime.py +0 -0
  366. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
  367. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
  368. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/flatfielder.py +0 -0
  369. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
  370. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
  371. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
  372. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
  373. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
  374. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
  375. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
  376. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
  377. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/__init__.py +0 -0
  378. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/average.py +0 -0
  379. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/cache.py +0 -0
  380. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/config.py +0 -0
  381. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/config_schema.py +0 -0
  382. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/coordinates.py +0 -0
  383. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/curvefit.py +0 -0
  384. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/fits.py +0 -0
  385. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/focusseries/__init__.py +0 -0
  386. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/focusseries/base.py +0 -0
  387. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/focusseries/photometry.py +0 -0
  388. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/focusseries/projection.py +0 -0
  389. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/grids/__init__.py +0 -0
  390. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/grids/filters.py +0 -0
  391. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/grids/grid.py +0 -0
  392. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/grids/gridnode.py +0 -0
  393. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/grids/pipeline.py +0 -0
  394. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/__init__.py +0 -0
  395. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/__init__.py +0 -0
  396. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/binningwidget.py +0 -0
  397. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
  398. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/exposewidget.py +0 -0
  399. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
  400. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
  401. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
  402. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
  403. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/http.py +0 -0
  404. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/influxdb.py +0 -0
  405. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/logger.py +0 -0
  406. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/logging/__init__.py +0 -0
  407. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/logging/context.py +0 -0
  408. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/logging/resolvableerror.py +0 -0
  409. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/modulegui.py +0 -0
  410. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/offsets/__init__.py +0 -0
  411. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
  412. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/offsets/applyoffsets.py +0 -0
  413. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
  414. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/parallel.py +0 -0
  415. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/pipeline/__init__.py +0 -0
  416. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/pipeline/night.py +0 -0
  417. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/pipeline/pipeline.py +0 -0
  418. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/__init__.py +0 -0
  419. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/csv.py +0 -0
  420. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/http.py +0 -0
  421. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/log.py +0 -0
  422. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/multi.py +0 -0
  423. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/publisher.py +0 -0
  424. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/serialization.py +0 -0
  425. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/shellcommand.py +0 -0
  426. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/threads/__init__.py +0 -0
  427. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/threads/lockwithabort.py +0 -0
  428. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/time.py +0 -0
  429. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/utils/units.py +0 -0
  430. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/version.py +0 -0
  431. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/__init__.py +0 -0
  432. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/archivefile.py +0 -0
  433. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/bufferedfile.py +0 -0
  434. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/file.py +0 -0
  435. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/filelists/__init__.py +0 -0
  436. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/filelists/filelist.py +0 -0
  437. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/filelists/testing.py +0 -0
  438. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/httpfile.py +0 -0
  439. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/localfile.py +0 -0
  440. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/memfile.py +0 -0
  441. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/sftpfile.py +0 -0
  442. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/smbfile.py +0 -0
  443. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/sshfile.py +0 -0
  444. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/tempfile.py +0 -0
  445. {pyobs_core-2.0.0.dev28 → pyobs_core-2.0.0.dev29}/pyobs/vfs/vfs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyobs-core
3
- Version: 2.0.0.dev28
3
+ Version: 2.0.0.dev29
4
4
  Summary: robotic telescope software
5
5
  Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>
6
6
  License-Expression: MIT
@@ -224,7 +224,7 @@ class Application:
224
224
  try:
225
225
  # open module
226
226
  log.info("Opening module...")
227
- await self._module.open()
227
+ await self._module.startup()
228
228
  log.info("Started successfully.")
229
229
 
230
230
  # run module
@@ -530,6 +530,21 @@ class Comm:
530
530
  async def _set_presence(self, state: ModuleState, error_string: str = "") -> None:
531
531
  pass
532
532
 
533
+ async def mark_ready(self) -> None:
534
+ """Signal that the module has finished its own startup (reached ModuleState.READY) and is
535
+ safe for peers to discover.
536
+
537
+ Called by Module once it transitions to READY. Transports that announce a module to peers
538
+ independently of RPC dispatch (e.g. XmppComm's XMPP presence, which drives other modules'
539
+ peer-discovery reaction) hold that announcement back until this fires, so peers never read
540
+ capabilities that are still mid-publish. Transports without such an announcement (e.g.
541
+ LocalComm) don't need to override this.
542
+ """
543
+ await self._mark_ready()
544
+
545
+ async def _mark_ready(self) -> None:
546
+ pass
547
+
533
548
  def get_client_state(self, module: str) -> tuple[ModuleState, str] | None:
534
549
  """Return the last known presence state of a connected module.
535
550
 
@@ -34,6 +34,9 @@ class XmppClient(slixmpp.ClientXMPP):
34
34
  self._jid_conflict = False
35
35
  self._conflict_reason: str | None = None
36
36
 
37
+ # module startup gating -- see send_presence()/mark_ready() below
38
+ self._module_ready = False
39
+
37
40
  # auto-accept invitations
38
41
  self.auto_authorize = True
39
42
 
@@ -58,6 +61,33 @@ class XmppClient(slixmpp.ClientXMPP):
58
61
  self.add_event_handler("stream_error", self._stream_error)
59
62
  self.add_filter("in", self._filter_messages)
60
63
 
64
+ def send_presence(self, *args: Any, **kwargs: Any) -> Any:
65
+ """Override slixmpp's send_presence to hold back every presence broadcast -- the initial
66
+ online announcement (session_start) as well as re-broadcasts triggered by capability
67
+ updates (XmppComm._register_events) or lifecycle state changes (XmppComm._set_presence) --
68
+ until mark_ready() fires. This keeps the module invisible to peers' online-discovery
69
+ (_got_online/ModuleOpenedEvent) while it's still starting up, so peers never read
70
+ capabilities that are still mid-publish. Calls made before mark_ready() are simply dropped;
71
+ mark_ready() sends its own presence once, which is enough to announce the module (any
72
+ entity-capabilities hash update from a dropped call in the meantime is still picked up,
73
+ since update_caps() itself isn't gated).
74
+ """
75
+ if not self._module_ready:
76
+ return None
77
+ return super().send_presence(*args, **kwargs)
78
+
79
+ def mark_ready(self) -> None:
80
+ """Allow send_presence() to actually transmit from here on -- called either once the owning
81
+ Module first reaches ModuleState.READY (on the live, already-connected client: announce
82
+ immediately), or by XmppComm._connect() on a freshly created client for a reconnect after
83
+ the module was already READY (not connected yet -- session_start() will send presence as
84
+ soon as it fires, now that gating allows it). No-op if already marked ready."""
85
+ if self._module_ready:
86
+ return
87
+ self._module_ready = True
88
+ if self._connect_event.is_set():
89
+ self.send_presence()
90
+
61
91
  def reconnect(self, wait: int | float = 2.0, reason: str = "Reconnecting") -> Any:
62
92
  """Disconnect only, instead of slixmpp's default reconnect-in-place.
63
93
 
@@ -170,6 +170,12 @@ class XmppComm(Comm):
170
170
  self._xmpp: XmppClient | None = None
171
171
  self._rpc: RPC | None = None
172
172
 
173
+ # module readiness (see mark_ready()) -- lives here rather than solely on XmppClient
174
+ # because _connect() replaces self._xmpp with a brand-new instance on every reconnect,
175
+ # and a reconnect after the module is already READY must announce presence immediately
176
+ # rather than re-gating it
177
+ self._module_ready = False
178
+
173
179
  # pubsub for states
174
180
  self._pubsub_service = f"pubsub.{self._domain}"
175
181
  self._state_node_handlers: dict[str, tuple[type[Interface], list[Callable[[Any], None]]]] = {}
@@ -213,6 +219,18 @@ class XmppComm(Comm):
213
219
  # create client
214
220
  self._xmpp = XmppClient(self._jid, self._password)
215
221
 
222
+ # presence gating (see mark_ready()) only applies to a comm with an actual Module
223
+ # attached that hasn't finished starting yet -- a module-less XmppComm (a GUI, an
224
+ # admin tool, a bare observer in tests) has no such lifecycle and must announce
225
+ # itself immediately as before, or peers relying on presence-based discovery would
226
+ # never see it. Likewise, if the module already reached READY on a previous
227
+ # connection, tell the new client right away -- it isn't connected yet, so this
228
+ # doesn't send anything itself, but it means session_start() will announce presence
229
+ # immediately once (re)connected instead of holding it back as if this were the
230
+ # initial startup.
231
+ if self._module_ready or not self.has_module:
232
+ self._xmpp.mark_ready()
233
+
216
234
  # self._xmpp = slixmpp.ClientXMPP(self._jid, password)
217
235
  # Register directly with an XML mask rather than via pubsub_publish.
218
236
  # slixmpp's StanzaPath matcher requires plugins to be lazily loaded
@@ -957,6 +975,14 @@ class XmppComm(Comm):
957
975
  CLOSED → handled by normal disconnect (unavailable)
958
976
  error_string rides as <status> text when state is ERROR.
959
977
  """
978
+ # publishing any lifecycle state at all is itself a readiness signal -- covers direct
979
+ # set_presence() callers that don't go through Module.set_state() (see mark_ready()).
980
+ # Idempotent: unlocks send_presence() once, then this call's own send below goes through.
981
+ # Goes through self._mark_ready() (not just self.client.mark_ready()) so self._module_ready
982
+ # is set too -- otherwise a later reconnect (_connect() creates a brand-new XmppClient)
983
+ # would re-gate presence on the new client despite this module already being announced.
984
+ await self._mark_ready()
985
+
960
986
  _show_map: dict[ModuleState, str | None] = {
961
987
  ModuleState.READY: None,
962
988
  ModuleState.ERROR: "dnd",
@@ -966,6 +992,12 @@ class XmppComm(Comm):
966
992
  status = error_string if state == ModuleState.ERROR and error_string else None
967
993
  self.client.send_presence(pshow=show, pstatus=status)
968
994
 
995
+ async def _mark_ready(self) -> None:
996
+ """See Comm.mark_ready(). Remembers readiness on self (survives client recreation on
997
+ reconnect, see _connect()) and lets the live client announce presence now."""
998
+ self._module_ready = True
999
+ self.client.mark_ready()
1000
+
969
1001
  async def _subscribe_presence(self, module: str, callback: Callable[[ModuleState, str], None]) -> None:
970
1002
  self._presence_callbacks.setdefault(module, []).append(callback)
971
1003
  result = self._get_client_state(module)
@@ -17,7 +17,7 @@ class FitsNamespaceMixin:
17
17
  self.__namespaces = {} if fits_namespaces is None else fits_namespaces
18
18
 
19
19
  def _filter_fits_namespace(
20
- self, hdr: dict[str, FitsHeaderEntry], sender: str, namespaces: list[str] | None = None
20
+ self, hdr: dict[str, FitsHeaderEntry], sender: str, namespaces: list[str] | None = None, **kwargs: Any
21
21
  ) -> dict[str, FitsHeaderEntry]:
22
22
  """Filter FITS header keywords by given namespaces. If no namespaces are given, let all through. Always
23
23
  let keywords with this module's name as namespace pass.
@@ -148,8 +148,9 @@ class Module(Object, IModule, IConfig):
148
148
  self._device_name = self.comm.name
149
149
  self._label = label if label is not None else self._device_name
150
150
 
151
- # state
152
- self._state = ModuleState.READY
151
+ # state -- starts STARTING, moved to READY once Application finishes the full open() chain
152
+ # (see Module.execute()'s guard and Application._main)
153
+ self._state = ModuleState.STARTING
153
154
  self._error_string = ""
154
155
 
155
156
  # own?
@@ -175,6 +176,12 @@ class Module(Object, IModule, IConfig):
175
176
  # per-type logging contract a module author gets to opt out of.
176
177
  _UNSUPPRESSIBLE: tuple[type[exc.PyobsError], ...] = (exc.ModuleError, exc.UnclassifiedError)
177
178
 
179
+ # methods still callable while the module is ModuleState.STARTING -- introspection/recovery
180
+ # only, nothing that touches a device that may not be initialized yet. get_version/get_label
181
+ # are deliberately not listed: they aren't declared on IModule, so they never appear in
182
+ # self._methods and can't be called via execute() at all, in any state.
183
+ _STARTING_WHITELIST: tuple[str, ...] = ("get_permitted_methods", "reset_error")
184
+
178
185
  def _disable_exception_logging(self, *exceptions: type[exc.PyobsError]) -> None:
179
186
  """Declare that the given PyobsError types (and their subclasses) fire often enough that even the
180
187
  default quiet INFO line is too much, and should not be logged locally at all -- the caller already
@@ -320,6 +327,25 @@ class Module(Object, IModule, IConfig):
320
327
  ConfigCapabilities(caps=self._config_caps),
321
328
  )
322
329
 
330
+ async def startup(self) -> None:
331
+ """Open the module and mark it ready for RPC dispatch.
332
+
333
+ Runs the full open() override chain (base Module setup plus every subclass's own
334
+ setup) and only then transitions ModuleState.STARTING -> READY, so Module.execute()
335
+ starts accepting non-whitelisted calls exactly once startup has actually finished.
336
+ Every caller that opens a module standalone (Application, MultiModule) should call
337
+ this instead of open() directly -- otherwise the module stays in STARTING forever.
338
+ Callers that need finer-grained control (e.g. tests exercising STARTING behavior
339
+ directly) can call open() and set_state() separately instead.
340
+
341
+ Named startup() rather than start() because start() is already IStartStop's abstract
342
+ RPC method -- a plain start() here would be silently shadowed by any module
343
+ implementing that interface (guiding, mastermind, scheduler, weather, kiosk, ...),
344
+ which would then never leave STARTING under Application/MultiModule.
345
+ """
346
+ await self.open()
347
+ await self.set_state(ModuleState.READY)
348
+
323
349
  async def close(self) -> None:
324
350
  """Close module."""
325
351
  await Object.close(self)
@@ -539,6 +565,10 @@ class Module(Object, IModule, IConfig):
539
565
  KeyError: If method does not exist.
540
566
  """
541
567
 
568
+ # is module still starting up?
569
+ if self._state == ModuleState.STARTING and method not in self._STARTING_WHITELIST:
570
+ raise exc.ModuleStartingError("Module is still starting up, please try again shortly.")
571
+
542
572
  # is module in error state?
543
573
  if self._state == ModuleState.ERROR:
544
574
  # if called method is not from IModule, raise error
@@ -771,6 +801,11 @@ class Module(Object, IModule, IConfig):
771
801
  if self._comm is not None:
772
802
  await self._comm.set_presence(state, error_string if error_string is not None else self._error_string)
773
803
 
804
+ # first time reaching READY, tell the transport it may now announce this module to
805
+ # peers -- e.g. XmppComm delays its initial XMPP presence until here, see mark_ready()
806
+ if state == ModuleState.READY:
807
+ await self._comm.mark_ready()
808
+
774
809
  async def get_state(self, **kwargs: Any) -> ModuleState: # type: ignore[override]
775
810
  """Returns current state of module."""
776
811
  return self._state
@@ -917,7 +952,7 @@ class MultiModule(Module):
917
952
 
918
953
  _module_name_var.set(name)
919
954
  try:
920
- await mod.open()
955
+ await mod.startup()
921
956
  await mod.main()
922
957
  except asyncio.CancelledError:
923
958
  pass
@@ -14,12 +14,14 @@ class ModuleState(StrEnum):
14
14
 
15
15
  Attributes:
16
16
  CLOSED: Module is closed.
17
+ STARTING: Module is starting up and not yet ready to accept commands.
17
18
  READY: Module is ready.
18
19
  ERROR: Module has an error.
19
20
  LOCAL: Module is in local mode and cannot be used remotely.
20
21
  """
21
22
 
22
23
  CLOSED = "closed"
24
+ STARTING = "starting"
23
25
  READY = "ready"
24
26
  ERROR = "error"
25
27
  LOCAL = "local"
@@ -122,6 +122,15 @@ class DeviceBusyError(PyobsError):
122
122
  pass
123
123
 
124
124
 
125
+ class ModuleStartingError(PyobsError):
126
+ """The module hasn't finished its own startup yet (still inside `open()`, e.g. connecting to
127
+ hardware) and isn't safe to command -- distinct from DeviceBusyError, which means the module is
128
+ fully up but its device is occupied with another operation. Back off and retry once the module
129
+ reports ModuleState.READY, rather than treating this as a domain failure."""
130
+
131
+ pass
132
+
133
+
125
134
  class NotSupportedError(PyobsError):
126
135
  """This module doesn't support the requested operation at all -- a capability the module only
127
136
  optionally implements (e.g. an alt/az-only telescope asked to move_radec) isn't available,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pyobs-core"
3
- version = "2.0.0.dev28"
3
+ version = "2.0.0.dev29"
4
4
  description = "robotic telescope software"
5
5
  authors = [{ name = "Tim-Oliver Husser", email = "thusser@uni-goettingen.de" }]
6
6
  requires-python = ">=3.11"