pyobs-core 2.0.0.dev92__tar.gz → 2.0.0.dev94__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 (449) hide show
  1. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/PKG-INFO +1 -1
  2. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/camera/basevideo.py +14 -2
  3. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/image/imagewatcher.py +9 -1
  4. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/robotic/mastermind.py +2 -0
  5. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/telescope/basetelescope.py +43 -10
  6. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/calibration/darkbias.py +2 -2
  7. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/calibration/pointing.py +2 -2
  8. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/calibration/skyflats.py +4 -4
  9. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/control/selector.py +2 -2
  10. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/imaging/autofocus.py +3 -3
  11. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/imaging/imaging.py +6 -6
  12. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/archive/archive.py +0 -2
  13. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/archive/local_archive.py +0 -2
  14. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -2
  15. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -2
  16. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -2
  17. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -2
  18. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -2
  19. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -2
  20. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/localfile.py +70 -32
  21. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyproject.toml +1 -1
  22. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/.gitignore +0 -0
  23. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/LICENSE +0 -0
  24. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/__init__.py +0 -0
  25. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/application.py +0 -0
  26. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/background_task.py +0 -0
  27. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/cli/__init__.py +0 -0
  28. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/cli/_cli.py +0 -0
  29. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/cli/pyobs.py +0 -0
  30. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/cli/pyobsd.py +0 -0
  31. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/cli/pyobsw.py +0 -0
  32. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/__init__.py +0 -0
  33. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/comm.py +0 -0
  34. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/commlogging.py +0 -0
  35. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/dummy/__init__.py +0 -0
  36. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/dummy/dummycomm.py +0 -0
  37. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/local/__init__.py +0 -0
  38. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/local/localcomm.py +0 -0
  39. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/local/localnetwork.py +0 -0
  40. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/proxy.py +0 -0
  41. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/__init__.py +0 -0
  42. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/rpc.py +0 -0
  43. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/serializer.py +0 -0
  44. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
  45. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
  46. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
  47. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
  48. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
  49. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
  50. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
  51. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/xmppclient.py +0 -0
  52. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/comm/xmpp/xmppcomm.py +0 -0
  53. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/__init__.py +0 -0
  54. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/badweather.py +0 -0
  55. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/event.py +0 -0
  56. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/exposurestatuschanged.py +0 -0
  57. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/filterchanged.py +0 -0
  58. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/focusfound.py +0 -0
  59. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/goodweather.py +0 -0
  60. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/log.py +0 -0
  61. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/modechanged.py +0 -0
  62. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/moduleclosed.py +0 -0
  63. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/moduleopened.py +0 -0
  64. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/motionstatuschanged.py +0 -0
  65. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/move.py +0 -0
  66. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/newimage.py +0 -0
  67. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/newspectrum.py +0 -0
  68. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/offsets.py +0 -0
  69. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/roofclosing.py +0 -0
  70. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/roofopened.py +0 -0
  71. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/taskfailed.py +0 -0
  72. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/taskfinished.py +0 -0
  73. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/taskstarted.py +0 -0
  74. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/events/testevent.py +0 -0
  75. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/__init__.py +0 -0
  76. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/image.py +0 -0
  77. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/meta/__init__.py +0 -0
  78. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/meta/altazoffsets.py +0 -0
  79. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/meta/exptime.py +0 -0
  80. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/meta/genericoffset.py +0 -0
  81. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/meta/onskydistance.py +0 -0
  82. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/meta/pixeloffsets.py +0 -0
  83. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/meta/radecoffsets.py +0 -0
  84. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/meta/skyoffsets.py +0 -0
  85. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processor.py +0 -0
  86. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/__init__.py +0 -0
  87. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/_daobackgroundremover.py +0 -0
  88. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/annotation/__init__.py +0 -0
  89. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/annotation/_pillow.py +0 -0
  90. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/annotation/circle.py +0 -0
  91. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/annotation/crosshair.py +0 -0
  92. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/annotation/text.py +0 -0
  93. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/astrometry/__init__.py +0 -0
  94. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
  95. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
  96. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
  97. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
  98. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/astrometry/astrometry.py +0 -0
  99. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/astrometry/dotnet.py +0 -0
  100. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/calibration/__init__.py +0 -0
  101. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
  102. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
  103. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/calibration/calibration.py +0 -0
  104. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/detection/__init__.py +0 -0
  105. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
  106. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/detection/_source_catalog.py +0 -0
  107. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/detection/daophot.py +0 -0
  108. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/detection/pysep.py +0 -0
  109. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/detection/simpledisk.py +0 -0
  110. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/detection/sourcedetection.py +0 -0
  111. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/exptime/__init__.py +0 -0
  112. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/exptime/exptime.py +0 -0
  113. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/exptime/star.py +0 -0
  114. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/image/__init__.py +0 -0
  115. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/image/addfitsheaders.py +0 -0
  116. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/image/download.py +0 -0
  117. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/image/flip.py +0 -0
  118. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/image/grayscale.py +0 -0
  119. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/image/httpserver.py +0 -0
  120. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/image/normalize.py +0 -0
  121. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/image/save.py +0 -0
  122. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/image/saveimage.py +0 -0
  123. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/image/smooth.py +0 -0
  124. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/image/softbin.py +0 -0
  125. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/misc/__init__.py +0 -0
  126. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/misc/addmask.py +0 -0
  127. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
  128. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/misc/circularmask.py +0 -0
  129. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/misc/createfilename.py +0 -0
  130. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
  131. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/misc/removebackground.py +0 -0
  132. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/modules/__init__.py +0 -0
  133. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/modules/getfitsheaders.py +0 -0
  134. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/offsets/__init__.py +0 -0
  135. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/offsets/astrometry.py +0 -0
  136. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/offsets/brighteststar.py +0 -0
  137. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
  138. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
  139. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
  140. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/offsets/fitsheader.py +0 -0
  141. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/offsets/offsets.py +0 -0
  142. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
  143. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/offsets/projected.py +0 -0
  144. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/offsets/spilled_light.py +0 -0
  145. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/photometry/__init__.py +0 -0
  146. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
  147. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
  148. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
  149. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
  150. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/photometry/photometry.py +0 -0
  151. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/photometry/photutil.py +0 -0
  152. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/photometry/pysep.py +0 -0
  153. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/wcs/__init__.py +0 -0
  154. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
  155. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IAbortable.py +0 -0
  156. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IAcquisition.py +0 -0
  157. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IAutoFocus.py +0 -0
  158. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IAutoGuiding.py +0 -0
  159. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IAutonomous.py +0 -0
  160. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IBinning.py +0 -0
  161. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/ICalibrate.py +0 -0
  162. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/ICamera.py +0 -0
  163. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IConfig.py +0 -0
  164. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/ICooling.py +0 -0
  165. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IData.py +0 -0
  166. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IDataSequence.py +0 -0
  167. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IDome.py +0 -0
  168. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IExposure.py +0 -0
  169. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IExposureTime.py +0 -0
  170. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IFilters.py +0 -0
  171. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
  172. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
  173. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IFlatField.py +0 -0
  174. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IFocusModel.py +0 -0
  175. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IFocuser.py +0 -0
  176. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IGain.py +0 -0
  177. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IImageFormat.py +0 -0
  178. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IImageType.py +0 -0
  179. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IMode.py +0 -0
  180. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IModule.py +0 -0
  181. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IMotion.py +0 -0
  182. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IMultiFiber.py +0 -0
  183. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IOffsetsAltAz.py +0 -0
  184. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IOffsetsRaDec.py +0 -0
  185. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IPointingAltAz.py +0 -0
  186. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IPointingBody.py +0 -0
  187. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IPointingHeliocentricPolar.py +0 -0
  188. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IPointingHeliographicStonyhurst.py +0 -0
  189. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IPointingHelioprojective.py +0 -0
  190. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IPointingOrbitalElements.py +0 -0
  191. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IPointingRaDec.py +0 -0
  192. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IPointingSeries.py +0 -0
  193. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IReady.py +0 -0
  194. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IRoof.py +0 -0
  195. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IRotation.py +0 -0
  196. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IRunnable.py +0 -0
  197. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IRunning.py +0 -0
  198. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IScriptRunner.py +0 -0
  199. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/ISpectrograph.py +0 -0
  200. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IStartStop.py +0 -0
  201. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IStructuredConfig.py +0 -0
  202. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/ISyncTarget.py +0 -0
  203. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/ITelescope.py +0 -0
  204. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/ITemperatures.py +0 -0
  205. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/ITrackingMode.py +0 -0
  206. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/ITrackingRate.py +0 -0
  207. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IVideo.py +0 -0
  208. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IWeather.py +0 -0
  209. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/IWindow.py +0 -0
  210. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/__init__.py +0 -0
  211. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/interfaces/interface.py +0 -0
  212. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/mixins/__init__.py +0 -0
  213. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/mixins/camerasettings.py +0 -0
  214. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/mixins/fitsheader.py +0 -0
  215. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/mixins/fitsnamespace.py +0 -0
  216. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/mixins/follow.py +0 -0
  217. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/mixins/motionstatus.py +0 -0
  218. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/mixins/pipeline.py +0 -0
  219. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/mixins/waitformotion.py +0 -0
  220. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/mixins/weatheraware.py +0 -0
  221. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/__init__.py +0 -0
  222. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/camera/__init__.py +0 -0
  223. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/camera/adaptive.py +0 -0
  224. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/camera/basecamera.py +0 -0
  225. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/camera/basespectrograph.py +0 -0
  226. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/camera/dummycamera.py +0 -0
  227. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/camera/dummyspectrograph.py +0 -0
  228. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/camera/dummyvideo.py +0 -0
  229. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/camera/pipelinecamera.py +0 -0
  230. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/flatfield/__init__.py +0 -0
  231. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/flatfield/flatfield.py +0 -0
  232. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/flatfield/pointing.py +0 -0
  233. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/flatfield/scheduler.py +0 -0
  234. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/focus/__init__.py +0 -0
  235. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/focus/dummyautofocus.py +0 -0
  236. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/focus/focusmodel.py +0 -0
  237. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/focus/focusseries.py +0 -0
  238. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/image/__init__.py +0 -0
  239. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/image/imagewriter.py +0 -0
  240. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/image/pipeline.py +0 -0
  241. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/image/seeing.py +0 -0
  242. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/module.py +0 -0
  243. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/__init__.py +0 -0
  244. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/_base.py +0 -0
  245. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/_baseguiding.py +0 -0
  246. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/acquisition.py +0 -0
  247. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/autoguiding.py +0 -0
  248. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/dummyacquisition.py +0 -0
  249. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/dummyguiding.py +0 -0
  250. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
  251. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
  252. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
  253. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
  254. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
  255. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/pointing/scienceframeguiding.py +0 -0
  256. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/robotic/__init__.py +0 -0
  257. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/robotic/pointing.py +0 -0
  258. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/robotic/scheduler.py +0 -0
  259. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/robotic/scriptrunner.py +0 -0
  260. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/roof/__init__.py +0 -0
  261. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/roof/basedome.py +0 -0
  262. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/roof/baseroof.py +0 -0
  263. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/roof/dummyroof.py +0 -0
  264. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/telescope/__init__.py +0 -0
  265. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/telescope/_dummytelescopebase.py +0 -0
  266. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/telescope/dummyaltaztelescope.py +0 -0
  267. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/telescope/dummyradectelescope.py +0 -0
  268. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/telescope/dummysolartelescope.py +0 -0
  269. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/test/__init__.py +0 -0
  270. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/test/standalone.py +0 -0
  271. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/utils/__init__.py +0 -0
  272. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/utils/dummymode.py +0 -0
  273. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/utils/fluentlogger.py +0 -0
  274. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/utils/httpfilecache.py +0 -0
  275. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/utils/kiosk.py +0 -0
  276. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/utils/matrix.py +0 -0
  277. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/utils/stellarium.py +0 -0
  278. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/utils/telegram.py +0 -0
  279. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/utils/trigger.py +0 -0
  280. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/weather/__init__.py +0 -0
  281. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/weather/mockweather.py +0 -0
  282. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/weather/weather.py +0 -0
  283. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/weather/weather_api.py +0 -0
  284. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/modules/weather/weather_state.py +0 -0
  285. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/object.py +0 -0
  286. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/py.typed +0 -0
  287. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/__init__.py +0 -0
  288. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/observation.py +0 -0
  289. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/__init__.py +0 -0
  290. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/_executor.py +0 -0
  291. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
  292. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
  293. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
  294. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
  295. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +0 -0
  296. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +0 -0
  297. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +0 -0
  298. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
  299. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/dataprovider.py +0 -0
  300. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
  301. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
  302. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
  303. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/merits/constant.py +0 -0
  304. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/merits/follow.py +0 -0
  305. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/merits/interval.py +0 -0
  306. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/merits/merit.py +0 -0
  307. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
  308. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/merits/random.py +0 -0
  309. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
  310. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/merits/transit.py +0 -0
  311. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
  312. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/ondemandscheduler.py +0 -0
  313. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
  314. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
  315. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/targets/heliocentricpolartarget.py +0 -0
  316. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/targets/helioprojectivetarget.py +0 -0
  317. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
  318. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
  319. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
  320. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
  321. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/targets/target.py +0 -0
  322. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
  323. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/__init__.py +0 -0
  324. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
  325. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/control/__init__.py +0 -0
  326. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/control/cases.py +0 -0
  327. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/control/conditional.py +0 -0
  328. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/control/parallel.py +0 -0
  329. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/control/sequential.py +0 -0
  330. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/exceptions.py +0 -0
  331. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
  332. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
  333. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/script.py +0 -0
  334. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/utils/__init__.py +0 -0
  335. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/utils/callmodule.py +0 -0
  336. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
  337. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/scripts/utils/log.py +0 -0
  338. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/__init__.py +0 -0
  339. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/backend/__init__.py +0 -0
  340. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/backend/observationarchive.py +0 -0
  341. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/backend/taskarchive.py +0 -0
  342. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
  343. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
  344. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
  345. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/__init__.py +0 -0
  346. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/_portal.py +0 -0
  347. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
  348. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
  349. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/configdb.py +0 -0
  350. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
  351. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
  352. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
  353. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/scripts/autofocus.py +0 -0
  354. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/scripts/default.py +0 -0
  355. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
  356. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/task.py +0 -0
  357. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
  358. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
  359. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/memory/__init__.py +0 -0
  360. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
  361. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
  362. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/observationarchive.py +0 -0
  363. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/storage/taskarchive.py +0 -0
  364. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/task.py +0 -0
  365. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/taskrunner.py +0 -0
  366. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/__init__.py +0 -0
  367. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/archive/__init__.py +0 -0
  368. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/exptime/__init__.py +0 -0
  369. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/exptime/exptime.py +0 -0
  370. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/exptime/stellarexptime.py +0 -0
  371. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
  372. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
  373. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/skyflats/flatfielder.py +0 -0
  374. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
  375. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
  376. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
  377. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/__init__.py +0 -0
  378. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/average.py +0 -0
  379. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/cache.py +0 -0
  380. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/config.py +0 -0
  381. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/config_schema.py +0 -0
  382. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/coordinates.py +0 -0
  383. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/curvefit.py +0 -0
  384. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/enums.py +0 -0
  385. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/exceptions.py +0 -0
  386. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/fits.py +0 -0
  387. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/focusseries/__init__.py +0 -0
  388. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/focusseries/base.py +0 -0
  389. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/focusseries/photometry.py +0 -0
  390. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/focusseries/projection.py +0 -0
  391. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/grids/__init__.py +0 -0
  392. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/grids/filters.py +0 -0
  393. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/grids/grid.py +0 -0
  394. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/grids/gridnode.py +0 -0
  395. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/grids/pipeline.py +0 -0
  396. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/gui/__init__.py +0 -0
  397. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/gui/camera/__init__.py +0 -0
  398. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/gui/camera/binningwidget.py +0 -0
  399. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
  400. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/gui/camera/exposewidget.py +0 -0
  401. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
  402. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
  403. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
  404. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
  405. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/http.py +0 -0
  406. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/influxdb.py +0 -0
  407. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/logger.py +0 -0
  408. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/logging/__init__.py +0 -0
  409. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/logging/context.py +0 -0
  410. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/logging/resolvableerror.py +0 -0
  411. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/modulegui.py +0 -0
  412. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/offsets/__init__.py +0 -0
  413. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
  414. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/offsets/applyoffsets.py +0 -0
  415. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
  416. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/parallel.py +0 -0
  417. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/pipeline/__init__.py +0 -0
  418. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/pipeline/pipeline.py +0 -0
  419. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/pipeline/progress.py +0 -0
  420. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/pipeline/reduction.py +0 -0
  421. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/pipeline/reduction_base.py +0 -0
  422. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/publisher/__init__.py +0 -0
  423. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/publisher/csv.py +0 -0
  424. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/publisher/http.py +0 -0
  425. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/publisher/log.py +0 -0
  426. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/publisher/multi.py +0 -0
  427. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/publisher/publisher.py +0 -0
  428. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/serialization.py +0 -0
  429. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/shellcommand.py +0 -0
  430. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/threads/__init__.py +0 -0
  431. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/threads/lockwithabort.py +0 -0
  432. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/time.py +0 -0
  433. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/units.py +0 -0
  434. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/utils/versions.py +0 -0
  435. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/version.py +0 -0
  436. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/__init__.py +0 -0
  437. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/archivefile.py +0 -0
  438. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/bufferedfile.py +0 -0
  439. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/file.py +0 -0
  440. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/filelists/__init__.py +0 -0
  441. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/filelists/filelist.py +0 -0
  442. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/filelists/testing.py +0 -0
  443. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/httpfile.py +0 -0
  444. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/memfile.py +0 -0
  445. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/sftpfile.py +0 -0
  446. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/smbfile.py +0 -0
  447. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/sshfile.py +0 -0
  448. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/tempfile.py +0 -0
  449. {pyobs_core-2.0.0.dev92 → pyobs_core-2.0.0.dev94}/pyobs/vfs/vfs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyobs-core
3
- Version: 2.0.0.dev92
3
+ Version: 2.0.0.dev94
4
4
  Summary: robotic telescope software
5
5
  Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>
6
6
  License-Expression: MIT
@@ -154,6 +154,10 @@ class BaseVideo(Module, ImageFitsHeaderMixin, IVideo, IImageType, metaclass=ABCM
154
154
  self._image_requests: list[ImageRequest] = []
155
155
  self._next_image: NextImage | None = None
156
156
  self._last_image: LastImage | None = None
157
+ # lazy per-frame cache for raw_handler: the first of N simultaneous raw
158
+ # consumers to wake for a given frame computes (meta, frame) bytes and the
159
+ # rest reuse it, instead of each redoing the header build/JSON/copy (#769)
160
+ self._raw_frame_cache: tuple[int, bytes, bytes] | None = None
157
161
  self._last_time = 0.0
158
162
  self._flip = flip
159
163
  # 60s is a starting point, not measured -- trades off against _activate_camera()/
@@ -500,8 +504,16 @@ class BaseVideo(Module, ImageFitsHeaderMixin, IVideo, IImageType, metaclass=ABCM
500
504
  if last is None:
501
505
  continue
502
506
 
503
- # build frame bytes (JSON meta header + raw little-endian bytes)
504
- meta, frame = self._raw_frame(last.data, last.date_obs)
507
+ # build frame bytes (JSON meta header + raw little-endian bytes), reusing
508
+ # the cached result if another consumer already built this frame -- safe
509
+ # without a lock since _raw_frame() is synchronous, so no other task can
510
+ # interleave between the cache check and the store (#769)
511
+ cached = self._raw_frame_cache
512
+ if cached is not None and cached[0] == self._frame_num:
513
+ _, meta, frame = cached
514
+ else:
515
+ meta, frame = self._raw_frame(last.data, last.date_obs)
516
+ self._raw_frame_cache = (self._frame_num, meta, frame)
505
517
 
506
518
  # now send it!
507
519
  try:
@@ -176,7 +176,7 @@ class ImageWatcher(Module):
176
176
  try:
177
177
  with warnings.catch_warnings():
178
178
  warnings.simplefilter("ignore", fits.verify.VerifyWarning)
179
- fits_file = fits.HDUList.fromstring(data)
179
+ fits_file = await asyncio.to_thread(fits.HDUList.fromstring, data)
180
180
  except Exception:
181
181
  fits_file = None
182
182
 
@@ -234,6 +234,10 @@ class ImageWatcher(Module):
234
234
  """Can be overwritten by derived classes to do extra processing on files.
235
235
  All information are stored in self.current_file and can be checked against the given filename.
236
236
 
237
+ Note:
238
+ This hook runs on the module's event loop and must not block: no CPU-heavy or
239
+ synchronous I/O here. Offload such work to a thread, e.g. with ``asyncio.to_thread``.
240
+
237
241
  Args:
238
242
  filename: Input name of original file.
239
243
 
@@ -246,6 +250,10 @@ class ImageWatcher(Module):
246
250
  """Can be overwritten by derived classes to do clean up after successful copying.
247
251
  All information are stored in self.current_file and can be checked against the given filename.
248
252
 
253
+ Note:
254
+ This hook runs on the module's event loop and must not block: no CPU-heavy or
255
+ synchronous I/O here. Offload such work to a thread, e.g. with ``asyncio.to_thread``.
256
+
249
257
  Args:
250
258
  filename: Input name of original file.
251
259
  """
@@ -253,6 +253,8 @@ class Mastermind(Module, IAutonomous, IFitsHeaderBefore):
253
253
  hdr = self._task.get_fits_headers()
254
254
  hdr["TASK"] = FitsHeaderEntry(self._task.name, "Name of task")
255
255
  hdr["REQNUM"] = FitsHeaderEntry(str(self._task.id), "Unique ID of task")
256
+ if self._task.project:
257
+ hdr["PROJECT"] = FitsHeaderEntry(self._task.project, "Project code")
256
258
  if self._obsnum is not None:
257
259
  hdr["OBSNUM"] = FitsHeaderEntry(self._obsnum, "Observation number (night-obsnum)")
258
260
  return hdr
@@ -35,6 +35,27 @@ from pyobs.utils.time import Time
35
35
 
36
36
  log = logging.getLogger(__name__)
37
37
 
38
+
39
+ def _format_ra(ra_deg: float) -> str:
40
+ """Format an RA in degrees as sexagesimal HH:MM:SS.sss.
41
+
42
+ Deliberately avoids astropy's Angle.to_string(): its vectorized do_format ufunc path emits a
43
+ RuntimeWarning on numpy 2.x, which application.py promotes to an error -- see pyobs-gui commit
44
+ 04d39d6 for the same issue and fix.
45
+ """
46
+ h, rem = divmod(ra_deg / 15.0, 1)
47
+ m, rem = divmod(rem * 60, 1)
48
+ return f"{int(h):02d}:{int(m):02d}:{rem * 60:06.3f}"
49
+
50
+
51
+ def _format_dec(dec_deg: float) -> str:
52
+ """Format a Dec in degrees as sexagesimal +DD:MM:SS.sss. See _format_ra for why to_string() is avoided."""
53
+ sign = "+" if dec_deg >= 0 else "-"
54
+ d, rem = divmod(abs(dec_deg), 1)
55
+ m, rem = divmod(rem * 60, 1)
56
+ return f"{sign}{int(d):02d}:{int(m):02d}:{rem * 60:06.3f}"
57
+
58
+
38
59
  # Gaussian gravitational constant, rad/day, for AU/day/solar-mass units -- encodes the Sun's
39
60
  # GM for heliocentric two-body elements, so no per-body mass lookup is needed.
40
61
  _GAUSSIAN_GRAVITATIONAL_CONSTANT = 0.01720209895
@@ -325,6 +346,12 @@ class BaseTelescope(
325
346
  if not isinstance(self, IPointingRaDec):
326
347
  raise exc.NotSupportedError("This telescope does not support RA/Dec pointing.")
327
348
 
349
+ # reject non-finite coordinates outright -- otherwise NaN/inf silently passes the
350
+ # altitude check below (NaN comparisons are always False) and only surfaces later as an
351
+ # opaque RuntimeWarning-turned-error out of the sexagesimal formatting
352
+ if not (math.isfinite(ra) and math.isfinite(dec)):
353
+ raise exc.InvalidArgumentError(f"RA/Dec must be finite, got ra={ra}, dec={dec}.")
354
+
328
355
  # do nothing, if initializing, parking or parked
329
356
  if self.motion_status() in [MotionStatus.INITIALIZING, MotionStatus.PARKING, MotionStatus.PARKED]:
330
357
  return
@@ -354,9 +381,9 @@ class BaseTelescope(
354
381
  await self._change_motion_status(MotionStatus.SLEWING)
355
382
  log.info(
356
383
  "Moving telescope to RA=%s (%.5f°), Dec=%s (%.5f°)...",
357
- ra_dec.ra.to_string(sep=":", unit=u.hour, pad=True),
384
+ _format_ra(ra),
358
385
  ra,
359
- ra_dec.dec.to_string(sep=":", unit=u.deg, pad=True),
386
+ _format_dec(dec),
360
387
  dec,
361
388
  )
362
389
  await self.comm.send_event(MoveRaDecEvent(ra=ra, dec=dec))
@@ -418,6 +445,10 @@ class BaseTelescope(
418
445
  if not isinstance(self, IPointingAltAz):
419
446
  raise exc.NotSupportedError("This telescope does not support Alt/Az pointing.")
420
447
 
448
+ # reject non-finite coordinates outright -- see move_radec for why
449
+ if not (math.isfinite(alt) and math.isfinite(az)):
450
+ raise exc.InvalidArgumentError(f"Alt/Az must be finite, got alt={alt}, az={az}.")
451
+
421
452
  # do nothing, if initializing, parking or parked
422
453
  if self.motion_status() in [MotionStatus.INITIALIZING, MotionStatus.PARKING, MotionStatus.PARKED]:
423
454
  return
@@ -760,14 +791,16 @@ class BaseTelescope(
760
791
  )
761
792
  hdr["AIRMASS"] = FitsHeaderEntry(float(coords_alt_az.secz.value), "Airmass of observation start")
762
793
 
763
- # convert to sexagesimal
764
- if coords_ra_dec is not None:
765
- hdr["RA"] = FitsHeaderEntry(
766
- str(coords_ra_dec.ra.to_string(sep=":", unit=u.hour, pad=True)), "Right ascension of object"
767
- )
768
- hdr["DEC"] = FitsHeaderEntry(
769
- str(coords_ra_dec.dec.to_string(sep=":", unit=u.deg, pad=True)), "Declination of object"
770
- )
794
+ # convert to sexagesimal -- _position_radec can be NaN for an uninitialized telescope, and
795
+ # unlike to_string() the manual formatters below raise on a non-finite value rather than
796
+ # just warning, so skip them instead of emitting bogus headers
797
+ if (
798
+ coords_ra_dec is not None
799
+ and math.isfinite(coords_ra_dec.ra.degree)
800
+ and math.isfinite(coords_ra_dec.dec.degree)
801
+ ):
802
+ hdr["RA"] = FitsHeaderEntry(_format_ra(float(coords_ra_dec.ra.degree)), "Right ascension of object")
803
+ hdr["DEC"] = FitsHeaderEntry(_format_dec(float(coords_ra_dec.dec.degree)), "Declination of object")
771
804
 
772
805
  # site location
773
806
  if self._observer is not None:
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- from typing import TYPE_CHECKING
4
+ from typing import TYPE_CHECKING, Annotated
5
5
 
6
6
  from pyobs.interfaces import (
7
7
  IBinning,
@@ -23,7 +23,7 @@ log = logging.getLogger(__name__)
23
23
  class DarkBiasScript(Script):
24
24
  """Script for running darks or biases."""
25
25
 
26
- camera: str
26
+ camera: Annotated[str, IData, IBinning, IWindow, IExposureTime, IImageType]
27
27
  count: int = 20
28
28
  exptime: float = 0
29
29
  binning: tuple[int, int] = (1, 1)
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- from typing import TYPE_CHECKING
4
+ from typing import TYPE_CHECKING, Annotated
5
5
 
6
6
  from pyobs.interfaces import IPointingAltAz, IReady
7
7
  from pyobs.robotic.scripts import Script
@@ -17,7 +17,7 @@ log = logging.getLogger(__name__)
17
17
  class PointingScript(Script):
18
18
  """Script for pointing the telescope for flats."""
19
19
 
20
- telescope: str
20
+ telescope: Annotated[str, IPointingAltAz, IReady]
21
21
  pointing: SkyFlatsBasePointing
22
22
 
23
23
  async def can_run(self, data: TaskData | None) -> bool:
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- from typing import TYPE_CHECKING
4
+ from typing import TYPE_CHECKING, Annotated
5
5
 
6
6
  from pyobs.interfaces import IBinning, IFilters, IFlatField, IReady, IRoof, ITelescope
7
7
  from pyobs.robotic.scripts import Script
@@ -21,9 +21,9 @@ FlatFunctions = str | dict[str, str | dict[str, str]]
21
21
  class SkyFlatsScript(Script):
22
22
  """Script for scheduling and running skyflats using an IFlatField module."""
23
23
 
24
- roof: str
25
- telescope: str
26
- flatfield: str
24
+ roof: Annotated[str, IRoof]
25
+ telescope: Annotated[str, ITelescope]
26
+ flatfield: Annotated[str, IBinning, IFilters, IFlatField]
27
27
  functions: FlatFunctions = {}
28
28
  priorities: SkyflatPriorities
29
29
  min_exptime: float = 0.5
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- from typing import TYPE_CHECKING
4
+ from typing import TYPE_CHECKING, Annotated
5
5
 
6
6
  from pyobs.interfaces import IMotion
7
7
  from pyobs.interfaces.IMode import IMode
@@ -19,7 +19,7 @@ class SelectorScript(Script):
19
19
  """Script for running Mode Selection."""
20
20
 
21
21
  mode: str
22
- selector: str
22
+ selector: Annotated[str, IMode, IMotion]
23
23
 
24
24
  async def can_run(self, data: TaskData | None) -> bool:
25
25
  """Whether this config can currently run.
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- from typing import TYPE_CHECKING
4
+ from typing import TYPE_CHECKING, Annotated
5
5
 
6
6
  from pyobs.interfaces import IAutoFocus, IMotion, IPointingRaDec, IReady, ITelescope
7
7
  from pyobs.robotic.scripts import Script
@@ -16,8 +16,8 @@ log = logging.getLogger(__name__)
16
16
  class AutoFocusScript(Script):
17
17
  """Script for running autofocus series."""
18
18
 
19
- autofocus: str = "autofocus"
20
- telescope: str = "telescope"
19
+ autofocus: Annotated[str, IAutoFocus] = "autofocus"
20
+ telescope: Annotated[str, ITelescope, IPointingRaDec] = "telescope"
21
21
  count: int = 5
22
22
  step: float = 0.1
23
23
  exposure_time: float = 2.0
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import logging
5
- from typing import TYPE_CHECKING, Any
5
+ from typing import TYPE_CHECKING, Annotated, Any
6
6
 
7
7
  from pydantic import BaseModel, ConfigDict, Field, PrivateAttr
8
8
 
@@ -80,11 +80,11 @@ class ImagingScript(Script):
80
80
 
81
81
  configuration: Configuration = Field(default_factory=Configuration)
82
82
 
83
- camera: str
84
- telescope: str | None = None
85
- filters: str | None = None
86
- autoguider: str | None = None
87
- acquisition: str | None = None
83
+ camera: Annotated[str, ICamera, IBinning, IWindow, IExposureTime, IImageType]
84
+ telescope: Annotated[str | None, ITelescope, IPointingRaDec] = None
85
+ filters: Annotated[str | None, IFilters] = None
86
+ autoguider: Annotated[str | None, IAutoGuiding] = None
87
+ acquisition: Annotated[str | None, IAcquisition] = None
88
88
 
89
89
  _object_name: str | None = PrivateAttr(default=None)
90
90
 
@@ -25,8 +25,6 @@ class FrameInfo:
25
25
  class Archive(PolymorphicBaseModel, metaclass=ABCMeta):
26
26
  """Base class for image archives."""
27
27
 
28
- __module__ = "pyobs.utils.archive"
29
-
30
28
  model_config = {"arbitrary_types_allowed": True}
31
29
 
32
30
  @abstractmethod
@@ -19,8 +19,6 @@ log = logging.getLogger(__name__)
19
19
  class LocalArchive(Archive):
20
20
  """Connector class to a local image archive."""
21
21
 
22
- __module__ = "pyobs.utils.archive"
23
-
24
22
  root: str
25
23
 
26
24
  _root_path: Path = PrivateAttr()
@@ -41,8 +41,6 @@ class PyobsArchiveFrameInfo(FrameInfo):
41
41
  class PyobsArchive(Archive):
42
42
  """Connector class to running pyobs-archive instance."""
43
43
 
44
- __module__ = "pyobs.utils.archive"
45
-
46
44
  url: str
47
45
  token: str
48
46
  proxies: dict[str, str] | None = None
@@ -7,8 +7,6 @@ from pyobs.utils.serialization import PolymorphicBaseModel
7
7
  class SkyFlatsBasePointing(PolymorphicBaseModel, metaclass=ABCMeta):
8
8
  """Base class for flat pointings."""
9
9
 
10
- __module__ = "pyobs.utils.skyflats.pointing"
11
-
12
10
  @abstractmethod
13
11
  async def __call__(self, telescope: IPointingAltAz) -> None:
14
12
  """Move telescope.
@@ -16,8 +16,6 @@ log = logging.getLogger(__name__)
16
16
  class SkyFlatsStaticPointing(SkyFlatsBasePointing):
17
17
  """Static flat pointing."""
18
18
 
19
- __module__ = "pyobs.utils.skyflats.pointing"
20
-
21
19
  _initialized: bool = False
22
20
 
23
21
  @model_validator(mode="after")
@@ -11,8 +11,6 @@ from .base import SkyflatPriorities
11
11
  class ArchiveSkyflatPriorities(SkyflatPriorities):
12
12
  """Calculate flat priorities from an archive."""
13
13
 
14
- __module__ = "pyobs.utils.skyflats.priorities"
15
-
16
14
  archive: Archive
17
15
  site: str
18
16
  instrument: str
@@ -6,8 +6,6 @@ from pyobs.utils.serialization import PolymorphicBaseModel
6
6
  class SkyflatPriorities(PolymorphicBaseModel, metaclass=ABCMeta):
7
7
  """Base class for sky flat priorities."""
8
8
 
9
- __module__ = "pyobs.utils.skyflats.priorities"
10
-
11
9
  @abstractmethod
12
10
  async def __call__(self) -> dict[tuple[str, tuple[int, int]], float]: ...
13
11
 
@@ -4,8 +4,6 @@ from .base import SkyflatPriorities
4
4
  class ConstSkyflatPriorities(SkyflatPriorities):
5
5
  """Constant flat priorities."""
6
6
 
7
- __module__ = "pyobs.utils.skyflats.priorities"
8
-
9
7
  priorities: dict[tuple[str, tuple[int, int]], float]
10
8
 
11
9
  async def __call__(self) -> dict[tuple[str, tuple[int, int]], float]:
@@ -7,13 +7,55 @@ from typing import IO, Any
7
7
  from .file import VFSFile
8
8
 
9
9
 
10
+ def _open_sync(full_path: str, mode: str, mkdir: bool) -> IO[Any]:
11
+ """Open a local file, creating parent directories first if needed.
12
+
13
+ Runs on an executor thread off the event loop. Raises ``ValueError`` when ``mkdir`` is
14
+ disabled and the parent directory does not exist.
15
+ """
16
+ path = os.path.dirname(full_path)
17
+ if not os.path.exists(path):
18
+ if mkdir:
19
+ # exist_ok: this runs on an executor thread, so concurrent opens into the same new
20
+ # sibling directory can race between the exists() check and makedirs() here.
21
+ os.makedirs(path, exist_ok=True)
22
+ else:
23
+ raise ValueError("Cannot write into sub-directory with disabled mkdir option.")
24
+ return open(full_path, mode)
25
+
26
+
27
+ def _find_sync(full_path: str, pattern: str) -> list[str]:
28
+ """Walk ``full_path`` and return the paths of files matching ``pattern``, relative to it."""
29
+ files = []
30
+ for cur, dirnames, filenames in os.walk(full_path):
31
+ for filename in fnmatch.filter(filenames, pattern):
32
+ files += [os.path.relpath(os.path.join(cur, filename), full_path)]
33
+ return files
34
+
35
+
36
+ def _remove_sync(full_path: str) -> bool:
37
+ """Remove the file at ``full_path``; return False if it does not exist or is a directory."""
38
+ try:
39
+ os.remove(full_path)
40
+ return True
41
+ except (FileNotFoundError, IsADirectoryError):
42
+ return False
43
+
44
+
10
45
  class LocalFile(VFSFile):
11
- """Wraps a local file with the virtual file system."""
46
+ """Wraps a local file with the virtual file system.
47
+
48
+ All potentially blocking I/O (open/read/write/close/remove/find/exists) runs on the default
49
+ executor, keeping the event loop responsive even on slow (e.g. network-mounted) paths.
50
+ """
12
51
 
13
52
  __module__ = "pyobs.vfs"
14
53
 
15
54
  def __init__(self, name: str, mode: str = "r", root: str | None = None, mkdir: bool = True, **kwargs: Any):
16
- """Open a local file.
55
+ """Create a new local file.
56
+
57
+ Only validates the path here; the file itself is opened in ``__aenter__`` off the event
58
+ loop, so construction stays cheap and never blocks.
17
59
 
18
60
  Args:
19
61
  name: Name of file.
@@ -32,35 +74,36 @@ class LocalFile(VFSFile):
32
74
 
33
75
  # build filename
34
76
  self.filename = name
35
- full_path = os.path.join(root, name)
77
+ self._full_path = os.path.join(root, name)
78
+ self._mode = mode
79
+ self._mkdir = mkdir
80
+ self.fd: IO[Any] | None = None
36
81
 
37
- # need to create directory?
38
- path = os.path.dirname(full_path)
39
- if not os.path.exists(path):
40
- if mkdir:
41
- os.makedirs(path)
42
- else:
43
- raise ValueError("Cannot write into sub-directory with disabled mkdir option.")
44
-
45
- # file object
46
- self.fd: IO[Any] = open(full_path, mode)
82
+ async def __aenter__(self) -> "LocalFile":
83
+ """Open the file on an executor thread, keeping the event loop responsive."""
84
+ loop = asyncio.get_running_loop()
85
+ self.fd = await loop.run_in_executor(None, _open_sync, self._full_path, self._mode, self._mkdir)
86
+ return self
47
87
 
48
88
  async def close(self) -> None:
49
89
  if self.fd:
50
- self.fd.close()
90
+ loop = asyncio.get_running_loop()
91
+ await loop.run_in_executor(None, self.fd.close)
51
92
 
52
93
  async def read(self, n: int = -1) -> str | bytes:
53
94
  if self.fd is None:
54
- raise OSError
55
- buf = self.fd.read(n)
95
+ raise OSError("LocalFile is not open; use 'async with' to open it before reading.")
96
+ loop = asyncio.get_running_loop()
97
+ buf = await loop.run_in_executor(None, self.fd.read, n)
56
98
  if not isinstance(buf, str) and not isinstance(buf, bytes):
57
99
  raise OSError
58
100
  return buf
59
101
 
60
102
  async def write(self, s: str | bytes) -> None:
61
103
  if self.fd is None:
62
- raise OSError
63
- self.fd.write(s)
104
+ raise OSError("LocalFile is not open; use 'async with' to open it before writing.")
105
+ loop = asyncio.get_running_loop()
106
+ await loop.run_in_executor(None, self.fd.write, s)
64
107
 
65
108
  @staticmethod
66
109
  async def local_path(path: str, **kwargs: Any) -> str:
@@ -120,12 +163,9 @@ class LocalFile(VFSFile):
120
163
  # build full path
121
164
  full_path = os.path.join(root, path)
122
165
 
123
- # loop directories
124
- files = []
125
- for cur, dirnames, filenames in os.walk(full_path):
126
- for filename in fnmatch.filter(filenames, pattern):
127
- files += [os.path.relpath(os.path.join(cur, filename), full_path)]
128
- return files
166
+ # walk directories off the event loop
167
+ loop = asyncio.get_running_loop()
168
+ return await loop.run_in_executor(None, _find_sync, full_path, pattern)
129
169
 
130
170
  @staticmethod
131
171
  async def remove(path: str, *args: Any, **kwargs: Any) -> bool:
@@ -141,13 +181,10 @@ class LocalFile(VFSFile):
141
181
  # get root from kwargs
142
182
  root = kwargs["root"]
143
183
 
144
- # build full path and remove
184
+ # build full path and remove off the event loop
145
185
  full_path = os.path.join(root, path)
146
- try:
147
- os.remove(full_path)
148
- return True
149
- except (FileNotFoundError, IsADirectoryError):
150
- return False
186
+ loop = asyncio.get_running_loop()
187
+ return await loop.run_in_executor(None, _remove_sync, full_path)
151
188
 
152
189
  @classmethod
153
190
  async def exists(cls, path: str, root: str = "", *args: Any, **kwargs: Any) -> bool:
@@ -164,8 +201,9 @@ class LocalFile(VFSFile):
164
201
  # build full path
165
202
  full_path = os.path.join(root, path)
166
203
 
167
- # check
168
- return os.path.exists(full_path)
204
+ # check off the event loop
205
+ loop = asyncio.get_running_loop()
206
+ return await loop.run_in_executor(None, os.path.exists, full_path)
169
207
 
170
208
 
171
209
  __all__ = ["LocalFile"]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pyobs-core"
3
- version = "2.0.0.dev92"
3
+ version = "2.0.0.dev94"
4
4
  description = "robotic telescope software"
5
5
  authors = [{ name = "Tim-Oliver Husser", email = "thusser@uni-goettingen.de" }]
6
6
  requires-python = ">=3.11"