pyobs-core 2.0.0.dev52__tar.gz → 2.0.0.dev54__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 (448) hide show
  1. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/PKG-INFO +1 -1
  2. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/comm.py +11 -5
  3. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xmppcomm.py +22 -4
  4. pyobs_core-2.0.0.dev54/pyobs/images/processor.py +63 -0
  5. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/dotnet.py +34 -26
  6. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/pipeline.py +16 -2
  7. pyobs_core-2.0.0.dev54/pyobs/robotic/scheduler/_executor.py +28 -0
  8. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +1 -1
  9. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +3 -4
  10. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +2 -3
  11. pyobs_core-2.0.0.dev54/pyobs/robotic/scheduler/dataprovider.py +78 -0
  12. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/ondemandscheduler.py +6 -3
  13. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/vfs.py +15 -6
  14. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyproject.toml +1 -1
  15. pyobs_core-2.0.0.dev52/pyobs/images/processor.py +0 -28
  16. pyobs_core-2.0.0.dev52/pyobs/robotic/scheduler/dataprovider.py +0 -49
  17. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/.gitignore +0 -0
  18. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/LICENSE +0 -0
  19. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/__init__.py +0 -0
  20. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/application.py +0 -0
  21. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/background_task.py +0 -0
  22. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/cli/__init__.py +0 -0
  23. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/cli/_cli.py +0 -0
  24. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/cli/pyobs.py +0 -0
  25. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/cli/pyobsd.py +0 -0
  26. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/cli/pyobsw.py +0 -0
  27. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/__init__.py +0 -0
  28. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/commlogging.py +0 -0
  29. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/dummy/__init__.py +0 -0
  30. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/dummy/dummycomm.py +0 -0
  31. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/local/__init__.py +0 -0
  32. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/local/localcomm.py +0 -0
  33. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/local/localnetwork.py +0 -0
  34. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/proxy.py +0 -0
  35. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/__init__.py +0 -0
  36. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/rpc.py +0 -0
  37. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/serializer.py +0 -0
  38. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
  39. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
  40. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
  41. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
  42. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
  43. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
  44. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
  45. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xmppclient.py +0 -0
  46. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/__init__.py +0 -0
  47. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/badweather.py +0 -0
  48. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/event.py +0 -0
  49. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/exposurestatuschanged.py +0 -0
  50. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/filterchanged.py +0 -0
  51. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/focusfound.py +0 -0
  52. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/goodweather.py +0 -0
  53. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/log.py +0 -0
  54. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/modechanged.py +0 -0
  55. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/moduleclosed.py +0 -0
  56. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/moduleopened.py +0 -0
  57. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/motionstatuschanged.py +0 -0
  58. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/move.py +0 -0
  59. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/newimage.py +0 -0
  60. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/newspectrum.py +0 -0
  61. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/offsets.py +0 -0
  62. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/roofclosing.py +0 -0
  63. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/roofopened.py +0 -0
  64. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/taskfailed.py +0 -0
  65. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/taskfinished.py +0 -0
  66. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/taskstarted.py +0 -0
  67. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/testevent.py +0 -0
  68. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/__init__.py +0 -0
  69. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/image.py +0 -0
  70. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/__init__.py +0 -0
  71. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/altazoffsets.py +0 -0
  72. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/exptime.py +0 -0
  73. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/genericoffset.py +0 -0
  74. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/onskydistance.py +0 -0
  75. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/pixeloffsets.py +0 -0
  76. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/radecoffsets.py +0 -0
  77. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/skyoffsets.py +0 -0
  78. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/__init__.py +0 -0
  79. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/_daobackgroundremover.py +0 -0
  80. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/annotation/__init__.py +0 -0
  81. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/annotation/_pillow.py +0 -0
  82. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/annotation/circle.py +0 -0
  83. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/annotation/crosshair.py +0 -0
  84. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/annotation/text.py +0 -0
  85. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/__init__.py +0 -0
  86. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
  87. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
  88. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
  89. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
  90. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/astrometry.py +0 -0
  91. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/calibration/__init__.py +0 -0
  92. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
  93. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
  94. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/calibration/calibration.py +0 -0
  95. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/__init__.py +0 -0
  96. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
  97. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/_source_catalog.py +0 -0
  98. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/daophot.py +0 -0
  99. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/pysep.py +0 -0
  100. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/simpledisk.py +0 -0
  101. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/sourcedetection.py +0 -0
  102. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/exptime/__init__.py +0 -0
  103. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/exptime/exptime.py +0 -0
  104. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/exptime/star.py +0 -0
  105. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/__init__.py +0 -0
  106. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/addfitsheaders.py +0 -0
  107. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/download.py +0 -0
  108. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/flip.py +0 -0
  109. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/grayscale.py +0 -0
  110. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/httpserver.py +0 -0
  111. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/normalize.py +0 -0
  112. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/save.py +0 -0
  113. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/saveimage.py +0 -0
  114. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/smooth.py +0 -0
  115. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/softbin.py +0 -0
  116. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/__init__.py +0 -0
  117. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/addmask.py +0 -0
  118. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
  119. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/circularmask.py +0 -0
  120. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/createfilename.py +0 -0
  121. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
  122. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/removebackground.py +0 -0
  123. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/modules/__init__.py +0 -0
  124. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/modules/getfitsheaders.py +0 -0
  125. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/__init__.py +0 -0
  126. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/astrometry.py +0 -0
  127. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/brighteststar.py +0 -0
  128. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
  129. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
  130. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
  131. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/fitsheader.py +0 -0
  132. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/offsets.py +0 -0
  133. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
  134. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/projected.py +0 -0
  135. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/spilled_light.py +0 -0
  136. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/__init__.py +0 -0
  137. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
  138. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
  139. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
  140. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
  141. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/photometry.py +0 -0
  142. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/photutil.py +0 -0
  143. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/pysep.py +0 -0
  144. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/wcs/__init__.py +0 -0
  145. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
  146. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IAbortable.py +0 -0
  147. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IAcquisition.py +0 -0
  148. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IAutoFocus.py +0 -0
  149. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IAutoGuiding.py +0 -0
  150. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IAutonomous.py +0 -0
  151. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IBinning.py +0 -0
  152. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ICalibrate.py +0 -0
  153. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ICamera.py +0 -0
  154. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IConfig.py +0 -0
  155. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ICooling.py +0 -0
  156. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IData.py +0 -0
  157. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IDataSequence.py +0 -0
  158. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IDome.py +0 -0
  159. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IExposure.py +0 -0
  160. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IExposureTime.py +0 -0
  161. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFilters.py +0 -0
  162. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
  163. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
  164. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFlatField.py +0 -0
  165. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFocusModel.py +0 -0
  166. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFocuser.py +0 -0
  167. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IGain.py +0 -0
  168. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IImageFormat.py +0 -0
  169. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IImageType.py +0 -0
  170. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IMode.py +0 -0
  171. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IModule.py +0 -0
  172. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IMotion.py +0 -0
  173. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IMultiFiber.py +0 -0
  174. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IOffsetsAltAz.py +0 -0
  175. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IOffsetsRaDec.py +0 -0
  176. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingAltAz.py +0 -0
  177. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingBody.py +0 -0
  178. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingHeliocentricPolar.py +0 -0
  179. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingHeliographicStonyhurst.py +0 -0
  180. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingHelioprojective.py +0 -0
  181. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingOrbitalElements.py +0 -0
  182. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingRaDec.py +0 -0
  183. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingSeries.py +0 -0
  184. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IReady.py +0 -0
  185. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IRoof.py +0 -0
  186. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IRotation.py +0 -0
  187. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IRunnable.py +0 -0
  188. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IRunning.py +0 -0
  189. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IScriptRunner.py +0 -0
  190. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ISpectrograph.py +0 -0
  191. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IStartStop.py +0 -0
  192. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IStructuredConfig.py +0 -0
  193. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ISyncTarget.py +0 -0
  194. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ITelescope.py +0 -0
  195. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ITemperatures.py +0 -0
  196. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ITrackingMode.py +0 -0
  197. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ITrackingRate.py +0 -0
  198. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IVideo.py +0 -0
  199. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IWeather.py +0 -0
  200. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IWindow.py +0 -0
  201. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/__init__.py +0 -0
  202. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/interface.py +0 -0
  203. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/__init__.py +0 -0
  204. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/camerasettings.py +0 -0
  205. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/fitsheader.py +0 -0
  206. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/fitsnamespace.py +0 -0
  207. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/follow.py +0 -0
  208. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/motionstatus.py +0 -0
  209. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/waitformotion.py +0 -0
  210. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/weatheraware.py +0 -0
  211. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/__init__.py +0 -0
  212. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/__init__.py +0 -0
  213. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/adaptive.py +0 -0
  214. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/basecamera.py +0 -0
  215. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/basespectrograph.py +0 -0
  216. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/basevideo.py +0 -0
  217. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/dummycamera.py +0 -0
  218. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/dummyspectrograph.py +0 -0
  219. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/dummyvideo.py +0 -0
  220. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/pipelinecamera.py +0 -0
  221. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/flatfield/__init__.py +0 -0
  222. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/flatfield/flatfield.py +0 -0
  223. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/flatfield/pointing.py +0 -0
  224. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/flatfield/scheduler.py +0 -0
  225. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/focus/__init__.py +0 -0
  226. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/focus/dummyautofocus.py +0 -0
  227. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/focus/focusmodel.py +0 -0
  228. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/focus/focusseries.py +0 -0
  229. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/image/__init__.py +0 -0
  230. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/image/imagewatcher.py +0 -0
  231. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/image/imagewriter.py +0 -0
  232. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/image/pipeline.py +0 -0
  233. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/image/seeing.py +0 -0
  234. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/module.py +0 -0
  235. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/__init__.py +0 -0
  236. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/_base.py +0 -0
  237. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/_baseguiding.py +0 -0
  238. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/acquisition.py +0 -0
  239. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/autoguiding.py +0 -0
  240. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/dummyacquisition.py +0 -0
  241. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/dummyguiding.py +0 -0
  242. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
  243. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
  244. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
  245. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
  246. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
  247. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/scienceframeguiding.py +0 -0
  248. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/robotic/__init__.py +0 -0
  249. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/robotic/mastermind.py +0 -0
  250. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/robotic/pointing.py +0 -0
  251. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/robotic/scheduler.py +0 -0
  252. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/robotic/scriptrunner.py +0 -0
  253. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/roof/__init__.py +0 -0
  254. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/roof/basedome.py +0 -0
  255. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/roof/baseroof.py +0 -0
  256. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/roof/dummyroof.py +0 -0
  257. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/__init__.py +0 -0
  258. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/_dummytelescopebase.py +0 -0
  259. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/basetelescope.py +0 -0
  260. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/dummyaltaztelescope.py +0 -0
  261. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/dummyradectelescope.py +0 -0
  262. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/dummysolartelescope.py +0 -0
  263. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/test/__init__.py +0 -0
  264. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/test/standalone.py +0 -0
  265. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/__init__.py +0 -0
  266. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/dummymode.py +0 -0
  267. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/fluentlogger.py +0 -0
  268. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/httpfilecache.py +0 -0
  269. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/kiosk.py +0 -0
  270. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/matrix.py +0 -0
  271. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/stellarium.py +0 -0
  272. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/telegram.py +0 -0
  273. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/trigger.py +0 -0
  274. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/weather/__init__.py +0 -0
  275. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/weather/mockweather.py +0 -0
  276. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/weather/weather.py +0 -0
  277. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/weather/weather_api.py +0 -0
  278. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/weather/weather_state.py +0 -0
  279. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/object.py +0 -0
  280. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/py.typed +0 -0
  281. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/__init__.py +0 -0
  282. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/observation.py +0 -0
  283. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/__init__.py +0 -0
  284. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
  285. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
  286. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
  287. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
  288. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
  289. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
  290. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
  291. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
  292. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/constant.py +0 -0
  293. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/follow.py +0 -0
  294. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/interval.py +0 -0
  295. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/merit.py +0 -0
  296. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
  297. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/random.py +0 -0
  298. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
  299. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/transit.py +0 -0
  300. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
  301. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
  302. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
  303. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/heliocentricpolartarget.py +0 -0
  304. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/helioprojectivetarget.py +0 -0
  305. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
  306. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
  307. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
  308. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
  309. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/target.py +0 -0
  310. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
  311. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/__init__.py +0 -0
  312. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
  313. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/calibration/darkbias.py +0 -0
  314. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/calibration/pointing.py +0 -0
  315. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/calibration/skyflats.py +0 -0
  316. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/__init__.py +0 -0
  317. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/cases.py +0 -0
  318. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/conditional.py +0 -0
  319. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/parallel.py +0 -0
  320. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/selector.py +0 -0
  321. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/sequential.py +0 -0
  322. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/exceptions.py +0 -0
  323. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
  324. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/imaging/autofocus.py +0 -0
  325. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/imaging/imaging.py +0 -0
  326. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
  327. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/script.py +0 -0
  328. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/utils/__init__.py +0 -0
  329. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/utils/callmodule.py +0 -0
  330. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
  331. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/utils/log.py +0 -0
  332. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/__init__.py +0 -0
  333. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/backend/__init__.py +0 -0
  334. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/backend/observationarchive.py +0 -0
  335. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/backend/taskarchive.py +0 -0
  336. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
  337. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
  338. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
  339. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/__init__.py +0 -0
  340. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/_portal.py +0 -0
  341. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
  342. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
  343. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/configdb.py +0 -0
  344. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
  345. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
  346. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
  347. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/scripts/autofocus.py +0 -0
  348. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/scripts/default.py +0 -0
  349. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
  350. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/task.py +0 -0
  351. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
  352. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
  353. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/memory/__init__.py +0 -0
  354. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
  355. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
  356. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/observationarchive.py +0 -0
  357. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/taskarchive.py +0 -0
  358. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/task.py +0 -0
  359. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/taskrunner.py +0 -0
  360. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/__init__.py +0 -0
  361. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/archive/__init__.py +0 -0
  362. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/archive/archive.py +0 -0
  363. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/archive/local_archive.py +0 -0
  364. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
  365. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/exptime/__init__.py +0 -0
  366. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/exptime/exptime.py +0 -0
  367. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/exptime/stellarexptime.py +0 -0
  368. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
  369. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
  370. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/flatfielder.py +0 -0
  371. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
  372. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
  373. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
  374. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
  375. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
  376. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
  377. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
  378. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
  379. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/__init__.py +0 -0
  380. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/average.py +0 -0
  381. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/cache.py +0 -0
  382. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/config.py +0 -0
  383. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/config_schema.py +0 -0
  384. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/coordinates.py +0 -0
  385. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/curvefit.py +0 -0
  386. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/enums.py +0 -0
  387. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/exceptions.py +0 -0
  388. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/fits.py +0 -0
  389. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/focusseries/__init__.py +0 -0
  390. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/focusseries/base.py +0 -0
  391. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/focusseries/photometry.py +0 -0
  392. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/focusseries/projection.py +0 -0
  393. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/grids/__init__.py +0 -0
  394. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/grids/filters.py +0 -0
  395. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/grids/grid.py +0 -0
  396. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/grids/gridnode.py +0 -0
  397. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/grids/pipeline.py +0 -0
  398. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/__init__.py +0 -0
  399. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/__init__.py +0 -0
  400. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/binningwidget.py +0 -0
  401. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
  402. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/exposewidget.py +0 -0
  403. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
  404. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
  405. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
  406. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
  407. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/http.py +0 -0
  408. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/influxdb.py +0 -0
  409. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/logger.py +0 -0
  410. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/logging/__init__.py +0 -0
  411. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/logging/context.py +0 -0
  412. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/logging/resolvableerror.py +0 -0
  413. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/modulegui.py +0 -0
  414. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/offsets/__init__.py +0 -0
  415. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
  416. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/offsets/applyoffsets.py +0 -0
  417. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
  418. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/parallel.py +0 -0
  419. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/pipeline/__init__.py +0 -0
  420. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/pipeline/night.py +0 -0
  421. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/pipeline/pipeline.py +0 -0
  422. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/__init__.py +0 -0
  423. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/csv.py +0 -0
  424. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/http.py +0 -0
  425. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/log.py +0 -0
  426. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/multi.py +0 -0
  427. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/publisher.py +0 -0
  428. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/serialization.py +0 -0
  429. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/shellcommand.py +0 -0
  430. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/threads/__init__.py +0 -0
  431. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/threads/lockwithabort.py +0 -0
  432. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/time.py +0 -0
  433. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/units.py +0 -0
  434. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/version.py +0 -0
  435. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/__init__.py +0 -0
  436. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/archivefile.py +0 -0
  437. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/bufferedfile.py +0 -0
  438. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/file.py +0 -0
  439. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/filelists/__init__.py +0 -0
  440. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/filelists/filelist.py +0 -0
  441. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/filelists/testing.py +0 -0
  442. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/httpfile.py +0 -0
  443. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/localfile.py +0 -0
  444. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/memfile.py +0 -0
  445. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/sftpfile.py +0 -0
  446. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/smbfile.py +0 -0
  447. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/sshfile.py +0 -0
  448. {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/tempfile.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyobs-core
3
- Version: 2.0.0.dev52
3
+ Version: 2.0.0.dev54
4
4
  Summary: robotic telescope software
5
5
  Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>
6
6
  License-Expression: MIT
@@ -39,7 +39,8 @@ class Comm:
39
39
  self._log_queue: asyncio.Queue[LogEvent] = asyncio.Queue()
40
40
  self._logging_task: asyncio.Task[Any] | None = None
41
41
  self._event_handlers: dict[type[Event], list[Callable[[Event, str], Coroutine[Any, Any, bool]]]] = {}
42
- self._registered_events: set[type[Event]] = set()
42
+ self._events_sent: set[type[Event]] = set()
43
+ self._events_subscribed: set[type[Event]] = set()
43
44
  self._closing = asyncio.Event()
44
45
  self._published_state: set[type[Interface]] = set()
45
46
 
@@ -434,10 +435,10 @@ class Comm:
434
435
 
435
436
  # we also want to register all events derived from the given one
436
437
  event_classes = self._get_derived_events(event_class)
437
- self._registered_events.update(event_classes)
438
438
 
439
- # do we have a handler?
439
+ # do we have a handler? then we subscribe, otherwise we just declare that we send it
440
440
  if handler:
441
+ self._events_subscribed.update(event_classes)
441
442
  # loop classes
442
443
  for ev in event_classes:
443
444
  # initialize list
@@ -447,6 +448,8 @@ class Comm:
447
448
  if handler not in self._event_handlers[ev]:
448
449
  # add handler
449
450
  self._event_handlers[ev].append(handler)
451
+ else:
452
+ self._events_sent.update(event_classes)
450
453
 
451
454
  # if event is not a local one, we also need to do some XMPP stuff
452
455
  if not event_class.local:
@@ -457,8 +460,9 @@ class Comm:
457
460
  ) -> None:
458
461
  """Remove a handler previously added via register_event().
459
462
 
460
- Leaves the event type itself registered (other handlers may still be interested in it,
461
- and the module may still want to advertise/receive it), only stops calling this handler.
463
+ Leaves the event type itself registered as *sent* if the module also declared it via a
464
+ handler-less register_event() call, only stops calling this handler and, once no handler
465
+ is left for the event, drops it from what's advertised as *subscribed*.
462
466
 
463
467
  Args:
464
468
  event_class: Class of event that was registered.
@@ -470,6 +474,8 @@ class Comm:
470
474
  handlers = self._event_handlers.get(ev)
471
475
  if handlers is not None and handler in handlers:
472
476
  handlers.remove(handler)
477
+ if not handlers:
478
+ self._events_subscribed.discard(ev)
473
479
 
474
480
  async def _register_events(
475
481
  self, events: list[type[Event]], handler: Callable[[Event, str], Coroutine[Any, Any, bool]] | None = None
@@ -37,6 +37,18 @@ if TYPE_CHECKING:
37
37
  log = logging.getLogger(__name__)
38
38
 
39
39
 
40
+ def _event_role(ev_cls: type[Event], events_sent: set[type[Event]], events_subscribed: set[type[Event]]) -> str:
41
+ """Space-separated role(s) ("send", "subscribe", or both) for an event class, for the
42
+ disco#info `role` attribute -- lets consumers with no access to the pyobs.events catalog
43
+ (e.g. pyobs-web-client) tell producers from consumers instead of guessing from the union."""
44
+ roles = []
45
+ if ev_cls in events_sent:
46
+ roles.append("send")
47
+ if ev_cls in events_subscribed:
48
+ roles.append("subscribe")
49
+ return " ".join(roles)
50
+
51
+
40
52
  def _retry_delay(attempt: int, cap: float = 30.0, base: float = 1.0) -> float:
41
53
  """Capped exponential backoff with full jitter.
42
54
 
@@ -984,10 +996,16 @@ class XmppComm(Comm):
984
996
  for interface in self._module.interfaces:
985
997
  info.xml.append(_interface_schema_to_xml(interface))
986
998
 
987
- # Append event schemas
988
- for ev_cls in sorted(self._registered_events, key=lambda e: e.__name__):
989
- if not ev_cls.local:
990
- info.xml.append(_event_schema_to_xml(ev_cls))
999
+ # Append event schemas, tagged with a role attribute so consumers that have no access
1000
+ # to the pyobs.events catalog themselves (e.g. pyobs-web-client) can tell which events
1001
+ # a module actually sends vs. which it only subscribes to receive.
1002
+ registered_events = self._events_sent | self._events_subscribed
1003
+ for ev_cls in sorted(registered_events, key=lambda e: e.__name__):
1004
+ if ev_cls.local:
1005
+ continue
1006
+ event_xml = _event_schema_to_xml(ev_cls)
1007
+ event_xml.attrib["role"] = _event_role(ev_cls, self._events_sent, self._events_subscribed)
1008
+ info.xml.append(event_xml)
991
1009
 
992
1010
  return info
993
1011
 
@@ -0,0 +1,63 @@
1
+ from abc import ABCMeta, abstractmethod
2
+ from typing import Any
3
+
4
+ from pyobs.images import Image
5
+ from pyobs.object import Object
6
+ from pyobs.utils.exceptions import ImageError
7
+
8
+
9
+ class ImageProcessor(Object, metaclass=ABCMeta):
10
+ VALID_ERROR_MODES = frozenset(("raise", "error", "info", "ignore"))
11
+
12
+ def __init__(self, on_error: str = "raise", **kwargs: Any):
13
+ """Init new image processor.
14
+
15
+ Args:
16
+ on_error: How the pipeline should handle an ImageError raised by this step. One of:
17
+ - "raise" (default): re-raise the exception, aborting the pipeline.
18
+ - "error": call handle_error(), pass its return value downstream.
19
+ - "info": log at INFO level, pass the pre-step image downstream unmodified.
20
+ - "ignore": silently pass the pre-step image downstream unmodified.
21
+ """
22
+ Object.__init__(self, **kwargs)
23
+
24
+ self._on_error = on_error
25
+ if self._on_error not in self.VALID_ERROR_MODES:
26
+ raise ValueError(f"on_error must be one of {sorted(self.VALID_ERROR_MODES)}, got {self._on_error!r}.")
27
+
28
+ @property
29
+ def on_error(self) -> str:
30
+ """The error handling mode for this step."""
31
+ return self._on_error
32
+
33
+ @abstractmethod
34
+ async def __call__(self, image: Image) -> Image:
35
+ """Processes an image.
36
+
37
+ Args:
38
+ image: Image to process.
39
+
40
+ Returns:
41
+ Processed image.
42
+ """
43
+
44
+ def handle_error(self, image: Image, error: ImageError) -> Image:
45
+ """Handle an ImageError raised by this step, when on_error == "error".
46
+
47
+ Override this to customize error handling (e.g. tag the image with a FITS header).
48
+ The default implementation re-raises the error.
49
+
50
+ Args:
51
+ image: The image that caused the error.
52
+ error: The ImageError that was raised.
53
+
54
+ Returns:
55
+ The image to pass to the next pipeline step.
56
+ """
57
+ raise error
58
+
59
+ async def reset(self) -> None:
60
+ """Resets state of image processor"""
61
+
62
+
63
+ __all__ = ["ImageProcessor"]
@@ -31,11 +31,15 @@ class AstrometryDotNet(Astrometry):
31
31
  (commonly degrees for astrometry.net). Default: ``3.0``.
32
32
  :param int timeout: Timeout in seconds for the network call to the astrometry
33
33
  web service. Default: ``10``.
34
- :param bool exceptions: Whether to raise exceptions on failure. If ``True``,
35
- processing errors are raised (typically as
36
- :class:`pyobs.images.exceptions.ImageError`). If ``False``,
37
- errors are handled by marking the image header and returning
38
- the original image. Default: ``True``.
34
+ :param bool exceptions: Deprecated, use ``on_error`` instead. ``exceptions=False`` is
35
+ equivalent to ``on_error="error"``; ``exceptions=True`` (the
36
+ default) is equivalent to ``on_error="raise"``.
37
+ :param str on_error: How the pipeline should handle a failed solve: ``"raise"`` (default,
38
+ abort the pipeline), ``"error"`` (mark ``WCSERR=1`` in the header, log
39
+ a warning, and pass the image through -- see ``handle_error``),
40
+ ``"info"``, or ``"ignore"``. Only takes effect when this processor
41
+ runs as a step in a ``PipelineMixin`` pipeline; a direct call always
42
+ raises on failure.
39
43
  :param kwargs: Additional keyword arguments forwarded to
40
44
  :class:`pyobs.images.processors.astrometry.Astrometry`.
41
45
 
@@ -48,11 +52,9 @@ class AstrometryDotNet(Astrometry):
48
52
  - On success, receives solver output and writes the resulting WCS into a copy of
49
53
  the input image using :class:`pyobs.images.processors.astrometry._ResponseImageWriter`.
50
54
  - Logs the outcome, including WCS information, and returns the result image.
51
- - On failure:
52
-
53
- - If ``exceptions=True``, raises the underlying :class:`pyobs.images.exceptions.ImageError`.
54
- - If ``exceptions=False``, sets ``WCSERR=1`` in the FITS header, logs a warning, and returns the original
55
- image unchanged.
55
+ - On failure, raises the underlying :class:`pyobs.images.exceptions.ImageError`. When run as
56
+ a pipeline step with ``on_error="error"``, the pipeline calls ``handle_error``, which sets
57
+ ``WCSERR=1`` in the FITS header, logs a warning, and returns the original image unchanged.
56
58
 
57
59
  Input/Output
58
60
  ------------
@@ -69,20 +71,20 @@ class AstrometryDotNet(Astrometry):
69
71
  class: pyobs.images.processors.astrometry.AstrometryDotNet
70
72
  url: "http://localhost:8080/api"
71
73
 
72
- Handle failures without raising exceptions:
74
+ Handle failures without aborting the pipeline:
73
75
 
74
76
  .. code-block:: yaml
75
77
 
76
78
  class: pyobs.images.processors.astrometry.AstrometryDotNet
77
79
  url: "http://localhost:8080/api"
78
- exceptions: false
80
+ on_error: error
79
81
 
80
82
  Notes
81
83
  -----
82
84
  - The ``_DotNetRequestBuilder`` determines how sources are extracted and how the
83
85
  request is formed (including any unit conventions for ``radius``). Consult its
84
86
  documentation for details.
85
- - ``WCSERR`` is used as a failure marker in the FITS header when ``exceptions=False``.
87
+ - ``WCSERR`` is used as a failure marker in the FITS header when ``handle_error`` runs.
86
88
  """
87
89
 
88
90
  __module__ = "pyobs.images.processors.astrometry"
@@ -93,7 +95,8 @@ class AstrometryDotNet(Astrometry):
93
95
  source_count: int = 50,
94
96
  radius: float = 3.0,
95
97
  timeout: int = 10,
96
- exceptions: bool = True,
98
+ exceptions: bool | None = None,
99
+ on_error: str = "raise",
97
100
  **kwargs: Any,
98
101
  ):
99
102
  """Init new astronomy.net processor.
@@ -103,17 +106,28 @@ class AstrometryDotNet(Astrometry):
103
106
  source_count: Number of sources to send.
104
107
  radius: Radius to search in.
105
108
  timeout: Timeout in seconds for call to astrometry web service.
106
- exceptions: Whether to raise Exceptions.
109
+ exceptions: Deprecated, use on_error instead. Whether to raise Exceptions.
110
+ on_error: How to handle a failed solve. One of "raise", "error", "info", "ignore".
111
+ On "error", handle_error() marks the image with WCSERR=1 and logs a warning.
107
112
  """
108
- Astrometry.__init__(self, **kwargs)
113
+ Astrometry.__init__(self, on_error=on_error, **kwargs)
109
114
 
110
115
  self.url = url
111
116
 
112
117
  self.timeout = timeout
113
- self.exceptions = exceptions
118
+
119
+ # backwards compat: if 'exceptions' is set but 'on_error' is left at its default,
120
+ # derive on_error from it.
121
+ if exceptions is not None and on_error == "raise":
122
+ self._on_error = "raise" if exceptions else "error"
114
123
 
115
124
  self._request_builder = _DotNetRequestBuilder(source_count, radius)
116
125
 
126
+ @property
127
+ def exceptions(self) -> bool:
128
+ """Deprecated, use on_error instead."""
129
+ return self.on_error != "error"
130
+
117
131
  async def _process(self, image: Image) -> Image:
118
132
  # build the request
119
133
  request = self._request_builder(image)
@@ -132,10 +146,7 @@ class AstrometryDotNet(Astrometry):
132
146
 
133
147
  return result_image
134
148
 
135
- def _handle_error(self, image: Image, error: exc.ImageError) -> Image:
136
- if self.exceptions:
137
- raise error
138
-
149
+ def handle_error(self, image: Image, error: exc.ImageError) -> Image:
139
150
  image.header["WCSERR"] = 1
140
151
 
141
152
  log.warning(error.message)
@@ -145,16 +156,13 @@ class AstrometryDotNet(Astrometry):
145
156
  async def __call__(self, image: Image) -> Image:
146
157
  """Find astrometric solution on given image.
147
158
 
148
- Writes WCSERR=1 into FITS header on failure.
159
+ Writes WCSERR=1 into FITS header on failure (see handle_error).
149
160
 
150
161
  Args:
151
162
  image: Image to analyse.
152
163
  """
153
164
 
154
- try:
155
- return await self._process(image)
156
- except exc.ImageError as e:
157
- return self._handle_error(image, e)
165
+ return await self._process(image)
158
166
 
159
167
 
160
168
  __all__ = ["AstrometryDotNet"]
@@ -5,6 +5,7 @@ from typing import Any
5
5
 
6
6
  from pyobs.images import Image, ImageProcessor
7
7
  from pyobs.object import Object
8
+ from pyobs.utils.exceptions import ImageError
8
9
 
9
10
  log = logging.getLogger(__name__)
10
11
 
@@ -37,6 +38,10 @@ class PipelineMixin:
37
38
  async def run_pipeline(self, image: Image) -> Image:
38
39
  """Run the pipeline on the given image.
39
40
 
41
+ Each step is run, and an ImageError it raises is handled according to the step's
42
+ on_error setting (default "raise"): re-raised, dispatched to the step's handle_error(),
43
+ logged, or ignored. Non-ImageError exceptions always propagate.
44
+
40
45
  Args:
41
46
  image: Image to run pipeline on.
42
47
 
@@ -44,9 +49,18 @@ class PipelineMixin:
44
49
  Image after pipeline run.
45
50
  """
46
51
 
47
- # loop steps, just let any exception pass
48
52
  for step in self.__pipeline_steps:
49
- image = await step(image)
53
+ try:
54
+ image = await step(image)
55
+ except ImageError as e:
56
+ if step.on_error == "raise":
57
+ raise
58
+ elif step.on_error == "error":
59
+ image = step.handle_error(image, e)
60
+ elif step.on_error == "info":
61
+ log.info("Step %s: %s", type(step).__name__, e)
62
+ elif step.on_error == "ignore":
63
+ pass
50
64
 
51
65
  # finished
52
66
  return image
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from collections.abc import Callable, Coroutine
5
+ from concurrent.futures import ThreadPoolExecutor
6
+ from typing import Any, TypeVar
7
+
8
+ _T = TypeVar("_T")
9
+
10
+ # single worker: evaluate_constraints_and_merits calls are always awaited sequentially by the
11
+ # caller (never fired concurrently), and DataProvider's functools.cache is not safe under real
12
+ # concurrent access -- one worker keeps that access serialized while still freeing the main loop.
13
+ _executor = ThreadPoolExecutor(max_workers=1, thread_name_prefix="pyobs-scheduler")
14
+
15
+
16
+ async def run_cpu_bound(coro_fn: Callable[..., Coroutine[Any, Any, _T]], *args: object) -> _T:
17
+ """Runs an async callable to completion on a dedicated worker thread, off the caller's loop.
18
+
19
+ Args:
20
+ coro_fn: An async callable whose body does not itself need to run on the caller's
21
+ event loop (no dependency on the caller's other tasks, timers, or comm state).
22
+ args: Positional args for coro_fn.
23
+ """
24
+ loop = asyncio.get_running_loop()
25
+ return await loop.run_in_executor(_executor, lambda: asyncio.run(coro_fn(*args)))
26
+
27
+
28
+ __all__ = ["run_cpu_bound"]
@@ -24,7 +24,7 @@ class MoonIlluminationConstraint(Constraint):
24
24
  return astroplan.MoonIlluminationConstraint(max=self.max_phase)
25
25
 
26
26
  async def __call__(self, time: Time, task: Task, data: DataProvider) -> bool:
27
- moon_illumination = float(data.observer.moon_illumination(time))
27
+ moon_illumination = data.moon_illumination(time)
28
28
  return moon_illumination <= self.max_phase
29
29
 
30
30
 
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  import astroplan
6
- import astropy.coordinates
7
6
  import astropy.units as u
8
7
  import numpy as np
9
8
  from astropy.coordinates import SkyCoord
@@ -32,12 +31,12 @@ class MoonSeparationConstraint(Constraint):
32
31
  if task.target is None:
33
32
  return True
34
33
  coord = task.target.coordinates(time)
35
- moon_separation = astropy.coordinates.get_body("moon", time).separation(coord, origin_mismatch="ignore")
34
+ moon_separation = data.moon(time).separation(coord, origin_mismatch="ignore") # type: ignore[unexpected-keyword]
36
35
  return float(moon_separation.degree) >= self.min_distance
37
36
 
38
37
  async def filter_skycoord(self, time: Time, coords: SkyCoord, data: DataProvider) -> np.ndarray:
39
- moon = astropy.coordinates.get_body("moon", time)
40
- separations = moon.separation(coords, origin_mismatch="ignore").deg
38
+ moon = data.moon(time)
39
+ separations = moon.separation(coords, origin_mismatch="ignore").deg # type: ignore[unexpected-keyword]
41
40
  return np.asarray(separations >= self.min_distance, dtype=np.bool_)
42
41
 
43
42
 
@@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Literal
5
5
 
6
6
  import astroplan
7
7
  import astropy.units as u
8
- from astropy.coordinates import get_sun
9
8
  from pydantic import Field
10
9
 
11
10
  from pyobs.utils.time import Time
@@ -34,12 +33,12 @@ class SolarElevationConstraint(Constraint):
34
33
  return astroplan.AtNightConstraint(max_solar_altitude=self.max_elevation * u.deg)
35
34
 
36
35
  async def __call__(self, time: Time, task: Task, data: DataProvider) -> bool:
37
- sun = data.observer.sun_altaz(time)
36
+ sun = data.sun_altaz(time)
38
37
  in_range = self.min_elevation <= float(sun.alt.degree) <= self.max_elevation
39
38
  if self.direction == "both":
40
39
  return in_range
41
40
  else:
42
- sun_coord = get_sun(time)
41
+ sun_coord = data.sun(time)
43
42
  transit = data.observer.target_meridian_transit_time(time, sun_coord, which="nearest")
44
43
  midnight = data.observer.midnight(time, which="nearest")
45
44
 
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations
2
+
3
+ import datetime
4
+ from dataclasses import dataclass
5
+ from functools import cache
6
+
7
+ import astropy.coordinates
8
+ from astroplan import Observer
9
+ from astropy.coordinates import SkyCoord
10
+
11
+ from pyobs.robotic.scheduler.observationarchiveevolution import (
12
+ ObservationArchiveEvolution,
13
+ )
14
+ from pyobs.utils.time import Time
15
+
16
+
17
+ @dataclass
18
+ class TaskSuccess:
19
+ date: Time
20
+ night: Time
21
+
22
+
23
+ class DataProvider:
24
+ """Data provider for Merit classes.
25
+
26
+ The ``@cache``d methods below are only safe to call from a single thread at a time -- they're
27
+ used exclusively from within the scheduler's dedicated single-worker executor
28
+ (`pyobs.robotic.scheduler._executor.run_cpu_bound`), never concurrently from the caller's main
29
+ event loop. A new `DataProvider` is created per `schedule()` call, so cache lifetime is bounded
30
+ to one schedule computation and never leaks stale values across runs.
31
+ """
32
+
33
+ def __init__(self, observer: Observer, archive: ObservationArchiveEvolution | None = None):
34
+ self.observer = observer
35
+ self.archive = archive if archive else ObservationArchiveEvolution(observer)
36
+
37
+ @cache
38
+ def last_sunset(self, time: Time) -> Time:
39
+ """Returns the time of the last sunset."""
40
+
41
+ # get last sunset
42
+ return Time(self.observer.sun_set_time(time, which="previous"))
43
+
44
+ @cache
45
+ def last_sunrise(self, time: Time) -> Time:
46
+ """Returns the time of the last sunrise."""
47
+
48
+ # get last sunset
49
+ return Time(self.observer.sun_rise_time(time, which="previous"))
50
+
51
+ @cache
52
+ def night(self, time: Time) -> datetime.date:
53
+ """Returns the time of the last sunset."""
54
+ sunset = self.last_sunset(time)
55
+ return sunset.to_datetime().date()
56
+
57
+ @cache
58
+ def sun(self, time: Time) -> SkyCoord:
59
+ """Returns the Sun's coordinates at the given time."""
60
+ return astropy.coordinates.get_sun(time)
61
+
62
+ @cache
63
+ def sun_altaz(self, time: Time) -> SkyCoord:
64
+ """Returns the Sun's AltAz coordinates at the given time, as seen by the observer."""
65
+ return self.observer.sun_altaz(time)
66
+
67
+ @cache
68
+ def moon(self, time: Time) -> SkyCoord:
69
+ """Returns the Moon's coordinates at the given time."""
70
+ return astropy.coordinates.get_body("moon", time)
71
+
72
+ @cache
73
+ def moon_illumination(self, time: Time) -> float:
74
+ """Returns the Moon's illumination fraction at the given time."""
75
+ return float(self.observer.moon_illumination(time))
76
+
77
+
78
+ __all__ = ["DataProvider"]
@@ -14,6 +14,7 @@ from pyobs.robotic.storage.observationarchive import ObservationArchive
14
14
  from pyobs.utils.time import Time
15
15
 
16
16
  from . import DataProvider
17
+ from ._executor import run_cpu_bound
17
18
  from .constraints import Constraint
18
19
  from .observationarchiveevolution import ObservationArchiveEvolution
19
20
  from .taskscheduler import TaskScheduler
@@ -250,7 +251,7 @@ class OnDemandScheduler(TaskScheduler):
250
251
  ) -> tuple[Task | None, float]:
251
252
 
252
253
  # evaluate all merit functions at given time
253
- merits = await self.evaluate_constraints_and_merits(tasks, projects, start, end, data)
254
+ merits = await run_cpu_bound(self.evaluate_constraints_and_merits, tasks, projects, start, end, data)
254
255
 
255
256
  # find max one
256
257
  idx = np.argmax(merits)
@@ -274,7 +275,7 @@ class OnDemandScheduler(TaskScheduler):
274
275
  other_tasks = [t for t in tasks if t is not task]
275
276
  t = start + TimeDelta(step * u.second)
276
277
  while t < start + TimeDelta(task.estimate_duration(time=start) * u.second):
277
- merits = await self.evaluate_constraints_and_merits(other_tasks, projects, t, end, data)
278
+ merits = await run_cpu_bound(self.evaluate_constraints_and_merits, other_tasks, projects, t, end, data)
278
279
  for i, m in enumerate(merits):
279
280
  if m > merit:
280
281
  return other_tasks[i], t, m
@@ -295,7 +296,9 @@ class OnDemandScheduler(TaskScheduler):
295
296
  better_start: Time = start + TimeDelta(task.estimate_duration(time=start) * u.second)
296
297
 
297
298
  # evaluate merit of better_task at new start time
298
- merit = (await self.evaluate_constraints_and_merits([better_task], projects, better_start, end, data))[0]
299
+ merit = (
300
+ await run_cpu_bound(self.evaluate_constraints_and_merits, [better_task], projects, better_start, end, data)
301
+ )[0]
299
302
 
300
303
  # if it got better, return it, otherwise return Nones
301
304
  if merit >= better_merit:
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import asyncio
3
4
  import io
4
5
  import logging
5
6
  from collections.abc import Awaitable, Callable
@@ -114,11 +115,15 @@ class VirtualFileSystem:
114
115
  hdulist: hdu list to write.
115
116
  """
116
117
 
117
- # open file
118
- async with self.open_file(filename, "wb") as f:
118
+ def _serialize() -> bytes:
119
119
  with io.BytesIO() as bio:
120
120
  hdulist.writeto(bio, *args, **kwargs)
121
- await f.write(bio.getvalue())
121
+ return bio.getvalue()
122
+
123
+ # open file
124
+ async with self.open_file(filename, "wb") as f:
125
+ data = await asyncio.to_thread(_serialize)
126
+ await f.write(data)
122
127
 
123
128
  async def read_image(self, filename: str) -> Image:
124
129
  """Convenience function that wraps around open_file() to read an Image.
@@ -145,11 +150,15 @@ class VirtualFileSystem:
145
150
  image: Image to write.
146
151
  """
147
152
 
148
- # open file
149
- async with self.open_file(filename, "wb") as f:
153
+ def _serialize() -> bytes:
150
154
  with io.BytesIO() as bio:
151
155
  image.writeto(bio, *args, **kwargs)
152
- await f.write(bio.getvalue())
156
+ return bio.getvalue()
157
+
158
+ # open file
159
+ async with self.open_file(filename, "wb") as f:
160
+ data = await asyncio.to_thread(_serialize)
161
+ await f.write(data)
153
162
 
154
163
  async def write_bytes(self, filename: str, data: bytes, *args: Any, **kwargs: Any) -> None:
155
164
  """Convenience function for writing bytes to a file.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pyobs-core"
3
- version = "2.0.0.dev52"
3
+ version = "2.0.0.dev54"
4
4
  description = "robotic telescope software"
5
5
  authors = [{ name = "Tim-Oliver Husser", email = "thusser@uni-goettingen.de" }]
6
6
  requires-python = ">=3.11"
@@ -1,28 +0,0 @@
1
- from abc import ABCMeta, abstractmethod
2
- from typing import Any
3
-
4
- from pyobs.images import Image
5
- from pyobs.object import Object
6
-
7
-
8
- class ImageProcessor(Object, metaclass=ABCMeta):
9
- def __init__(self, **kwargs: Any):
10
- """Init new image processor."""
11
- Object.__init__(self, **kwargs)
12
-
13
- @abstractmethod
14
- async def __call__(self, image: Image) -> Image:
15
- """Processes an image.
16
-
17
- Args:
18
- image: Image to process.
19
-
20
- Returns:
21
- Processed image.
22
- """
23
-
24
- async def reset(self) -> None:
25
- """Resets state of image processor"""
26
-
27
-
28
- __all__ = ["ImageProcessor"]