pyobs-core 1.53.0__tar.gz → 2.0.0.dev1__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.
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/PKG-INFO +1 -1
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/application.py +1 -1
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/comm.py +112 -18
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/proxy.py +38 -1
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/xmpp/xmppclient.py +0 -1
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/xmpp/xmppcomm.py +185 -4
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/event.py +2 -1
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/modules/getfitsheaders.py +2 -4
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/spilled_light.py +3 -3
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IAutoFocus.py +5 -2
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/ICooling.py +12 -2
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IExposureTime.py +5 -4
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/ILatLon.py +5 -2
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IOffsetsAltAz.py +8 -3
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IOffsetsRaDec.py +8 -3
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IPointingAltAz.py +6 -3
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IPointingHGS.py +8 -3
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IPointingHelioprojective.py +8 -3
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IPointingRaDec.py +6 -3
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IRotation.py +4 -3
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/ITemperatures.py +3 -2
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/interface.py +4 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/mixins/camerasettings.py +3 -6
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/mixins/fitsheader.py +9 -9
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/mixins/follow.py +3 -4
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/mixins/waitformotion.py +9 -12
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/mixins/weatheraware.py +2 -4
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/camera/dummycamera.py +11 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/flatfield/flatfield.py +30 -39
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/flatfield/pointing.py +5 -10
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/flatfield/scheduler.py +11 -15
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/focus/focusmodel.py +20 -35
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/focus/focusseries.py +52 -56
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/module.py +2 -2
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/_base.py +2 -6
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/_baseguiding.py +8 -9
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/acquisition.py +37 -38
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/autoguiding.py +17 -16
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/robotic/pointing.py +7 -8
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/utils/autonomouswarning.py +17 -13
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/utils/kiosk.py +19 -19
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/utils/stellarium.py +7 -8
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/utils/telegram.py +10 -13
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/utils/trigger.py +2 -4
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/object.py +21 -9
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/targets/helioprojectiveradialarget.py +1 -1
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/calibration/darkbias.py +13 -16
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/calibration/pointing.py +9 -12
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/calibration/skyflats.py +21 -24
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/control/selector.py +13 -9
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/imaging/autofocus.py +16 -22
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/imaging/imaging.py +60 -74
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/utils/callmodule.py +6 -8
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/scripts/autofocus.py +30 -41
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/scripts/default.py +56 -69
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/exptime/stellarexptime.py +23 -16
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/skyflats/flatfielder.py +72 -60
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/enums.py +36 -1
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/logging/context.py +1 -1
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/shellcommand.py +10 -11
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyproject.toml +2 -1
- pyobs_core-1.53.0/pyobs/comm/mock/__init__.py +0 -3
- pyobs_core-1.53.0/pyobs/comm/mock/mockcomm.py +0 -85
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/.gitignore +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/LICENSE +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/background_task.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/cli/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/cli/_cli.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/cli/pyobs.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/cli/pyobsd.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/cli/pyobsw.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/commlogging.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/dbus/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/dbus/dbuscomm.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/dbus/patch.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/dummy/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/dummy/dummycomm.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/local/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/local/localcomm.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/local/localnetwork.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/xmpp/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/xmpp/rpc.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/badweather.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/exposurestatuschanged.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/filterchanged.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/focusfound.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/goodweather.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/log.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/modechanged.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/moduleclosed.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/moduleopened.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/motionstatuschanged.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/move.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/newimage.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/newspectrum.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/offsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/roofclosing.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/roofopened.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/taskfailed.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/taskfinished.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/taskstarted.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/events/testevent.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/image.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/meta/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/meta/altazoffsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/meta/exptime.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/meta/genericoffset.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/meta/onskydistance.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/meta/pixeloffsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/meta/radecoffsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/meta/skyoffsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processor.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/_daobackgroundremover.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/annotation/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/annotation/_pillow.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/annotation/circle.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/annotation/crosshair.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/annotation/text.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/astrometry/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/astrometry/astrometry.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/astrometry/dotnet.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/calibration/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/calibration/calibration.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/detection/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/detection/_source_catalog.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/detection/daophot.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/detection/pysep.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/detection/simpledisk.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/detection/sourcedetection.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/exptime/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/exptime/exptime.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/exptime/star.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/image/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/image/addfitsheaders.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/image/download.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/image/flip.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/image/grayscale.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/image/httpserver.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/image/normalize.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/image/save.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/image/saveimage.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/image/smooth.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/image/softbin.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/misc/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/misc/addmask.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/misc/circularmask.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/misc/createfilename.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/misc/removebackground.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/modules/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/astrometry.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/brighteststar.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/fitsheader.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/offsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/projected.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/photometry/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/photometry/photometry.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/photometry/photutil.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/photometry/pysep.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/wcs/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IAbortable.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IAcquisition.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IAutoGuiding.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IAutonomous.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IBinning.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/ICalibrate.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/ICamera.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IConfig.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IData.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IDome.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IExposure.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IFilters.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IFlatField.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IFocusModel.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IFocuser.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IGain.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IImageFormat.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IImageType.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IMode.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IModule.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IMotion.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IMultiFiber.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IPointingSeries.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IReady.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IRoof.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IRunnable.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IRunning.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IScriptRunner.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/ISpectrograph.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IStartStop.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/ISyncTarget.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/ITelescope.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IVideo.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IWeather.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/IWindow.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/interfaces/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/mixins/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/mixins/fitsnamespace.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/mixins/motionstatus.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/mixins/pipeline.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/camera/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/camera/adaptive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/camera/basecamera.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/camera/basespectrograph.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/camera/basevideo.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/camera/dummyspectrograph.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/camera/pipelinecamera.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/flatfield/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/focus/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/image/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/image/imagewatcher.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/image/imagewriter.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/image/pipeline.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/image/seeing.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/dummyacquisition.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/dummyguiding.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/pointing/scienceframeguiding.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/robotic/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/robotic/mastermind.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/robotic/scheduler.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/robotic/scriptrunner.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/roof/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/roof/basedome.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/roof/baseroof.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/roof/dummyroof.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/telescope/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/telescope/basetelescope.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/telescope/dummytelescope.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/test/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/test/standalone.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/utils/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/utils/dummymode.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/utils/fluentlogger.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/utils/httpfilecache.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/utils/matrix.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/weather/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/weather/weather.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/weather/weather_api.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/modules/weather/weather_state.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/py.typed +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/observation.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/dataprovider.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/merits/constant.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/merits/follow.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/merits/interval.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/merits/merit.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/merits/random.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/merits/transit.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/ondemandscheduler.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/targets/target.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/control/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/control/cases.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/control/conditional.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/control/parallel.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/control/sequential.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/script.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/utils/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/scripts/utils/log.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/backend/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/backend/observationarchive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/backend/taskarchive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/_portal.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/configdb.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/task.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/memory/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/observationarchive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/storage/taskarchive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/task.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/taskrunner.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/archive/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/archive/archive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/archive/local_archive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/exptime/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/exptime/exptime.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/average.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/cache.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/config.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/coordinates.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/curvefit.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/exceptions.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/fits.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/focusseries/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/focusseries/base.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/focusseries/photometry.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/focusseries/projection.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/grids/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/grids/filters.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/grids/grid.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/grids/gridnode.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/grids/pipeline.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/gui/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/gui/camera/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/gui/camera/binningwidget.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/gui/camera/exposewidget.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/http.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/influxdb.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/logger.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/logging/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/logging/resolvableerror.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/modulegui.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/offsets/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/offsets/applyoffsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/parallel.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/pipeline/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/pipeline/night.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/pipeline/pipeline.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/publisher/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/publisher/csv.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/publisher/http.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/publisher/log.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/publisher/multi.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/publisher/publisher.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/serialization.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/simulation/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/simulation/camera.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/simulation/telescope.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/simulation/world.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/threads/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/threads/lockwithabort.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/time.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/utils/types.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/version.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/archivefile.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/bufferedfile.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/file.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/filelists/__init__.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/filelists/filelist.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/filelists/testing.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/httpfile.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/localfile.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/memfile.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/sftpfile.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/smbfile.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/sshfile.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/tempfile.py +0 -0
- {pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/vfs/vfs.py +0 -0
|
@@ -98,7 +98,7 @@ class Application:
|
|
|
98
98
|
super().__init__(identifier="pyobs", **kw)
|
|
99
99
|
|
|
100
100
|
def _format_record(self, record: logging.LogRecord) -> list[tuple[str, Any]]:
|
|
101
|
-
pairs = super()._format_record(record)
|
|
101
|
+
pairs: list[tuple[str, Any]] = super()._format_record(record)
|
|
102
102
|
pairs.append(("PYOBS_MODULE", getattr(record, "pyobs_module", "")))
|
|
103
103
|
return pairs
|
|
104
104
|
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import functools
|
|
4
5
|
import inspect
|
|
5
6
|
import logging
|
|
6
7
|
from collections.abc import Callable, Coroutine
|
|
7
|
-
from typing import TYPE_CHECKING, Any,
|
|
8
|
+
from typing import TYPE_CHECKING, Any, overload
|
|
8
9
|
|
|
9
10
|
import pyobs.interfaces
|
|
10
11
|
from pyobs.events import Event, LogEvent, ModuleClosedEvent
|
|
11
12
|
from pyobs.interfaces import Interface
|
|
12
13
|
|
|
13
14
|
from .commlogging import CommLoggingHandler
|
|
14
|
-
from .proxy import Proxy
|
|
15
|
+
from .proxy import Proxy, ProxyType, _ProxyContext
|
|
15
16
|
|
|
16
17
|
if TYPE_CHECKING:
|
|
17
18
|
from pyobs.modules import Module
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
StateCallback = Callable[[Any], None]
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
log = logging.getLogger(__name__)
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class Comm:
|
|
@@ -27,13 +27,13 @@ class Comm:
|
|
|
27
27
|
|
|
28
28
|
__module__ = "pyobs.comm"
|
|
29
29
|
|
|
30
|
-
def __init__(self
|
|
30
|
+
def __init__(self) -> None:
|
|
31
31
|
"""Creates a comm module."""
|
|
32
32
|
|
|
33
33
|
self._proxies: dict[str, Proxy] = {}
|
|
34
|
+
self._state_subscriptions: dict[str, list[tuple[type[Interface], StateCallback]]] = {}
|
|
34
35
|
self._module: Module | None = None
|
|
35
36
|
self._log_queue: asyncio.Queue[LogEvent] = asyncio.Queue()
|
|
36
|
-
self._cache_proxies = cache_proxies
|
|
37
37
|
self._logging_task: asyncio.Task[Any] | None = None
|
|
38
38
|
self._event_handlers: dict[type[Event], list[Callable[[Event, str], Coroutine[Any, Any, bool]]]] = {}
|
|
39
39
|
self._closing = asyncio.Event()
|
|
@@ -117,7 +117,7 @@ class Comm:
|
|
|
117
117
|
return None
|
|
118
118
|
|
|
119
119
|
# if client doesn't exist or we disabled caching, fetch a new proxy
|
|
120
|
-
if client not in self._proxies
|
|
120
|
+
if client not in self._proxies:
|
|
121
121
|
# get interfaces
|
|
122
122
|
try:
|
|
123
123
|
interfaces = await self.get_interfaces(client)
|
|
@@ -126,18 +126,20 @@ class Comm:
|
|
|
126
126
|
|
|
127
127
|
# create new proxy
|
|
128
128
|
proxy = Proxy(self, client, interfaces)
|
|
129
|
+
|
|
130
|
+
# subscribe to state
|
|
131
|
+
for interface in interfaces:
|
|
132
|
+
if getattr(interface, "state", None) is not None:
|
|
133
|
+
await self.subscribe_state(client, interface, functools.partial(proxy.update_state, interface))
|
|
134
|
+
|
|
129
135
|
self._proxies[client] = proxy
|
|
130
136
|
|
|
131
137
|
# return proxy
|
|
132
138
|
return self._proxies[client]
|
|
133
139
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
@overload
|
|
138
|
-
async def proxy(self, name_or_object: str | object, obj_type: type[ProxyType] | None = None) -> Any: ...
|
|
139
|
-
|
|
140
|
-
async def proxy(self, name_or_object: str | object, obj_type: type[ProxyType] | None = None) -> Any | ProxyType:
|
|
140
|
+
async def _resolve_proxy(
|
|
141
|
+
self, name_or_object: str | object, obj_type: type[ProxyType] | None = None
|
|
142
|
+
) -> Any | ProxyType:
|
|
141
143
|
"""Returns object directly if it is of given type. Otherwise get proxy of client with given name and check type.
|
|
142
144
|
|
|
143
145
|
If name_or_object is an object:
|
|
@@ -184,16 +186,41 @@ class Comm:
|
|
|
184
186
|
# completely wrong...
|
|
185
187
|
raise ValueError(f'Given parameter is neither a name nor an object of requested type "{obj_type}".')
|
|
186
188
|
|
|
187
|
-
async def
|
|
189
|
+
async def _safe_resolve_proxy(
|
|
188
190
|
self, name_or_object: str | object, obj_type: type[ProxyType] | None = None
|
|
189
191
|
) -> Any | ProxyType | None:
|
|
190
192
|
"""Calls proxy() in a safe way and returns None instead of raising an exception."""
|
|
191
193
|
|
|
192
194
|
try:
|
|
193
|
-
return await self.
|
|
195
|
+
return await self._resolve_proxy(name_or_object, obj_type)
|
|
194
196
|
except ValueError:
|
|
195
197
|
return None
|
|
196
198
|
|
|
199
|
+
@overload
|
|
200
|
+
def proxy(self, name_or_object: str | object, obj_type: type[ProxyType]) -> _ProxyContext[ProxyType]: ...
|
|
201
|
+
@overload
|
|
202
|
+
def proxy(self, name_or_object: str | object, obj_type: None = None) -> _ProxyContext[Any]: ...
|
|
203
|
+
|
|
204
|
+
def proxy(self, name_or_object: str | object, obj_type: type[ProxyType] | None = None) -> _ProxyContext[Any]:
|
|
205
|
+
"""Returns a context manager; use as `async with self.proxy(...) as x:`."""
|
|
206
|
+
return _ProxyContext(self._resolve_proxy(name_or_object, obj_type))
|
|
207
|
+
|
|
208
|
+
@overload
|
|
209
|
+
def safe_proxy(
|
|
210
|
+
self, name_or_object: str | object, obj_type: type[ProxyType]
|
|
211
|
+
) -> _ProxyContext[ProxyType | None]: ...
|
|
212
|
+
@overload
|
|
213
|
+
def safe_proxy(self, name_or_object: str | object, obj_type: None = None) -> _ProxyContext[Any]: ...
|
|
214
|
+
|
|
215
|
+
def safe_proxy(self, name_or_object: str | object, obj_type: type[ProxyType] | None = None) -> _ProxyContext[Any]:
|
|
216
|
+
"""Same as proxy(), but yields None inside the block instead of raising."""
|
|
217
|
+
return _ProxyContext(self._safe_resolve_proxy(name_or_object, obj_type))
|
|
218
|
+
|
|
219
|
+
async def has_proxy(self, name_or_object: str | object, obj_type: type[Any] | None = None) -> bool:
|
|
220
|
+
"""True if a proxy of the given type can currently be resolved. Doesn't keep a reference
|
|
221
|
+
to it, so doesn't need async with the way proxy()/safe_proxy() do."""
|
|
222
|
+
return await self._safe_resolve_proxy(name_or_object, obj_type) is not None
|
|
223
|
+
|
|
197
224
|
async def _client_disconnected(self, event: Event, sender: str) -> bool:
|
|
198
225
|
"""Called when a client disconnects.
|
|
199
226
|
|
|
@@ -203,9 +230,15 @@ class Comm:
|
|
|
203
230
|
|
|
204
231
|
"""
|
|
205
232
|
|
|
206
|
-
# if a client disconnects,
|
|
233
|
+
# if a client disconnects, clear its proxy state then evict it
|
|
207
234
|
if sender in self._proxies:
|
|
235
|
+
self._proxies[sender].clear_state()
|
|
208
236
|
del self._proxies[sender]
|
|
237
|
+
|
|
238
|
+
# tear down any state subscriptions held for that client
|
|
239
|
+
for interface, callback in self._state_subscriptions.pop(sender, []):
|
|
240
|
+
await self.unsubscribe_state(sender, interface, callback)
|
|
241
|
+
|
|
209
242
|
return True
|
|
210
243
|
|
|
211
244
|
@property
|
|
@@ -397,6 +430,67 @@ class Comm:
|
|
|
397
430
|
) -> None:
|
|
398
431
|
pass
|
|
399
432
|
|
|
433
|
+
async def set_state(self, interface: type[Interface], state: Any) -> None:
|
|
434
|
+
"""Publish state for this module.
|
|
435
|
+
|
|
436
|
+
Args:
|
|
437
|
+
interface: Interface type for the state.
|
|
438
|
+
state: State object to publish.
|
|
439
|
+
"""
|
|
440
|
+
await self._set_state(interface, state)
|
|
441
|
+
|
|
442
|
+
async def _set_state(self, interface: type[Interface], state: Any) -> None:
|
|
443
|
+
pass
|
|
444
|
+
|
|
445
|
+
async def subscribe_state(
|
|
446
|
+
self,
|
|
447
|
+
module: str,
|
|
448
|
+
interface: type[Interface],
|
|
449
|
+
callback: StateCallback,
|
|
450
|
+
) -> None:
|
|
451
|
+
"""Subscribe to state updates for a given module and interface.
|
|
452
|
+
|
|
453
|
+
Delivers the current value immediately on subscribe.
|
|
454
|
+
|
|
455
|
+
Args:
|
|
456
|
+
module: Name of remote module.
|
|
457
|
+
interface: Interface type to subscribe to.
|
|
458
|
+
callback: Called with state object on each update.
|
|
459
|
+
"""
|
|
460
|
+
self._state_subscriptions.setdefault(module, []).append((interface, callback))
|
|
461
|
+
await self._subscribe_state(module, interface, callback)
|
|
462
|
+
|
|
463
|
+
async def _subscribe_state(
|
|
464
|
+
self,
|
|
465
|
+
module: str,
|
|
466
|
+
interface: type[Interface],
|
|
467
|
+
callback: StateCallback,
|
|
468
|
+
) -> None:
|
|
469
|
+
pass
|
|
470
|
+
|
|
471
|
+
async def unsubscribe_state(
|
|
472
|
+
self,
|
|
473
|
+
module: str,
|
|
474
|
+
interface: type[Interface],
|
|
475
|
+
callback: StateCallback,
|
|
476
|
+
) -> None:
|
|
477
|
+
"""Unsubscribe from state updates.
|
|
478
|
+
|
|
479
|
+
Args:
|
|
480
|
+
module: Name of remote module.
|
|
481
|
+
interface: Interface type to unsubscribe from.
|
|
482
|
+
callback: Callback that was registered.
|
|
483
|
+
"""
|
|
484
|
+
await self._unsubscribe_state(module, interface, callback)
|
|
485
|
+
|
|
486
|
+
async def _unsubscribe_state(
|
|
487
|
+
self,
|
|
488
|
+
module: str,
|
|
489
|
+
interface: type[Interface],
|
|
490
|
+
callback: StateCallback,
|
|
491
|
+
) -> None:
|
|
492
|
+
pass
|
|
493
|
+
|
|
400
494
|
def _send_event_to_module(self, event: Event, from_client: str) -> None:
|
|
401
495
|
"""Send an event to all connected modules.
|
|
402
496
|
|
|
@@ -2,7 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import inspect
|
|
4
4
|
import types
|
|
5
|
-
from
|
|
5
|
+
from collections.abc import Coroutine
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Generic, TypeVar, get_type_hints
|
|
6
7
|
|
|
7
8
|
from pyobs.interfaces import Interface
|
|
8
9
|
from pyobs.utils.types import cast_bound_arguments_to_simple
|
|
@@ -10,6 +11,9 @@ from pyobs.utils.types import cast_bound_arguments_to_simple
|
|
|
10
11
|
if TYPE_CHECKING:
|
|
11
12
|
from pyobs.comm import Comm
|
|
12
13
|
|
|
14
|
+
"""Class of a proxy."""
|
|
15
|
+
ProxyType = TypeVar("ProxyType")
|
|
16
|
+
|
|
13
17
|
|
|
14
18
|
class Proxy:
|
|
15
19
|
"""A proxy for remote pyobs modules."""
|
|
@@ -48,6 +52,9 @@ class Proxy:
|
|
|
48
52
|
# create methods
|
|
49
53
|
self._methods = self._create_methods()
|
|
50
54
|
|
|
55
|
+
# store state
|
|
56
|
+
self._state: dict[type[Interface], Any] = {}
|
|
57
|
+
|
|
51
58
|
@property
|
|
52
59
|
def name(self) -> str:
|
|
53
60
|
"""Name of the client."""
|
|
@@ -150,5 +157,35 @@ class Proxy:
|
|
|
150
157
|
|
|
151
158
|
return inner
|
|
152
159
|
|
|
160
|
+
def update_state(self, interface: type[Interface], state: Any) -> None:
|
|
161
|
+
"""Called by Comm whenever a new state arrives. Not intended to be called directly by module code."""
|
|
162
|
+
self._state[interface] = state
|
|
163
|
+
|
|
164
|
+
def clear_state(self) -> None:
|
|
165
|
+
"""Clear all cached state. Called by Comm when the remote module disconnects."""
|
|
166
|
+
self._state.clear()
|
|
167
|
+
|
|
168
|
+
def state(self, interface: type[Interface]) -> Any | None:
|
|
169
|
+
"""Latest known state for the given interface, or None if nothing has arrived yet."""
|
|
170
|
+
return self._state.get(interface)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class _ProxyContext(Generic[ProxyType]):
|
|
174
|
+
"""Returned by Comm.proxy() / Object.proxy() / Comm.safe_proxy(). Must be used as:
|
|
175
|
+
async with self.proxy("camera", ICooling) as camera:
|
|
176
|
+
...
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
def __init__(self, coro: Coroutine[Any, Any, ProxyType]) -> None:
|
|
180
|
+
self._coro = coro
|
|
181
|
+
|
|
182
|
+
async def __aenter__(self) -> ProxyType:
|
|
183
|
+
return await self._coro
|
|
184
|
+
|
|
185
|
+
async def __aexit__(self, *exc_info: Any) -> None:
|
|
186
|
+
# intentionally a no-op: the underlying Proxy is owned and cached
|
|
187
|
+
# by Comm, not by this block, and stays alive for other callers.
|
|
188
|
+
pass
|
|
189
|
+
|
|
153
190
|
|
|
154
191
|
__all__ = ["Proxy"]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import dataclasses
|
|
4
5
|
import functools
|
|
5
6
|
import json
|
|
6
7
|
import logging
|
|
@@ -9,12 +10,15 @@ import ssl
|
|
|
9
10
|
import time
|
|
10
11
|
import xml.sax.saxutils
|
|
11
12
|
from collections.abc import Callable, Coroutine
|
|
12
|
-
from
|
|
13
|
+
from enum import StrEnum
|
|
14
|
+
from typing import TYPE_CHECKING, Annotated, Any, get_args, get_origin, get_type_hints
|
|
13
15
|
|
|
14
16
|
import slixmpp
|
|
15
17
|
import slixmpp.exceptions
|
|
16
18
|
from slixmpp import ElementBase
|
|
17
19
|
from slixmpp.xmlstream import ET
|
|
20
|
+
from slixmpp.xmlstream.handler import Callback
|
|
21
|
+
from slixmpp.xmlstream.matcher import MatchXMLMask
|
|
18
22
|
|
|
19
23
|
from pyobs.comm import Comm
|
|
20
24
|
from pyobs.events import Event, LogEvent, ModuleClosedEvent, ModuleOpenedEvent
|
|
@@ -36,6 +40,11 @@ class EventStanza(ElementBase):
|
|
|
36
40
|
namespace = "pyobs:event"
|
|
37
41
|
|
|
38
42
|
|
|
43
|
+
class StateStanza(ElementBase):
|
|
44
|
+
name = "state"
|
|
45
|
+
namespace = "pyobs:state"
|
|
46
|
+
|
|
47
|
+
|
|
39
48
|
class XmppComm(Comm):
|
|
40
49
|
"""A Comm class using XMPP.
|
|
41
50
|
|
|
@@ -157,6 +166,10 @@ class XmppComm(Comm):
|
|
|
157
166
|
self._xmpp: XmppClient | None = None
|
|
158
167
|
self._rpc: RPC | None = None
|
|
159
168
|
|
|
169
|
+
# pubsub for states
|
|
170
|
+
self._pubsub_service = f"pubsub.{self._domain}"
|
|
171
|
+
self._state_node_handlers: dict[str, tuple[type[Interface], list[Callable[[Any], None]]]] = {}
|
|
172
|
+
|
|
160
173
|
def _set_module(self, module: Module) -> None:
|
|
161
174
|
"""Called, when the module connected to this Comm changes.
|
|
162
175
|
|
|
@@ -186,7 +199,22 @@ class XmppComm(Comm):
|
|
|
186
199
|
self._xmpp = XmppClient(self._jid, self._password)
|
|
187
200
|
|
|
188
201
|
# self._xmpp = slixmpp.ClientXMPP(self._jid, password)
|
|
189
|
-
|
|
202
|
+
# Register directly with an XML mask rather than via pubsub_publish.
|
|
203
|
+
# slixmpp's StanzaPath matcher requires plugins to be lazily loaded
|
|
204
|
+
# before matching — for live notifications (not triggered by an IQ)
|
|
205
|
+
# this never happens, so pubsub_publish is never fired. MatchXMLMask
|
|
206
|
+
# works on raw XML and fires reliably for every pubsub notification.
|
|
207
|
+
self._xmpp.register_handler(
|
|
208
|
+
Callback(
|
|
209
|
+
"pyobs pubsub event",
|
|
210
|
+
MatchXMLMask(
|
|
211
|
+
'<message xmlns="jabber:client">'
|
|
212
|
+
'<event xmlns="http://jabber.org/protocol/pubsub#event">'
|
|
213
|
+
"<items /></event></message>"
|
|
214
|
+
),
|
|
215
|
+
self._handle_event_sync,
|
|
216
|
+
)
|
|
217
|
+
)
|
|
190
218
|
self._xmpp.add_event_handler("got_online", self._got_online)
|
|
191
219
|
self._xmpp.add_event_handler("got_offline", self._got_offline)
|
|
192
220
|
self._xmpp.add_event_handler("disconnected", self._disconnected)
|
|
@@ -421,8 +449,11 @@ class XmppComm(Comm):
|
|
|
421
449
|
log.debug("Module %s does not seem to implement IModule, ignoring.", module)
|
|
422
450
|
return
|
|
423
451
|
|
|
424
|
-
# store interfaces
|
|
425
|
-
|
|
452
|
+
# store interfaces — guard against a second _got_online for the same JID
|
|
453
|
+
# (ejabberd may send multiple presence stanzas) racing against the first
|
|
454
|
+
future = self._interface_cache.get(jid)
|
|
455
|
+
if future is not None and not future.done():
|
|
456
|
+
future.set_result(self._interface_names_to_classes(interface_names))
|
|
426
457
|
|
|
427
458
|
# append to list
|
|
428
459
|
if jid not in self._online_clients:
|
|
@@ -533,6 +564,14 @@ class XmppComm(Comm):
|
|
|
533
564
|
await self._safe_send(self.client["xep_0115"].update_caps)
|
|
534
565
|
self.client.send_presence()
|
|
535
566
|
|
|
567
|
+
def _handle_event_sync(self, msg: Any) -> None:
|
|
568
|
+
"""Synchronous entry point for the MatchXMLMask Callback.
|
|
569
|
+
|
|
570
|
+
Callback handlers must be synchronous; this creates an asyncio task
|
|
571
|
+
so that _handle_event can await safely.
|
|
572
|
+
"""
|
|
573
|
+
asyncio.create_task(self._handle_event(msg))
|
|
574
|
+
|
|
536
575
|
async def _handle_event(self, msg: Any) -> None:
|
|
537
576
|
"""Handles an event.
|
|
538
577
|
|
|
@@ -540,6 +579,26 @@ class XmppComm(Comm):
|
|
|
540
579
|
msg: Received XMPP message.
|
|
541
580
|
"""
|
|
542
581
|
|
|
582
|
+
node = msg["pubsub_event"]["items"]["node"]
|
|
583
|
+
|
|
584
|
+
# State-node notifications: dispatch to handler if registered, then return.
|
|
585
|
+
# map_node_event() cannot be used here because the XEP-0060 plugin iterates
|
|
586
|
+
# Items.iterables (empty) to fire mapped events, so live notifications are
|
|
587
|
+
# silently dropped. _handle_event (pubsub_publish) fires reliably for all nodes.
|
|
588
|
+
if node.startswith("pyobs:state:"):
|
|
589
|
+
if node in self._state_node_handlers:
|
|
590
|
+
if len(msg.xml.findall("{urn:sleekxmpp:delay}delay")) == 0:
|
|
591
|
+
interface, callbacks = self._state_node_handlers[node]
|
|
592
|
+
payload = msg["pubsub_event"]["items"]["item"]["payload"]
|
|
593
|
+
if payload is not None:
|
|
594
|
+
state_obj = self._xml_to_dataclass(payload, interface.state)
|
|
595
|
+
for callback in callbacks:
|
|
596
|
+
callback(state_obj)
|
|
597
|
+
# If payload is None it's a retract notification for the old
|
|
598
|
+
# max_items:1 slot — the matching publish notification (with
|
|
599
|
+
# payload) arrives in the next pubsub_publish event.
|
|
600
|
+
return
|
|
601
|
+
|
|
543
602
|
# get body, unescape it, parse it
|
|
544
603
|
# node = msg['pubsub_event'][items']['node']
|
|
545
604
|
body = json.loads(xml.sax.saxutils.unescape(msg["pubsub_event"]["items"]["item"]["payload"].text))
|
|
@@ -629,5 +688,127 @@ class XmppComm(Comm):
|
|
|
629
688
|
else:
|
|
630
689
|
return False, value
|
|
631
690
|
|
|
691
|
+
@staticmethod
|
|
692
|
+
def _state_namespace(interface: type[Interface]) -> str:
|
|
693
|
+
return f"urn:pyobs:state:{interface.__name__}:{interface.version}"
|
|
694
|
+
|
|
695
|
+
@staticmethod
|
|
696
|
+
def _state_node(module: str, interface: type[Interface]) -> str:
|
|
697
|
+
return f"pyobs:state:{module}:{interface.__name__}:{interface.version}"
|
|
698
|
+
|
|
699
|
+
@staticmethod
|
|
700
|
+
def _dataclass_to_xml(state: Any, namespace: str) -> ET.Element:
|
|
701
|
+
root = ET.Element(f"{{{namespace}}}state")
|
|
702
|
+
for f in dataclasses.fields(state):
|
|
703
|
+
value = getattr(state, f.name)
|
|
704
|
+
# Use ET.Element + append (not SubElement) so children stay in the
|
|
705
|
+
# empty namespace and elem.find("fieldname") works on the receiving side.
|
|
706
|
+
child = ET.Element(f.name)
|
|
707
|
+
if isinstance(value, bool):
|
|
708
|
+
child.text = "true" if value else "false"
|
|
709
|
+
elif isinstance(value, StrEnum):
|
|
710
|
+
child.text = value.value
|
|
711
|
+
else:
|
|
712
|
+
child.text = str(value)
|
|
713
|
+
root.append(child)
|
|
714
|
+
return root
|
|
715
|
+
|
|
716
|
+
@staticmethod
|
|
717
|
+
def _xml_to_dataclass(elem: ET.Element, state_cls: type) -> Any:
|
|
718
|
+
hints = get_type_hints(state_cls, include_extras=True)
|
|
719
|
+
# Extract namespace from root element tag, e.g. "{urn:pyobs:state:ICooling:1}state"
|
|
720
|
+
# Children may arrive namespaced (after ejabberd round-trip) or plain (locally),
|
|
721
|
+
# so try both forms.
|
|
722
|
+
ns = ""
|
|
723
|
+
if elem.tag.startswith("{"):
|
|
724
|
+
ns = elem.tag[1 : elem.tag.index("}")]
|
|
725
|
+
kwargs = {}
|
|
726
|
+
for f in dataclasses.fields(state_cls):
|
|
727
|
+
# Try namespaced lookup first, then plain
|
|
728
|
+
child = elem.find(f"{{{ns}}}{f.name}") if ns else None
|
|
729
|
+
if child is None:
|
|
730
|
+
child = elem.find(f.name)
|
|
731
|
+
if child is None or child.text is None:
|
|
732
|
+
continue
|
|
733
|
+
field_type = hints[f.name]
|
|
734
|
+
# unwrap Annotated[T, ...] → T for type dispatch
|
|
735
|
+
if get_origin(field_type) is Annotated:
|
|
736
|
+
field_type = get_args(field_type)[0]
|
|
737
|
+
if field_type is bool:
|
|
738
|
+
kwargs[f.name] = child.text == "true"
|
|
739
|
+
elif field_type is float:
|
|
740
|
+
kwargs[f.name] = float(child.text)
|
|
741
|
+
elif field_type is int:
|
|
742
|
+
kwargs[f.name] = int(child.text)
|
|
743
|
+
elif isinstance(field_type, type) and issubclass(field_type, StrEnum):
|
|
744
|
+
kwargs[f.name] = field_type(child.text)
|
|
745
|
+
else:
|
|
746
|
+
kwargs[f.name] = child.text
|
|
747
|
+
return state_cls(**kwargs)
|
|
748
|
+
|
|
749
|
+
async def _fetch_and_dispatch_state(
|
|
750
|
+
self, node: str, interface: type[Interface], callback: Callable[[Any], None]
|
|
751
|
+
) -> None:
|
|
752
|
+
"""Fetch the current item for *node* and dispatch it to *callback*.
|
|
753
|
+
|
|
754
|
+
Called when a live notification arrives without a payload — either a
|
|
755
|
+
retract stanza or a node whose deliver_payloads flag is off.
|
|
756
|
+
"""
|
|
757
|
+
try:
|
|
758
|
+
result = await self._safe_send(self.client["xep_0060"].get_items, self._pubsub_service, node, max_items=1)
|
|
759
|
+
item_list = result["pubsub"]["items"]["items"]
|
|
760
|
+
if item_list:
|
|
761
|
+
callback(self._xml_to_dataclass(item_list[0]["payload"], interface.state))
|
|
762
|
+
except (slixmpp.exceptions.IqError, slixmpp.exceptions.IqTimeout):
|
|
763
|
+
pass
|
|
764
|
+
|
|
765
|
+
async def _set_state(self, interface: type[Interface], state: Any) -> None:
|
|
766
|
+
node = self._state_node(self._module.name, interface)
|
|
767
|
+
stanza = StateStanza()
|
|
768
|
+
stanza.xml = self._dataclass_to_xml(state, self._state_namespace(interface))
|
|
769
|
+
await self._safe_send(self.client["xep_0060"].publish, self._pubsub_service, node, payload=stanza)
|
|
770
|
+
|
|
771
|
+
async def _subscribe_state(self, module: str, interface: type[Interface], callback: Callable[[Any], None]) -> None:
|
|
772
|
+
node = self._state_node(module, interface)
|
|
773
|
+
if node in self._state_node_handlers:
|
|
774
|
+
# Node already subscribed — just add the callback
|
|
775
|
+
self._state_node_handlers[node][1].append(callback)
|
|
776
|
+
else:
|
|
777
|
+
self._state_node_handlers[node] = (interface, [callback])
|
|
778
|
+
await self._safe_send(self.client["xep_0060"].subscribe, self._pubsub_service, node)
|
|
779
|
+
|
|
780
|
+
# "deliver the current value immediately on subscribe" -- hard requirement above
|
|
781
|
+
try:
|
|
782
|
+
result = await self._safe_send(self.client["xep_0060"].get_items, self._pubsub_service, node, max_items=1)
|
|
783
|
+
# result["pubsub"]["items"]["items"] uses plugin_multi_attrib to get
|
|
784
|
+
# the list of Item stanzas; item["payload"] returns the XML element
|
|
785
|
+
# via Item.get_payload(). Integer indexing items[0] is wrong here —
|
|
786
|
+
# it calls ElementBase.__getitem__("0") which returns a string.
|
|
787
|
+
item_list = result["pubsub"]["items"]["items"]
|
|
788
|
+
if item_list:
|
|
789
|
+
state_obj = self._xml_to_dataclass(item_list[0]["payload"], interface.state)
|
|
790
|
+
for cb in self._state_node_handlers.get(node, (None, []))[1]:
|
|
791
|
+
cb(state_obj)
|
|
792
|
+
except (slixmpp.exceptions.IqError, slixmpp.exceptions.IqTimeout):
|
|
793
|
+
pass # node exists but nothing published yet
|
|
794
|
+
|
|
795
|
+
async def _unsubscribe_state(
|
|
796
|
+
self, module: str, interface: type[Interface], callback: Callable[[Any], None]
|
|
797
|
+
) -> None:
|
|
798
|
+
node = self._state_node(module, interface)
|
|
799
|
+
if node in self._state_node_handlers:
|
|
800
|
+
_, callbacks = self._state_node_handlers[node]
|
|
801
|
+
try:
|
|
802
|
+
callbacks.remove(callback)
|
|
803
|
+
except ValueError:
|
|
804
|
+
pass
|
|
805
|
+
if not callbacks:
|
|
806
|
+
# Last subscriber — unsubscribe from ejabberd and remove handler
|
|
807
|
+
del self._state_node_handlers[node]
|
|
808
|
+
try:
|
|
809
|
+
await self._safe_send(self.client["xep_0060"].unsubscribe, self._pubsub_service, node)
|
|
810
|
+
except (slixmpp.exceptions.IqError, slixmpp.exceptions.IqTimeout):
|
|
811
|
+
pass # already gone server-side
|
|
812
|
+
|
|
632
813
|
|
|
633
814
|
__all__ = ["XmppComm"]
|
{pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/modules/getfitsheaders.py
RENAMED
|
@@ -101,11 +101,9 @@ class GetFitsHeaders(ImageProcessor):
|
|
|
101
101
|
# loop all modules
|
|
102
102
|
requests: list[Task[Any]] = []
|
|
103
103
|
for sender in self._senders:
|
|
104
|
-
# get proxy
|
|
105
|
-
proxy = await self.proxy(sender, IFitsHeaderBefore)
|
|
106
|
-
|
|
107
104
|
# request headers
|
|
108
|
-
|
|
105
|
+
async with self.proxy(sender, IFitsHeaderBefore) as proxy:
|
|
106
|
+
requests.append(asyncio.create_task(proxy.get_fits_header_before(self._namespace)))
|
|
109
107
|
|
|
110
108
|
# copy image
|
|
111
109
|
out = image.copy()
|
{pyobs_core-1.53.0 → pyobs_core-2.0.0.dev1}/pyobs/images/processors/offsets/spilled_light.py
RENAMED
|
@@ -299,9 +299,9 @@ class SpilledLightGuiding(Offsets):
|
|
|
299
299
|
return image
|
|
300
300
|
|
|
301
301
|
async def _load_fibre_information(self) -> None:
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
302
|
+
async with self.comm.proxy(self._fibers, IMultiFiber) as proxy:
|
|
303
|
+
self._fibre_position = await proxy.get_pixel_position()
|
|
304
|
+
self._inner_radius = await proxy.get_radius()
|
|
305
305
|
|
|
306
306
|
async def _correct_for_binning(self, binning: int) -> None:
|
|
307
307
|
self._fibre_position = (self._fibre_position[0] / binning, self._fibre_position[1] / binning)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from abc import ABCMeta, abstractmethod
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Annotated, Any
|
|
5
5
|
|
|
6
|
+
from ..utils.enums import Unit
|
|
6
7
|
from .IAbortable import IAbortable
|
|
7
8
|
|
|
8
9
|
|
|
@@ -12,7 +13,9 @@ class IAutoFocus(IAbortable, metaclass=ABCMeta):
|
|
|
12
13
|
__module__ = "pyobs.interfaces"
|
|
13
14
|
|
|
14
15
|
@abstractmethod
|
|
15
|
-
async def auto_focus(
|
|
16
|
+
async def auto_focus(
|
|
17
|
+
self, count: int, step: float, exposure_time: Annotated[float, Unit.SECONDS], **kwargs: Any
|
|
18
|
+
) -> tuple[float, float]:
|
|
16
19
|
"""Perform an auto-focus series.
|
|
17
20
|
|
|
18
21
|
This method performs an auto-focus series with "count" images on each side of the initial guess and the given
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from abc import ABCMeta, abstractmethod
|
|
4
|
-
from
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Annotated, Any
|
|
5
6
|
|
|
7
|
+
from ..utils.enums import Unit
|
|
6
8
|
from .ITemperatures import ITemperatures
|
|
7
9
|
|
|
8
10
|
|
|
11
|
+
@dataclass
|
|
12
|
+
class CoolingState:
|
|
13
|
+
setpoint: Annotated[float, Unit.CELSIUS] | None
|
|
14
|
+
power: Annotated[int, Unit.PERCENT] | None
|
|
15
|
+
enabled: bool
|
|
16
|
+
|
|
17
|
+
|
|
9
18
|
class ICooling(ITemperatures, metaclass=ABCMeta):
|
|
10
19
|
"""The module can control the cooling of a device."""
|
|
11
20
|
|
|
12
21
|
__module__ = "pyobs.interfaces"
|
|
22
|
+
state = CoolingState
|
|
13
23
|
|
|
14
24
|
@abstractmethod
|
|
15
25
|
async def get_cooling(self, **kwargs: Any) -> tuple[bool, float, float]:
|
|
@@ -24,7 +34,7 @@ class ICooling(ITemperatures, metaclass=ABCMeta):
|
|
|
24
34
|
...
|
|
25
35
|
|
|
26
36
|
@abstractmethod
|
|
27
|
-
async def set_cooling(self, enabled: bool, setpoint: float, **kwargs: Any) -> None:
|
|
37
|
+
async def set_cooling(self, enabled: bool, setpoint: Annotated[float, Unit.CELSIUS], **kwargs: Any) -> None:
|
|
28
38
|
"""Enables/disables cooling and sets setpoint.
|
|
29
39
|
|
|
30
40
|
Args:
|