pyobs-core 2.0.0.dev27__tar.gz → 2.0.0.dev29__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/PKG-INFO +1 -1
  2. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/application.py +1 -1
  3. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/comm.py +15 -0
  4. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/rpc.py +56 -24
  5. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xmppclient.py +30 -0
  6. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xmppcomm.py +35 -3
  7. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IAcquisition.py +4 -1
  8. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IAutoFocus.py +2 -1
  9. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ICalibrate.py +5 -1
  10. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IConfig.py +3 -2
  11. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IData.py +1 -0
  12. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IDataSequence.py +2 -1
  13. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IExposureTime.py +2 -0
  14. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFilters.py +1 -1
  15. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFlatField.py +3 -0
  16. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFocusModel.py +7 -1
  17. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFocuser.py +3 -1
  18. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IMode.py +1 -1
  19. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IMultiFiber.py +3 -0
  20. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingAltAz.py +2 -0
  21. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingBody.py +5 -2
  22. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingHeliocentricPolar.py +3 -1
  23. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingHeliographicStonyhurst.py +3 -1
  24. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingHelioprojective.py +3 -1
  25. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingOrbitalElements.py +6 -3
  26. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingRaDec.py +3 -0
  27. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IPointingSeries.py +5 -1
  28. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IRotation.py +5 -1
  29. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IRunnable.py +7 -1
  30. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IScriptRunner.py +3 -0
  31. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ISyncTarget.py +5 -1
  32. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ITrackingMode.py +1 -1
  33. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IWeather.py +4 -0
  34. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/mixins/fitsnamespace.py +1 -1
  35. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/basecamera.py +12 -13
  36. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/basespectrograph.py +8 -2
  37. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/basevideo.py +5 -1
  38. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/dummycamera.py +2 -1
  39. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/dummyspectrograph.py +3 -2
  40. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/flatfield/flatfield.py +7 -7
  41. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/flatfield/scheduler.py +7 -2
  42. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/focus/focusmodel.py +39 -6
  43. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/focus/focusseries.py +5 -5
  44. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/module.py +226 -38
  45. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/_base.py +2 -2
  46. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/scienceframeguiding.py +5 -1
  47. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/robotic/mastermind.py +7 -2
  48. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/robotic/scriptrunner.py +13 -3
  49. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/roof/basedome.py +1 -1
  50. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/roof/dummyroof.py +20 -13
  51. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/_dummytelescopebase.py +44 -18
  52. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/basetelescope.py +53 -14
  53. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/dummymode.py +3 -2
  54. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/weather/mockweather.py +5 -1
  55. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/weather/weather.py +13 -1
  56. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/astroplanscheduler.py +3 -1
  57. pyobs_core-2.0.0.dev29/pyobs/robotic/scripts/__init__.py +4 -0
  58. pyobs_core-2.0.0.dev29/pyobs/robotic/scripts/exceptions.py +12 -0
  59. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/imaging/autofocus.py +6 -1
  60. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/imaging/imaging.py +1 -1
  61. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/task.py +11 -11
  62. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/taskrunner.py +7 -4
  63. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/task.py +7 -0
  64. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/taskrunner.py +9 -5
  65. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/enums.py +2 -0
  66. pyobs_core-2.0.0.dev29/pyobs/utils/exceptions.py +204 -0
  67. pyobs_core-2.0.0.dev29/pyobs/utils/threads/__init__.py +3 -0
  68. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/threads/lockwithabort.py +4 -7
  69. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyproject.toml +1 -1
  70. pyobs_core-2.0.0.dev27/pyobs/robotic/scripts/__init__.py +0 -3
  71. pyobs_core-2.0.0.dev27/pyobs/utils/exceptions.py +0 -290
  72. pyobs_core-2.0.0.dev27/pyobs/utils/threads/__init__.py +0 -3
  73. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/.gitignore +0 -0
  74. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/LICENSE +0 -0
  75. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/__init__.py +0 -0
  76. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/background_task.py +0 -0
  77. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/cli/__init__.py +0 -0
  78. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/cli/_cli.py +0 -0
  79. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/cli/pyobs.py +0 -0
  80. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/cli/pyobsd.py +0 -0
  81. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/cli/pyobsw.py +0 -0
  82. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/__init__.py +0 -0
  83. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/commlogging.py +0 -0
  84. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/dummy/__init__.py +0 -0
  85. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/dummy/dummycomm.py +0 -0
  86. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/local/__init__.py +0 -0
  87. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/local/localcomm.py +0 -0
  88. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/local/localnetwork.py +0 -0
  89. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/proxy.py +0 -0
  90. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/__init__.py +0 -0
  91. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/serializer.py +0 -0
  92. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
  93. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
  94. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
  95. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
  96. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
  97. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
  98. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
  99. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/__init__.py +0 -0
  100. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/badweather.py +0 -0
  101. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/event.py +0 -0
  102. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/exposurestatuschanged.py +0 -0
  103. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/filterchanged.py +0 -0
  104. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/focusfound.py +0 -0
  105. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/goodweather.py +0 -0
  106. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/log.py +0 -0
  107. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/modechanged.py +0 -0
  108. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/moduleclosed.py +0 -0
  109. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/moduleopened.py +0 -0
  110. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/motionstatuschanged.py +0 -0
  111. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/move.py +0 -0
  112. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/newimage.py +0 -0
  113. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/newspectrum.py +0 -0
  114. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/offsets.py +0 -0
  115. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/roofclosing.py +0 -0
  116. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/roofopened.py +0 -0
  117. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/taskfailed.py +0 -0
  118. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/taskfinished.py +0 -0
  119. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/taskstarted.py +0 -0
  120. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/events/testevent.py +0 -0
  121. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/__init__.py +0 -0
  122. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/image.py +0 -0
  123. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/__init__.py +0 -0
  124. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/altazoffsets.py +0 -0
  125. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/exptime.py +0 -0
  126. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/genericoffset.py +0 -0
  127. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/onskydistance.py +0 -0
  128. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/pixeloffsets.py +0 -0
  129. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/radecoffsets.py +0 -0
  130. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/meta/skyoffsets.py +0 -0
  131. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processor.py +0 -0
  132. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/__init__.py +0 -0
  133. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/_daobackgroundremover.py +0 -0
  134. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/annotation/__init__.py +0 -0
  135. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/annotation/_pillow.py +0 -0
  136. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/annotation/circle.py +0 -0
  137. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/annotation/crosshair.py +0 -0
  138. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/annotation/text.py +0 -0
  139. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/__init__.py +0 -0
  140. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
  141. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
  142. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
  143. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
  144. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/astrometry.py +0 -0
  145. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/astrometry/dotnet.py +0 -0
  146. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/calibration/__init__.py +0 -0
  147. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
  148. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
  149. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/calibration/calibration.py +0 -0
  150. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/__init__.py +0 -0
  151. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
  152. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/_source_catalog.py +0 -0
  153. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/daophot.py +0 -0
  154. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/pysep.py +0 -0
  155. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/simpledisk.py +0 -0
  156. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/detection/sourcedetection.py +0 -0
  157. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/exptime/__init__.py +0 -0
  158. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/exptime/exptime.py +0 -0
  159. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/exptime/star.py +0 -0
  160. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/__init__.py +0 -0
  161. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/addfitsheaders.py +0 -0
  162. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/download.py +0 -0
  163. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/flip.py +0 -0
  164. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/grayscale.py +0 -0
  165. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/httpserver.py +0 -0
  166. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/normalize.py +0 -0
  167. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/save.py +0 -0
  168. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/saveimage.py +0 -0
  169. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/smooth.py +0 -0
  170. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/image/softbin.py +0 -0
  171. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/__init__.py +0 -0
  172. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/addmask.py +0 -0
  173. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
  174. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/circularmask.py +0 -0
  175. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/createfilename.py +0 -0
  176. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
  177. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/misc/removebackground.py +0 -0
  178. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/modules/__init__.py +0 -0
  179. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/modules/getfitsheaders.py +0 -0
  180. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/__init__.py +0 -0
  181. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/astrometry.py +0 -0
  182. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/brighteststar.py +0 -0
  183. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
  184. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
  185. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
  186. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/fitsheader.py +0 -0
  187. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/offsets.py +0 -0
  188. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
  189. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/projected.py +0 -0
  190. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/offsets/spilled_light.py +0 -0
  191. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/__init__.py +0 -0
  192. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
  193. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
  194. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
  195. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
  196. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/photometry.py +0 -0
  197. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/photutil.py +0 -0
  198. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/photometry/pysep.py +0 -0
  199. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/wcs/__init__.py +0 -0
  200. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
  201. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IAbortable.py +0 -0
  202. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IAutoGuiding.py +0 -0
  203. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IAutonomous.py +0 -0
  204. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IBinning.py +0 -0
  205. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ICamera.py +0 -0
  206. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ICooling.py +0 -0
  207. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IDome.py +0 -0
  208. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IExposure.py +0 -0
  209. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
  210. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
  211. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IGain.py +0 -0
  212. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IImageFormat.py +0 -0
  213. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IImageType.py +0 -0
  214. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IModule.py +0 -0
  215. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IMotion.py +0 -0
  216. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IOffsetsAltAz.py +0 -0
  217. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IOffsetsRaDec.py +0 -0
  218. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IReady.py +0 -0
  219. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IRoof.py +0 -0
  220. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IRunning.py +0 -0
  221. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ISpectrograph.py +0 -0
  222. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IStartStop.py +0 -0
  223. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IStructuredConfig.py +0 -0
  224. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ITelescope.py +0 -0
  225. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ITemperatures.py +0 -0
  226. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/ITrackingRate.py +0 -0
  227. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IVideo.py +0 -0
  228. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/IWindow.py +0 -0
  229. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/__init__.py +0 -0
  230. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/interfaces/interface.py +0 -0
  231. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/mixins/__init__.py +0 -0
  232. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/mixins/camerasettings.py +0 -0
  233. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/mixins/fitsheader.py +0 -0
  234. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/mixins/follow.py +0 -0
  235. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/mixins/motionstatus.py +0 -0
  236. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/mixins/pipeline.py +0 -0
  237. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/mixins/waitformotion.py +0 -0
  238. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/mixins/weatheraware.py +0 -0
  239. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/__init__.py +0 -0
  240. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/__init__.py +0 -0
  241. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/adaptive.py +0 -0
  242. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/dummyvideo.py +0 -0
  243. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/camera/pipelinecamera.py +0 -0
  244. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/flatfield/__init__.py +0 -0
  245. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/flatfield/pointing.py +0 -0
  246. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/focus/__init__.py +0 -0
  247. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/focus/dummyautofocus.py +0 -0
  248. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/image/__init__.py +0 -0
  249. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/image/imagewatcher.py +0 -0
  250. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/image/imagewriter.py +0 -0
  251. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/image/pipeline.py +0 -0
  252. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/image/seeing.py +0 -0
  253. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/__init__.py +0 -0
  254. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/_baseguiding.py +0 -0
  255. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/acquisition.py +0 -0
  256. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/autoguiding.py +0 -0
  257. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/dummyacquisition.py +0 -0
  258. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/dummyguiding.py +0 -0
  259. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
  260. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
  261. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
  262. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
  263. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
  264. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/robotic/__init__.py +0 -0
  265. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/robotic/pointing.py +0 -0
  266. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/robotic/scheduler.py +0 -0
  267. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/roof/__init__.py +0 -0
  268. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/roof/baseroof.py +0 -0
  269. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/__init__.py +0 -0
  270. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/dummyaltaztelescope.py +0 -0
  271. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/dummyradectelescope.py +0 -0
  272. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/telescope/dummysolartelescope.py +0 -0
  273. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/test/__init__.py +0 -0
  274. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/test/standalone.py +0 -0
  275. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/__init__.py +0 -0
  276. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/fluentlogger.py +0 -0
  277. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/httpfilecache.py +0 -0
  278. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/kiosk.py +0 -0
  279. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/matrix.py +0 -0
  280. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/stellarium.py +0 -0
  281. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/telegram.py +0 -0
  282. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/utils/trigger.py +0 -0
  283. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/weather/__init__.py +0 -0
  284. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/weather/weather_api.py +0 -0
  285. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/modules/weather/weather_state.py +0 -0
  286. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/object.py +0 -0
  287. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/py.typed +0 -0
  288. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/__init__.py +0 -0
  289. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/observation.py +0 -0
  290. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/__init__.py +0 -0
  291. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
  292. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
  293. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
  294. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +0 -0
  295. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +0 -0
  296. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +0 -0
  297. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
  298. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/dataprovider.py +0 -0
  299. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
  300. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
  301. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
  302. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/constant.py +0 -0
  303. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/follow.py +0 -0
  304. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/interval.py +0 -0
  305. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/merit.py +0 -0
  306. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
  307. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/random.py +0 -0
  308. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
  309. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/merits/transit.py +0 -0
  310. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
  311. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/ondemandscheduler.py +0 -0
  312. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
  313. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
  314. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/heliocentricpolartarget.py +0 -0
  315. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/helioprojectivetarget.py +0 -0
  316. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
  317. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
  318. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
  319. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
  320. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/targets/target.py +0 -0
  321. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
  322. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
  323. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/calibration/darkbias.py +0 -0
  324. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/calibration/pointing.py +0 -0
  325. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/calibration/skyflats.py +0 -0
  326. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/__init__.py +0 -0
  327. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/cases.py +0 -0
  328. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/conditional.py +0 -0
  329. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/parallel.py +0 -0
  330. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/selector.py +0 -0
  331. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/control/sequential.py +0 -0
  332. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
  333. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
  334. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/script.py +0 -0
  335. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/utils/__init__.py +0 -0
  336. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/utils/callmodule.py +0 -0
  337. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
  338. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/scripts/utils/log.py +0 -0
  339. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/__init__.py +0 -0
  340. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/backend/__init__.py +0 -0
  341. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/backend/observationarchive.py +0 -0
  342. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/backend/taskarchive.py +0 -0
  343. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
  344. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
  345. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
  346. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/__init__.py +0 -0
  347. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/_portal.py +0 -0
  348. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
  349. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
  350. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/configdb.py +0 -0
  351. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
  352. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
  353. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
  354. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/scripts/autofocus.py +0 -0
  355. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/scripts/default.py +0 -0
  356. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
  357. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
  358. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/memory/__init__.py +0 -0
  359. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
  360. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
  361. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/observationarchive.py +0 -0
  362. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/storage/taskarchive.py +0 -0
  363. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/__init__.py +0 -0
  364. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/archive/__init__.py +0 -0
  365. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/archive/archive.py +0 -0
  366. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/archive/local_archive.py +0 -0
  367. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
  368. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/exptime/__init__.py +0 -0
  369. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/exptime/exptime.py +0 -0
  370. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/exptime/stellarexptime.py +0 -0
  371. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
  372. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
  373. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/flatfielder.py +0 -0
  374. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
  375. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
  376. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
  377. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
  378. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
  379. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
  380. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
  381. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
  382. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/__init__.py +0 -0
  383. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/average.py +0 -0
  384. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/cache.py +0 -0
  385. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/config.py +0 -0
  386. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/config_schema.py +0 -0
  387. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/coordinates.py +0 -0
  388. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/curvefit.py +0 -0
  389. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/fits.py +0 -0
  390. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/focusseries/__init__.py +0 -0
  391. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/focusseries/base.py +0 -0
  392. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/focusseries/photometry.py +0 -0
  393. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/focusseries/projection.py +0 -0
  394. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/grids/__init__.py +0 -0
  395. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/grids/filters.py +0 -0
  396. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/grids/grid.py +0 -0
  397. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/grids/gridnode.py +0 -0
  398. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/grids/pipeline.py +0 -0
  399. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/__init__.py +0 -0
  400. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/__init__.py +0 -0
  401. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/binningwidget.py +0 -0
  402. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
  403. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/exposewidget.py +0 -0
  404. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
  405. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
  406. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
  407. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
  408. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/http.py +0 -0
  409. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/influxdb.py +0 -0
  410. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/logger.py +0 -0
  411. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/logging/__init__.py +0 -0
  412. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/logging/context.py +0 -0
  413. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/logging/resolvableerror.py +0 -0
  414. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/modulegui.py +0 -0
  415. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/offsets/__init__.py +0 -0
  416. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
  417. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/offsets/applyoffsets.py +0 -0
  418. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
  419. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/parallel.py +0 -0
  420. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/pipeline/__init__.py +0 -0
  421. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/pipeline/night.py +0 -0
  422. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/pipeline/pipeline.py +0 -0
  423. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/__init__.py +0 -0
  424. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/csv.py +0 -0
  425. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/http.py +0 -0
  426. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/log.py +0 -0
  427. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/multi.py +0 -0
  428. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/publisher/publisher.py +0 -0
  429. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/serialization.py +0 -0
  430. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/shellcommand.py +0 -0
  431. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/time.py +0 -0
  432. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/utils/units.py +0 -0
  433. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/version.py +0 -0
  434. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/__init__.py +0 -0
  435. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/archivefile.py +0 -0
  436. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/bufferedfile.py +0 -0
  437. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/file.py +0 -0
  438. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/filelists/__init__.py +0 -0
  439. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/filelists/filelist.py +0 -0
  440. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/filelists/testing.py +0 -0
  441. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/httpfile.py +0 -0
  442. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/localfile.py +0 -0
  443. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/memfile.py +0 -0
  444. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/sftpfile.py +0 -0
  445. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/smbfile.py +0 -0
  446. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/sshfile.py +0 -0
  447. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/tempfile.py +0 -0
  448. {pyobs_core-2.0.0.dev27 → pyobs_core-2.0.0.dev29}/pyobs/vfs/vfs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyobs-core
3
- Version: 2.0.0.dev27
3
+ Version: 2.0.0.dev29
4
4
  Summary: robotic telescope software
5
5
  Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>
6
6
  License-Expression: MIT
@@ -224,7 +224,7 @@ class Application:
224
224
  try:
225
225
  # open module
226
226
  log.info("Opening module...")
227
- await self._module.open()
227
+ await self._module.startup()
228
228
  log.info("Started successfully.")
229
229
 
230
230
  # run module
@@ -530,6 +530,21 @@ class Comm:
530
530
  async def _set_presence(self, state: ModuleState, error_string: str = "") -> None:
531
531
  pass
532
532
 
533
+ async def mark_ready(self) -> None:
534
+ """Signal that the module has finished its own startup (reached ModuleState.READY) and is
535
+ safe for peers to discover.
536
+
537
+ Called by Module once it transitions to READY. Transports that announce a module to peers
538
+ independently of RPC dispatch (e.g. XmppComm's XMPP presence, which drives other modules'
539
+ peer-discovery reaction) hold that announcement back until this fires, so peers never read
540
+ capabilities that are still mid-publish. Transports without such an announcement (e.g.
541
+ LocalComm) don't need to override this.
542
+ """
543
+ await self._mark_ready()
544
+
545
+ async def _mark_ready(self) -> None:
546
+ pass
547
+
533
548
  def get_client_state(self, module: str) -> tuple[ModuleState, str] | None:
534
549
  """Return the last known presence state of a connected module.
535
550
 
@@ -96,9 +96,22 @@ def fault_to_xml(exception: Exception) -> ET.Element:
96
96
  value_elem = ET.Element(f"{{{_NS}}}value")
97
97
  pyobs_fault = ET.Element(f"{{{_PYOBS_NS}}}fault")
98
98
  exc_elem = ET.Element("exception")
99
- exc_elem.text = type(exception).__name__
99
+ # Fully-qualified name, not the bare class name -- domain exceptions can live anywhere, not
100
+ # just in pyobs.utils.exceptions (see PyobsError._registry / resolve()). If this is an
101
+ # UnclassifiedError wrapping something that was never a PyobsError to begin with (see
102
+ # Module.execute()'s classification), serialize the ORIGINAL type's name instead of
103
+ # "UnclassifiedError" itself -- original_type never crosses the wire as an attribute (only the
104
+ # class name and message do), so this is the only way it survives to the caller. The caller's
105
+ # own registry lookup then decides fresh: an unregistered builtin/vendor type still correctly
106
+ # falls back to UnclassifiedError, but this time with original_type actually populated.
107
+ original_type = getattr(exception, "original_type", None)
108
+ exc_elem.text = original_type if original_type else f"{type(exception).__module__}.{type(exception).__qualname__}"
100
109
  msg_elem = ET.Element("message")
101
- msg_elem.text = str(exception)
110
+ # the raw message, not str(exception) -- str() already prepends "<ClassName>", and
111
+ # reconstruction on the caller's side passes this straight back in as the new instance's
112
+ # message, so serializing str() here would bake in a doubled "<ClassName> <ClassName> ..." once
113
+ # the caller's own __str__ formats it again
114
+ msg_elem.text = getattr(exception, "message", None) or str(exception)
102
115
  pyobs_fault.append(exc_elem)
103
116
  pyobs_fault.append(msg_elem)
104
117
  value_elem.append(pyobs_fault)
@@ -107,16 +120,17 @@ def fault_to_xml(exception: Exception) -> ET.Element:
107
120
 
108
121
 
109
122
  def xml_to_fault(fault_elem: ET.Element) -> tuple[str, str]:
110
- """Parse <fault> and return (exception_class_name, message)."""
123
+ """Parse <fault> and return (exception_qualified_name, message)."""
124
+ _fallback_name = f"{exc.RemoteError.__module__}.{exc.RemoteError.__qualname__}"
111
125
  value_elem = fault_elem.find(f"{{{_NS}}}value")
112
126
  if value_elem is None:
113
- return "RemoteError", "Unknown error"
127
+ return _fallback_name, "Unknown error"
114
128
  pyobs_fault = value_elem.find(f"{{{_PYOBS_NS}}}fault")
115
129
  if pyobs_fault is None:
116
- return "RemoteError", "Unknown error"
130
+ return _fallback_name, "Unknown error"
117
131
  exc_el = pyobs_fault.find("exception")
118
132
  msg_el = pyobs_fault.find("message")
119
- exc_name = (exc_el.text if exc_el is not None else None) or "RemoteError"
133
+ exc_name = (exc_el.text if exc_el is not None else None) or _fallback_name
120
134
  msg = (msg_el.text if msg_el is not None else None) or ""
121
135
  return exc_name, msg
122
136
 
@@ -170,6 +184,13 @@ class RPC:
170
184
  iq.enable("rpc_query")
171
185
  pmethod = iq["rpc_query"]["method_call"]["method_name"]
172
186
 
187
+ # XEP-0009 already assigns this per call (used elsewhere as the Future dict key) -- reuse
188
+ # it as a correlation id so an operator can jump from a caller-side exception straight to
189
+ # the matching origin-side log line, instead of neither side pointing at the other
190
+ call_id: str | slixmpp.JID = iq["id"]
191
+ if isinstance(call_id, slixmpp.JID):
192
+ call_id = call_id.node
193
+
173
194
  try:
174
195
  if self._handler is None:
175
196
  return
@@ -208,7 +229,7 @@ class RPC:
208
229
  response.send()
209
230
 
210
231
  # Call method
211
- return_value = await self._handler.execute(pmethod, *params, sender=iq["from"].user)
232
+ return_value = await self._handler.execute(pmethod, *params, sender=iq["from"].user, call_id=call_id)
212
233
 
213
234
  # Serialize return value
214
235
  return_type = hints.get("return", type(None))
@@ -220,9 +241,12 @@ class RPC:
220
241
  self._client.plugin["xep_0009"].forbidden(iq).send()
221
242
 
222
243
  except Exception as e:
223
- if isinstance(e, exc.PyObsError):
224
- e.log(log, "ERROR", f"Exception in call to {pmethod}: {e}", exc_info=True)
225
- else:
244
+ # Module.execute() already classified and logged anything raised by the call itself
245
+ # (every transport gets the same treatment there now), so there's nothing left to do
246
+ # here but serialize and send the fault -- except for failures that never reached
247
+ # execute() at all (e.g. malformed RPC parameters during deserialization above), which
248
+ # this is the only place that will ever log
249
+ if not isinstance(e, exc.PyobsError):
226
250
  log.exception("Unexpected exception in %s.", pmethod)
227
251
  self._client.plugin["xep_0009"].send_fault(iq, fault_to_xml(e))
228
252
 
@@ -269,18 +293,22 @@ class RPC:
269
293
  fault_elem = iq["rpc_query"]["method_response"]["fault"]
270
294
  exc_name, msg = xml_to_fault(fault_elem)
271
295
 
272
- exception_class = getattr(exc, exc_name, None)
273
- if exception_class is None or not issubclass(exception_class, Exception):
274
- exception_class = exc.RemoteError
275
-
276
296
  sender = iq["from"].node
277
- if issubclass(exception_class, exc.RemoteError):
278
- exception = exception_class(message=msg, module=sender)
297
+ exception_class = exc.PyobsError.resolve(exc_name)
298
+ if exception_class is not None:
299
+ # real registered type (e.g. FocusError) -- raised as itself, not wrapped
300
+ exception: exc.PyobsError = exception_class(msg, remote_module=sender)
279
301
  else:
280
- exception = exception_class(msg)
302
+ # unresolvable: never a PyobsError to begin with, or its defining module was never
303
+ # imported in this process -- the qualified name string still survives as original_type
304
+ exception = exc.UnclassifiedError(msg, original_type=exc_name, remote_module=sender)
305
+
306
+ # same correlation id Module.execute() logged on the origin side -- an operator can jump
307
+ # straight from this caller-side exception to the matching detailed log line, by id
308
+ setattr(exception, "call_id", jid)
281
309
 
282
310
  if not future.done():
283
- future.set_exception(exc.InvocationError(module=sender, exception=exception))
311
+ future.set_exception(exception)
284
312
 
285
313
  async def _on_jabber_rpc_error(self, iq: Any) -> None:
286
314
  pmethod = self._client.plugin["xep_0009"].extract_method(iq["rpc_query"])
@@ -295,12 +323,16 @@ class RPC:
295
323
 
296
324
  sender = iq["from"].node
297
325
  e = {
298
- "item-not-found": exc.RemoteError(sender, f"No remote handler for {pmethod} at {iq['from']}!"),
299
- "forbidden": exc.RemoteError(sender, f"Forbidden to invoke {pmethod} at {iq['from']}!"),
300
- "undefined-condition": exc.RemoteError(sender, f"Unexpected problem invoking {pmethod} at {iq['from']}!"),
301
- "service-unavailable": exc.RemoteError(sender, f"Service at {iq['from']} is unavailable."),
302
- "remote-server-not-found": exc.RemoteError(sender, f"Could not find remote server for {iq['from']}."),
303
- }.get(condition, exc.RemoteError(sender, f"Unexpected exception at {iq['from']}!"))
326
+ "item-not-found": exc.RemoteError(f"No remote handler for {pmethod} at {iq['from']}!", module=sender),
327
+ "forbidden": exc.RemoteError(f"Forbidden to invoke {pmethod} at {iq['from']}!", module=sender),
328
+ "undefined-condition": exc.RemoteError(
329
+ f"Unexpected problem invoking {pmethod} at {iq['from']}!", module=sender
330
+ ),
331
+ "service-unavailable": exc.RemoteError(f"Service at {iq['from']} is unavailable.", module=sender),
332
+ "remote-server-not-found": exc.RemoteError(
333
+ f"Could not find remote server for {iq['from']}.", module=sender
334
+ ),
335
+ }.get(condition, exc.RemoteError(f"Unexpected exception at {iq['from']}!", module=sender))
304
336
 
305
337
  callback.set_exception(e)
306
338
 
@@ -34,6 +34,9 @@ class XmppClient(slixmpp.ClientXMPP):
34
34
  self._jid_conflict = False
35
35
  self._conflict_reason: str | None = None
36
36
 
37
+ # module startup gating -- see send_presence()/mark_ready() below
38
+ self._module_ready = False
39
+
37
40
  # auto-accept invitations
38
41
  self.auto_authorize = True
39
42
 
@@ -58,6 +61,33 @@ class XmppClient(slixmpp.ClientXMPP):
58
61
  self.add_event_handler("stream_error", self._stream_error)
59
62
  self.add_filter("in", self._filter_messages)
60
63
 
64
+ def send_presence(self, *args: Any, **kwargs: Any) -> Any:
65
+ """Override slixmpp's send_presence to hold back every presence broadcast -- the initial
66
+ online announcement (session_start) as well as re-broadcasts triggered by capability
67
+ updates (XmppComm._register_events) or lifecycle state changes (XmppComm._set_presence) --
68
+ until mark_ready() fires. This keeps the module invisible to peers' online-discovery
69
+ (_got_online/ModuleOpenedEvent) while it's still starting up, so peers never read
70
+ capabilities that are still mid-publish. Calls made before mark_ready() are simply dropped;
71
+ mark_ready() sends its own presence once, which is enough to announce the module (any
72
+ entity-capabilities hash update from a dropped call in the meantime is still picked up,
73
+ since update_caps() itself isn't gated).
74
+ """
75
+ if not self._module_ready:
76
+ return None
77
+ return super().send_presence(*args, **kwargs)
78
+
79
+ def mark_ready(self) -> None:
80
+ """Allow send_presence() to actually transmit from here on -- called either once the owning
81
+ Module first reaches ModuleState.READY (on the live, already-connected client: announce
82
+ immediately), or by XmppComm._connect() on a freshly created client for a reconnect after
83
+ the module was already READY (not connected yet -- session_start() will send presence as
84
+ soon as it fires, now that gating allows it). No-op if already marked ready."""
85
+ if self._module_ready:
86
+ return
87
+ self._module_ready = True
88
+ if self._connect_event.is_set():
89
+ self.send_presence()
90
+
61
91
  def reconnect(self, wait: int | float = 2.0, reason: str = "Reconnecting") -> Any:
62
92
  """Disconnect only, instead of slixmpp's default reconnect-in-place.
63
93
 
@@ -170,6 +170,12 @@ class XmppComm(Comm):
170
170
  self._xmpp: XmppClient | None = None
171
171
  self._rpc: RPC | None = None
172
172
 
173
+ # module readiness (see mark_ready()) -- lives here rather than solely on XmppClient
174
+ # because _connect() replaces self._xmpp with a brand-new instance on every reconnect,
175
+ # and a reconnect after the module is already READY must announce presence immediately
176
+ # rather than re-gating it
177
+ self._module_ready = False
178
+
173
179
  # pubsub for states
174
180
  self._pubsub_service = f"pubsub.{self._domain}"
175
181
  self._state_node_handlers: dict[str, tuple[type[Interface], list[Callable[[Any], None]]]] = {}
@@ -213,6 +219,18 @@ class XmppComm(Comm):
213
219
  # create client
214
220
  self._xmpp = XmppClient(self._jid, self._password)
215
221
 
222
+ # presence gating (see mark_ready()) only applies to a comm with an actual Module
223
+ # attached that hasn't finished starting yet -- a module-less XmppComm (a GUI, an
224
+ # admin tool, a bare observer in tests) has no such lifecycle and must announce
225
+ # itself immediately as before, or peers relying on presence-based discovery would
226
+ # never see it. Likewise, if the module already reached READY on a previous
227
+ # connection, tell the new client right away -- it isn't connected yet, so this
228
+ # doesn't send anything itself, but it means session_start() will announce presence
229
+ # immediately once (re)connected instead of holding it back as if this were the
230
+ # initial startup.
231
+ if self._module_ready or not self.has_module:
232
+ self._xmpp.mark_ready()
233
+
216
234
  # self._xmpp = slixmpp.ClientXMPP(self._jid, password)
217
235
  # Register directly with an XML mask rather than via pubsub_publish.
218
236
  # slixmpp's StanzaPath matcher requires plugins to be lazily loaded
@@ -503,10 +521,10 @@ class XmppComm(Comm):
503
521
  # RPC layer's jabber_rpc_error event handling ever gets a chance to act on it,
504
522
  # so the IQ-level "forbidden" condition (see Module ACLs) has to be read here.
505
523
  if e.iq["error"]["condition"] == "forbidden":
506
- raise exc.RemoteError(client, f"Forbidden to invoke {method} on {client}.")
507
- raise exc.RemoteError(client, f"Could not call {method} on {client}.")
524
+ raise exc.RemoteError(f"Forbidden to invoke {method} on {client}.", module=client)
525
+ raise exc.RemoteError(f"Could not call {method} on {client}.", module=client)
508
526
  except slixmpp.exceptions.IqTimeout:
509
- raise exc.RemoteTimeoutError(client, f"Call to {method} on {client} timed out.")
527
+ raise exc.RemoteTimeoutError(f"Call to {method} on {client} timed out.", module=client)
510
528
 
511
529
  async def _got_online(self, msg: Any) -> None:
512
530
  """If a new client connects, add it to list.
@@ -957,6 +975,14 @@ class XmppComm(Comm):
957
975
  CLOSED → handled by normal disconnect (unavailable)
958
976
  error_string rides as <status> text when state is ERROR.
959
977
  """
978
+ # publishing any lifecycle state at all is itself a readiness signal -- covers direct
979
+ # set_presence() callers that don't go through Module.set_state() (see mark_ready()).
980
+ # Idempotent: unlocks send_presence() once, then this call's own send below goes through.
981
+ # Goes through self._mark_ready() (not just self.client.mark_ready()) so self._module_ready
982
+ # is set too -- otherwise a later reconnect (_connect() creates a brand-new XmppClient)
983
+ # would re-gate presence on the new client despite this module already being announced.
984
+ await self._mark_ready()
985
+
960
986
  _show_map: dict[ModuleState, str | None] = {
961
987
  ModuleState.READY: None,
962
988
  ModuleState.ERROR: "dnd",
@@ -966,6 +992,12 @@ class XmppComm(Comm):
966
992
  status = error_string if state == ModuleState.ERROR and error_string else None
967
993
  self.client.send_presence(pshow=show, pstatus=status)
968
994
 
995
+ async def _mark_ready(self) -> None:
996
+ """See Comm.mark_ready(). Remembers readiness on self (survives client recreation on
997
+ reconnect, see _connect()) and lets the live client announce presence now."""
998
+ self._module_ready = True
999
+ self.client.mark_ready()
1000
+
969
1001
  async def _subscribe_presence(self, module: str, callback: Callable[[ModuleState, str], None]) -> None:
970
1002
  self._presence_callbacks.setdefault(module, []).append(callback)
971
1003
  result = self._get_client_state(module)
@@ -59,7 +59,10 @@ class IAcquisition(IRunning, IAbortable, metaclass=ABCMeta):
59
59
  Result with time, ra, dec, alt, az, and an offset in whichever frame the mount supports.
60
60
 
61
61
  Raises:
62
- ValueError: If target could not be acquired.
62
+ AbortedError: If the acquisition was aborted.
63
+ GeneralError: If a dependency (e.g. the camera) failed.
64
+ ImageError: If the calculated offset was too large or otherwise unusable.
65
+ AcquisitionError: If target could not be acquired within the given tolerance.
63
66
  """
64
67
  ...
65
68
 
@@ -54,7 +54,8 @@ class IAutoFocus(IRunning, IAbortable, metaclass=ABCMeta):
54
54
  Result of autofocus.
55
55
 
56
56
  Raises:
57
- ValueError: If focus could not be obtained.
57
+ AbortedError: If the autofocus series was aborted.
58
+ FocusError: If focus could not be obtained.
58
59
  """
59
60
  ...
60
61
 
@@ -11,7 +11,11 @@ class ICalibrate(Interface, metaclass=ABCMeta):
11
11
 
12
12
  @abstractmethod
13
13
  async def calibrate(self, **kwargs: Any) -> None:
14
- """Calibrate the device."""
14
+ """Calibrate the device.
15
+
16
+ Raises:
17
+ GeneralError: If calibration failed.
18
+ """
15
19
  ...
16
20
 
17
21
 
@@ -33,7 +33,7 @@ class IConfig(Interface, metaclass=ABCMeta):
33
33
  Current value.
34
34
 
35
35
  Raises:
36
- ValueError: If config item of given name does not exist.
36
+ InvalidArgumentError: If config item of given name does not exist.
37
37
  """
38
38
  ...
39
39
 
@@ -46,7 +46,8 @@ class IConfig(Interface, metaclass=ABCMeta):
46
46
  value: New value.
47
47
 
48
48
  Raises:
49
- ValueError: If config item of given name does not exist or value is invalid.
49
+ InvalidArgumentError: If config item of given name does not exist.
50
+ ValueError: If value is invalid.
50
51
  """
51
52
  ...
52
53
 
@@ -20,6 +20,7 @@ class IData(Interface, metaclass=ABCMeta):
20
20
  Name of image that was taken.
21
21
 
22
22
  Raises:
23
+ DeviceBusyError: If the device is already busy (exposing or running a sequence).
23
24
  GrabImageError: If there was a problem grabbing the image.
24
25
  """
25
26
  ...
@@ -38,7 +38,8 @@ class IDataSequence(IAbortable, metaclass=ABCMeta):
38
38
  during the wait.
39
39
 
40
40
  Raises:
41
- GrabImageError: If the device is already busy (exposing or already running a
41
+ InvalidArgumentError: If count or delay is out of range.
42
+ DeviceBusyError: If the device is already busy (exposing or already running a
42
43
  sequence).
43
44
  """
44
45
  ...
@@ -31,6 +31,8 @@ class IExposureTime(Interface, metaclass=ABCMeta):
31
31
 
32
32
  Raises:
33
33
  ValueError: If exposure time could not be set.
34
+ NotSupportedError: If this module doesn't support setting exposure time directly (e.g.
35
+ it's dictated by something else, like incoming science frames).
34
36
  """
35
37
  ...
36
38
 
@@ -35,7 +35,7 @@ class IFilters(IMotion, metaclass=ABCMeta):
35
35
  filter_name: Name of filter to set.
36
36
 
37
37
  Raises:
38
- ValueError: If an invalid filter was given.
38
+ InvalidArgumentError: If an invalid filter was given.
39
39
  MoveError: If filter wheel cannot be moved.
40
40
  """
41
41
  ...
@@ -21,6 +21,9 @@ class IFlatField(IAbortable, metaclass=ABCMeta):
21
21
 
22
22
  Returns:
23
23
  Number of images actually taken and total exposure time in seconds
24
+
25
+ Raises:
26
+ DeviceBusyError: If a flat-fielding run is already in progress.
24
27
  """
25
28
  ...
26
29
 
@@ -21,7 +21,13 @@ class IFocusModel(Interface, metaclass=ABCMeta):
21
21
 
22
22
  @abstractmethod
23
23
  async def set_optimal_focus(self, **kwargs: Any) -> None:
24
- """Sets optimal focus."""
24
+ """Sets optimal focus.
25
+
26
+ Raises:
27
+ WeatherDataError: If the weather station returned an invalid temperature reading.
28
+ FocusTimeoutError: If a temperature module didn't respond in time.
29
+ MissingSensorError: If a configured sensor isn't in a module's temperature data.
30
+ """
25
31
  ...
26
32
 
27
33
 
@@ -31,8 +31,9 @@ class IFocuser(IMotion, metaclass=ABCMeta):
31
31
  focus: New focus value in mm.
32
32
 
33
33
  Raises:
34
+ InvalidArgumentError: If given value is invalid.
35
+ AbortedError: If movement was aborted.
34
36
  MoveError: If telescope cannot be moved.
35
- InterruptedError: If movement was aborted.
36
37
  """
37
38
  ...
38
39
 
@@ -45,6 +46,7 @@ class IFocuser(IMotion, metaclass=ABCMeta):
45
46
 
46
47
  Raises:
47
48
  ValueError: If given value is invalid.
49
+ NotSupportedError: If this module doesn't support a separate focus offset.
48
50
  MoveError: If telescope cannot be moved.
49
51
  """
50
52
  ...
@@ -36,7 +36,7 @@ class IMode(Interface, metaclass=ABCMeta):
36
36
  group: Name of the group to set the mode for.
37
37
 
38
38
  Raises:
39
- ValueError: If an invalid mode or group was given.
39
+ InvalidArgumentError: If an invalid mode or group was given.
40
40
  MoveError: If mode selector cannot be moved.
41
41
  """
42
42
  ...
@@ -42,6 +42,9 @@ class IMultiFiber(Interface, metaclass=ABCMeta):
42
42
 
43
43
  Args:
44
44
  fiber: Name of fiber to set.
45
+
46
+ Raises:
47
+ InvalidArgumentError: If fiber name is invalid.
45
48
  """
46
49
  ...
47
50
 
@@ -34,6 +34,8 @@ class IPointingAltAz(Interface, metaclass=ABCMeta):
34
34
  az: Az in deg to move to.
35
35
 
36
36
  Raises:
37
+ NotSupportedError: If this device doesn't support Alt/Az pointing.
38
+ AltitudeLimitError: If the destination is below the configured altitude limit.
37
39
  MoveError: If device could not be moved.
38
40
  """
39
41
  ...
@@ -20,8 +20,11 @@ class IPointingBody(Interface, metaclass=ABCMeta):
20
20
  asteroid/comet designation known to JPL Horizons).
21
21
 
22
22
  Raises:
23
- MoveError: If telescope could not be moved.
24
- ValueError: If body name is not resolvable.
23
+ NotSupportedError: If this device doesn't support body tracking.
24
+ BodyResolutionError: If body name is not resolvable.
25
+ MoveError: If telescope could not be moved. Also propagates whatever the underlying
26
+ RA/Dec move raises (e.g. MissingObserverError, AltitudeLimitError), since tracking
27
+ a body is implemented as resolving it and then moving there.
25
28
  """
26
29
  ...
27
30
 
@@ -33,7 +33,9 @@ class IPointingHeliocentricPolar(Interface, metaclass=ABCMeta):
33
33
  psi: Position angle around the solar disk, in degrees.
34
34
 
35
35
  Raises:
36
- MoveError: If device could not be moved.
36
+ MoveError: If device could not be moved. Also propagates whatever the underlying
37
+ RA/Dec move raises (e.g. MissingObserverError, AltitudeLimitError), since this is
38
+ typically implemented as converting to RA/Dec and then moving there.
37
39
  """
38
40
  ...
39
41
 
@@ -35,7 +35,9 @@ class IPointingHeliographicStonyhurst(Interface, metaclass=ABCMeta):
35
35
  lat: Latitude in deg to track.
36
36
 
37
37
  Raises:
38
- MoveError: If device could not be moved.
38
+ MoveError: If device could not be moved. Also propagates whatever the underlying
39
+ RA/Dec move raises (e.g. MissingObserverError, AltitudeLimitError), since this is
40
+ typically implemented as converting to RA/Dec and then moving there.
39
41
  """
40
42
  ...
41
43
 
@@ -34,7 +34,9 @@ class IPointingHelioprojective(Interface, metaclass=ABCMeta):
34
34
  theta_y: The theta_y coordinate.
35
35
 
36
36
  Raises:
37
- MoveError: If device could not be moved.
37
+ MoveError: If device could not be moved. Also propagates whatever the underlying
38
+ RA/Dec move raises (e.g. MissingObserverError, AltitudeLimitError), since this is
39
+ typically implemented as converting to RA/Dec and then moving there.
38
40
  """
39
41
  ...
40
42
 
@@ -37,9 +37,12 @@ class IPointingOrbitalElements(Interface, metaclass=ABCMeta):
37
37
  elements: Orbital elements of the body to track.
38
38
 
39
39
  Raises:
40
- MoveError: If telescope could not be moved.
41
- ValueError: If elements are incomplete or inconsistent (neither mean_anomaly
42
- nor perihelion_time given).
40
+ NotSupportedError: If this device doesn't support orbital-element tracking.
41
+ InvalidOrbitalElementsError: If elements are incomplete or inconsistent (neither
42
+ mean_anomaly nor perihelion_time given).
43
+ MoveError: If telescope could not be moved. Also propagates whatever the underlying
44
+ RA/Dec move raises (e.g. MissingObserverError, AltitudeLimitError), since tracking
45
+ orbital elements is implemented as propagating them and then moving there.
43
46
  """
44
47
  ...
45
48
 
@@ -34,6 +34,9 @@ class IPointingRaDec(Interface, metaclass=ABCMeta):
34
34
  dec: Dec in deg to track.
35
35
 
36
36
  Raises:
37
+ NotSupportedError: If this device doesn't support RA/Dec pointing.
38
+ MissingObserverError: If no observer is configured.
39
+ AltitudeLimitError: If the destination is below the configured altitude limit.
37
40
  MoveError: If device could not be moved.
38
41
  """
39
42
  ...
@@ -12,7 +12,11 @@ class IPointingSeries(Interface, metaclass=ABCMeta):
12
12
 
13
13
  @abstractmethod
14
14
  async def add_pointing_measurement(self, **kwargs: Any) -> None:
15
- """Add a new measurement to the pointing series."""
15
+ """Add a new measurement to the pointing series.
16
+
17
+ Raises:
18
+ GeneralError: If the measurement could not be added.
19
+ """
16
20
  ...
17
21
 
18
22
 
@@ -24,7 +24,11 @@ class IRotation(IMotion, metaclass=ABCMeta):
24
24
 
25
25
  @abstractmethod
26
26
  async def set_rotation(self, angle: Annotated[float, Unit.DEGREES], **kwargs: Any) -> None:
27
- """Sets the rotation angle to the given value in degrees."""
27
+ """Sets the rotation angle to the given value in degrees.
28
+
29
+ Raises:
30
+ MoveError: If the device could not be rotated.
31
+ """
28
32
  ...
29
33
 
30
34
 
@@ -11,7 +11,13 @@ class IRunnable(IAbortable, metaclass=ABCMeta):
11
11
 
12
12
  @abstractmethod
13
13
  async def run(self, **kwargs: Any) -> None:
14
- """Perform module task"""
14
+ """Perform module task
15
+
16
+ Raises:
17
+ DeviceBusyError: If this task is already running.
18
+ ScriptError: ScriptRunner-based implementations wrap whatever the underlying script
19
+ raises that isn't already a domain exception.
20
+ """
15
21
  ...
16
22
 
17
23
 
@@ -15,6 +15,9 @@ class IScriptRunner(Interface, metaclass=ABCMeta):
15
15
 
16
16
  Args:
17
17
  script: Script to run.
18
+
19
+ Raises:
20
+ ScriptError: If the script failed.
18
21
  """
19
22
  ...
20
23
 
@@ -12,7 +12,11 @@ class ISyncTarget(Interface, metaclass=ABCMeta):
12
12
 
13
13
  @abstractmethod
14
14
  async def sync_target(self, **kwargs: Any) -> None:
15
- """Synchronize device on current target."""
15
+ """Synchronize device on current target.
16
+
17
+ Raises:
18
+ GeneralError: If synchronization failed.
19
+ """
16
20
  ...
17
21
 
18
22
 
@@ -46,7 +46,7 @@ class ITrackingMode(Interface, metaclass=ABCMeta):
46
46
 
47
47
  Raises:
48
48
  MoveError: If mode could not be set.
49
- ValueError: If mode is not in this module's capabilities.
49
+ InvalidArgumentError: If mode is not in this module's capabilities.
50
50
  """
51
51
  ...
52
52