pyobs-core 1.52.16__tar.gz → 2.0.0.dev4__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.52.16 → pyobs_core-2.0.0.dev4}/PKG-INFO +2 -1
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/application.py +52 -8
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/background_task.py +7 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/cli/pyobs.py +6 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/comm.py +199 -21
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/commlogging.py +5 -2
- pyobs_core-2.0.0.dev4/pyobs/comm/local/localcomm.py +157 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/proxy.py +63 -1
- pyobs_core-2.0.0.dev4/pyobs/comm/xmpp/rpc.py +303 -0
- pyobs_core-2.0.0.dev4/pyobs/comm/xmpp/serializer.py +338 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +6 -19
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/xmpp/xmppclient.py +0 -1
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/xmpp/xmppcomm.py +319 -6
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/event.py +2 -1
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/log.py +18 -2
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/modules/getfitsheaders.py +2 -4
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/offsets/spilled_light.py +3 -3
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IAutoFocus.py +5 -2
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IBinning.py +16 -19
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IConfig.py +6 -24
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/ICooling.py +15 -14
- pyobs_core-2.0.0.dev4/pyobs/interfaces/IExposure.py +29 -0
- pyobs_core-2.0.0.dev4/pyobs/interfaces/IExposureTime.py +38 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IFilters.py +13 -17
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IFocuser.py +14 -19
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IGain.py +14 -19
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IImageFormat.py +15 -19
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IImageType.py +13 -10
- pyobs_core-2.0.0.dev4/pyobs/interfaces/IMode.py +43 -0
- pyobs_core-2.0.0.dev4/pyobs/interfaces/IModule.py +26 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IMotion.py +18 -13
- pyobs_core-2.0.0.dev4/pyobs/interfaces/IMultiFiber.py +48 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IOffsetsAltAz.py +17 -12
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IOffsetsRaDec.py +17 -12
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IPointingAltAz.py +17 -12
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IPointingHGS.py +17 -12
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IPointingHelioprojective.py +17 -12
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IPointingRaDec.py +17 -12
- pyobs_core-2.0.0.dev4/pyobs/interfaces/IReady.py +24 -0
- pyobs_core-2.0.0.dev4/pyobs/interfaces/IRotation.py +31 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IRunning.py +13 -1
- pyobs_core-2.0.0.dev4/pyobs/interfaces/ITemperatures.py +32 -0
- pyobs_core-2.0.0.dev4/pyobs/interfaces/IVideo.py +19 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IWindow.py +16 -17
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/__init__.py +48 -24
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/interface.py +4 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/mixins/camerasettings.py +3 -6
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/mixins/fitsheader.py +14 -11
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/mixins/follow.py +3 -4
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/mixins/motionstatus.py +9 -12
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/mixins/waitformotion.py +12 -12
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/mixins/weatheraware.py +3 -5
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/camera/basecamera.py +36 -38
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/camera/basespectrograph.py +0 -8
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/camera/basevideo.py +5 -21
- pyobs_core-2.0.0.dev4/pyobs/modules/camera/dummycamera.py +346 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/camera/dummyspectrograph.py +0 -11
- pyobs_core-2.0.0.dev4/pyobs/modules/camera/dummyvideo.py +69 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/camera/pipelinecamera.py +1 -10
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/flatfield/flatfield.py +49 -63
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/flatfield/pointing.py +5 -10
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/flatfield/scheduler.py +11 -15
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/focus/focusmodel.py +20 -35
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/focus/focusseries.py +52 -56
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/module.py +117 -4
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/_base.py +2 -6
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/_baseguiding.py +8 -9
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/acquisition.py +37 -38
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/autoguiding.py +19 -28
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/scienceframeguiding.py +0 -16
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/robotic/pointing.py +7 -8
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/roof/baseroof.py +8 -11
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/roof/dummyroof.py +3 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/telescope/basetelescope.py +16 -27
- pyobs_core-2.0.0.dev4/pyobs/modules/telescope/dummytelescope.py +312 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/utils/autonomouswarning.py +17 -13
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/utils/dummymode.py +12 -35
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/utils/kiosk.py +19 -19
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/utils/stellarium.py +7 -8
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/utils/telegram.py +10 -13
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/utils/trigger.py +2 -4
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/weather/weather_api.py +1 -1
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/object.py +21 -9
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/merits/transit.py +5 -1
- pyobs_core-2.0.0.dev4/pyobs/robotic/scheduler/targets/__init__.py +6 -0
- pyobs_core-2.0.0.dev4/pyobs/robotic/scheduler/targets/helioprojectiveradialarget.py +32 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/calibration/darkbias.py +13 -16
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/calibration/pointing.py +9 -12
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/calibration/skyflats.py +21 -24
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/control/selector.py +14 -9
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/imaging/autofocus.py +16 -22
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/imaging/imaging.py +60 -74
- pyobs_core-2.0.0.dev4/pyobs/robotic/scripts/utils/callmodule.py +86 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/scripts/autofocus.py +30 -41
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/scripts/default.py +56 -69
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/exptime/stellarexptime.py +23 -16
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/skyflats/flatfielder.py +72 -60
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/enums.py +36 -1
- pyobs_core-2.0.0.dev4/pyobs/utils/logging/context.py +24 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/parallel.py +15 -3
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/shellcommand.py +10 -11
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyproject.toml +9 -1
- pyobs_core-1.52.16/pyobs/comm/dbus/__init__.py +0 -3
- pyobs_core-1.52.16/pyobs/comm/dbus/dbuscomm.py +0 -591
- pyobs_core-1.52.16/pyobs/comm/dbus/patch.py +0 -112
- pyobs_core-1.52.16/pyobs/comm/local/localcomm.py +0 -98
- pyobs_core-1.52.16/pyobs/comm/mock/__init__.py +0 -3
- pyobs_core-1.52.16/pyobs/comm/mock/mockcomm.py +0 -85
- pyobs_core-1.52.16/pyobs/comm/xmpp/rpc.py +0 -274
- pyobs_core-1.52.16/pyobs/interfaces/IExposure.py +0 -33
- pyobs_core-1.52.16/pyobs/interfaces/IExposureTime.py +0 -43
- pyobs_core-1.52.16/pyobs/interfaces/ILatLon.py +0 -38
- pyobs_core-1.52.16/pyobs/interfaces/IMode.py +0 -62
- pyobs_core-1.52.16/pyobs/interfaces/IModule.py +0 -40
- pyobs_core-1.52.16/pyobs/interfaces/IMultiFiber.py +0 -73
- pyobs_core-1.52.16/pyobs/interfaces/IReady.py +0 -22
- pyobs_core-1.52.16/pyobs/interfaces/IRotation.py +0 -23
- pyobs_core-1.52.16/pyobs/interfaces/ITemperatures.py +0 -24
- pyobs_core-1.52.16/pyobs/interfaces/IVideo.py +0 -22
- pyobs_core-1.52.16/pyobs/modules/camera/dummycamera.py +0 -302
- pyobs_core-1.52.16/pyobs/modules/telescope/dummytelescope.py +0 -346
- pyobs_core-1.52.16/pyobs/robotic/scheduler/targets/__init__.py +0 -5
- pyobs_core-1.52.16/pyobs/robotic/scripts/utils/callmodule.py +0 -66
- pyobs_core-1.52.16/pyobs/utils/simulation/__init__.py +0 -11
- pyobs_core-1.52.16/pyobs/utils/simulation/camera.py +0 -284
- pyobs_core-1.52.16/pyobs/utils/simulation/telescope.py +0 -200
- pyobs_core-1.52.16/pyobs/utils/simulation/world.py +0 -107
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/.gitignore +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/LICENSE +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/cli/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/cli/_cli.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/cli/pyobsd.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/cli/pyobsw.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/dummy/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/dummy/dummycomm.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/local/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/local/localnetwork.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/xmpp/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/badweather.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/exposurestatuschanged.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/filterchanged.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/focusfound.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/goodweather.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/modechanged.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/moduleclosed.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/moduleopened.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/motionstatuschanged.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/move.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/newimage.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/newspectrum.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/offsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/roofclosing.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/roofopened.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/taskfailed.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/taskfinished.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/taskstarted.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/events/testevent.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/image.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/meta/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/meta/altazoffsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/meta/exptime.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/meta/genericoffset.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/meta/onskydistance.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/meta/pixeloffsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/meta/radecoffsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/meta/skyoffsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processor.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/_daobackgroundremover.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/annotation/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/annotation/_pillow.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/annotation/circle.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/annotation/crosshair.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/annotation/text.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/astrometry/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/astrometry/astrometry.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/astrometry/dotnet.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/calibration/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/calibration/calibration.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/detection/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/detection/_source_catalog.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/detection/daophot.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/detection/pysep.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/detection/simpledisk.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/detection/sourcedetection.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/exptime/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/exptime/exptime.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/exptime/star.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/image/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/image/addfitsheaders.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/image/download.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/image/flip.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/image/grayscale.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/image/httpserver.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/image/normalize.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/image/save.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/image/saveimage.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/image/smooth.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/image/softbin.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/misc/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/misc/addmask.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/misc/circularmask.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/misc/createfilename.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/misc/removebackground.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/modules/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/offsets/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/offsets/astrometry.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/offsets/brighteststar.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/offsets/fitsheader.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/offsets/offsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/offsets/projected.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/photometry/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/photometry/photometry.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/photometry/photutil.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/photometry/pysep.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/wcs/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IAbortable.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IAcquisition.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IAutoGuiding.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IAutonomous.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/ICalibrate.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/ICamera.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IData.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IDome.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IFlatField.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IFocusModel.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IPointingSeries.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IRoof.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IRunnable.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IScriptRunner.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/ISpectrograph.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IStartStop.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/ISyncTarget.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/ITelescope.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/interfaces/IWeather.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/mixins/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/mixins/fitsnamespace.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/mixins/pipeline.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/camera/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/camera/adaptive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/flatfield/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/focus/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/image/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/image/imagewatcher.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/image/imagewriter.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/image/pipeline.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/image/seeing.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/dummyacquisition.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/dummyguiding.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/robotic/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/robotic/mastermind.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/robotic/scheduler.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/robotic/scriptrunner.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/roof/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/roof/basedome.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/telescope/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/test/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/test/standalone.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/utils/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/utils/fluentlogger.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/utils/httpfilecache.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/utils/matrix.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/weather/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/weather/weather.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/modules/weather/weather_state.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/py.typed +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/observation.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/dataprovider.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/merits/constant.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/merits/follow.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/merits/interval.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/merits/merit.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/merits/random.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/ondemandscheduler.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/targets/target.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/control/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/control/cases.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/control/conditional.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/control/parallel.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/control/sequential.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/script.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/utils/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/scripts/utils/log.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/backend/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/backend/observationarchive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/backend/taskarchive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/_portal.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/configdb.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/task.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/memory/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/observationarchive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/storage/taskarchive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/task.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/taskrunner.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/archive/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/archive/archive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/archive/local_archive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/exptime/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/exptime/exptime.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/average.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/cache.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/config.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/coordinates.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/curvefit.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/exceptions.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/fits.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/focusseries/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/focusseries/base.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/focusseries/photometry.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/focusseries/projection.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/grids/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/grids/filters.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/grids/grid.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/grids/gridnode.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/grids/pipeline.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/gui/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/gui/camera/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/gui/camera/binningwidget.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/gui/camera/exposewidget.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/http.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/influxdb.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/logger.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/logging/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/logging/resolvableerror.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/modulegui.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/offsets/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/offsets/applyoffsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/pipeline/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/pipeline/night.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/pipeline/pipeline.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/publisher/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/publisher/csv.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/publisher/http.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/publisher/log.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/publisher/multi.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/publisher/publisher.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/serialization.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/threads/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/threads/lockwithabort.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/time.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/utils/types.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/version.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/archivefile.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/bufferedfile.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/file.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/filelists/__init__.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/filelists/filelist.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/filelists/testing.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/httpfile.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/localfile.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/memfile.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/sftpfile.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/smbfile.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/sshfile.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/tempfile.py +0 -0
- {pyobs_core-1.52.16 → pyobs_core-2.0.0.dev4}/pyobs/vfs/vfs.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyobs-core
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0.dev4
|
|
4
4
|
Summary: robotic telescope software
|
|
5
5
|
Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -15,6 +15,7 @@ Requires-Dist: colour<0.2,>=0.1.5
|
|
|
15
15
|
Requires-Dist: dacite>=1.9.2
|
|
16
16
|
Requires-Dist: dbus-next<0.3,>=0.2.3
|
|
17
17
|
Requires-Dist: influxdb-client>=1.49.0
|
|
18
|
+
Requires-Dist: logging-journald>=0.6.11
|
|
18
19
|
Requires-Dist: numpy<3,>=2.2.5
|
|
19
20
|
Requires-Dist: pandas>=2.2.3
|
|
20
21
|
Requires-Dist: paramiko>=3.5.1
|
|
@@ -13,6 +13,7 @@ import yaml
|
|
|
13
13
|
from pyobs.modules import Module
|
|
14
14
|
from pyobs.object import get_class_from_string, get_object
|
|
15
15
|
from pyobs.utils.config import pre_process_yaml
|
|
16
|
+
from pyobs.utils.logging.context import ModuleNameFilter
|
|
16
17
|
|
|
17
18
|
# just init logger with something here, will be overwritten in __init__
|
|
18
19
|
log = logging.getLogger(__name__)
|
|
@@ -37,6 +38,7 @@ class Application:
|
|
|
37
38
|
config: str,
|
|
38
39
|
log_file: str | None = None,
|
|
39
40
|
log_level: str = "info",
|
|
41
|
+
syslog: bool = False,
|
|
40
42
|
influx_log: InfluxLogConfig | None = None,
|
|
41
43
|
**kwargs: Any,
|
|
42
44
|
):
|
|
@@ -46,6 +48,8 @@ class Application:
|
|
|
46
48
|
config: Name of config file.
|
|
47
49
|
log_file: Name of log file, if any.
|
|
48
50
|
log_level: Logging level.
|
|
51
|
+
syslog: Send log to systemd journal, tagged with SYSLOG_IDENTIFIER=pyobs
|
|
52
|
+
and PYOBS_MODULE=<module name>. Requires logging-journald.
|
|
49
53
|
influx_log: Log to influx DB.
|
|
50
54
|
"""
|
|
51
55
|
|
|
@@ -53,13 +57,22 @@ class Application:
|
|
|
53
57
|
self._config = config
|
|
54
58
|
config_base = os.path.splitext(os.path.basename(config))[0]
|
|
55
59
|
|
|
56
|
-
#
|
|
57
|
-
|
|
60
|
+
# filter that injects %(pyobs_module)s into every LogRecord from the context var
|
|
61
|
+
module_name_filter = ModuleNameFilter()
|
|
62
|
+
|
|
63
|
+
# formatters — file/stream include the module name as text; journal omits
|
|
64
|
+
# timestamp/priority since those are captured natively by journald
|
|
65
|
+
formatter = logging.Formatter(
|
|
66
|
+
"%(asctime)s [%(levelname)s] (%(pyobs_module)s) %(filename)s:%(lineno)d %(message)s"
|
|
67
|
+
)
|
|
68
|
+
journal_formatter = logging.Formatter("%(pyobs_module)s %(filename)s:%(lineno)d %(message)s")
|
|
69
|
+
|
|
58
70
|
handlers: list[logging.Handler] = []
|
|
59
71
|
|
|
60
72
|
# create stdout logging handler
|
|
61
73
|
stream_handler = logging.StreamHandler()
|
|
62
74
|
stream_handler.setFormatter(formatter)
|
|
75
|
+
stream_handler.addFilter(module_name_filter)
|
|
63
76
|
handlers.append(stream_handler)
|
|
64
77
|
|
|
65
78
|
# create file logging handler, if log file is given
|
|
@@ -70,10 +83,30 @@ class Application:
|
|
|
70
83
|
else:
|
|
71
84
|
file_handler = logging.handlers.WatchedFileHandler(log_file)
|
|
72
85
|
|
|
73
|
-
# add log file handler
|
|
74
86
|
file_handler.setFormatter(formatter)
|
|
87
|
+
file_handler.addFilter(module_name_filter)
|
|
75
88
|
handlers.append(file_handler)
|
|
76
89
|
|
|
90
|
+
# systemd journal handler?
|
|
91
|
+
if syslog:
|
|
92
|
+
from logging_journald import JournaldLogHandler # type: ignore[import-untyped]
|
|
93
|
+
|
|
94
|
+
class PyobsJournaldLogHandler(JournaldLogHandler): # type: ignore[misc]
|
|
95
|
+
"""JournaldLogHandler that adds SYSLOG_IDENTIFIER=pyobs and PYOBS_MODULE per record."""
|
|
96
|
+
|
|
97
|
+
def __init__(self, **kw: Any) -> None:
|
|
98
|
+
super().__init__(identifier="pyobs", **kw)
|
|
99
|
+
|
|
100
|
+
def _format_record(self, record: logging.LogRecord) -> list[tuple[str, Any]]:
|
|
101
|
+
pairs: list[tuple[str, Any]] = super()._format_record(record)
|
|
102
|
+
pairs.append(("PYOBS_MODULE", getattr(record, "pyobs_module", "")))
|
|
103
|
+
return pairs
|
|
104
|
+
|
|
105
|
+
journal_handler = PyobsJournaldLogHandler()
|
|
106
|
+
journal_handler.setFormatter(journal_formatter)
|
|
107
|
+
journal_handler.addFilter(module_name_filter)
|
|
108
|
+
handlers.append(journal_handler)
|
|
109
|
+
|
|
77
110
|
# influx handler?
|
|
78
111
|
if influx_log is not None:
|
|
79
112
|
from pyobs.utils.influxdb import InfluxHandler
|
|
@@ -91,7 +124,12 @@ class Application:
|
|
|
91
124
|
|
|
92
125
|
# set pyobs logger
|
|
93
126
|
global log
|
|
127
|
+
from pathlib import Path
|
|
128
|
+
|
|
129
|
+
from pyobs.utils.logging.context import module_name
|
|
130
|
+
|
|
94
131
|
log = logging.getLogger(__name__)
|
|
132
|
+
module_name.set(Path(self._config).stem)
|
|
95
133
|
|
|
96
134
|
# load config
|
|
97
135
|
log.info("Loading configuration from %s...", self._config)
|
|
@@ -102,8 +140,17 @@ class Application:
|
|
|
102
140
|
class_name = cfg["class"]
|
|
103
141
|
klass = get_class_from_string(class_name)
|
|
104
142
|
|
|
105
|
-
# create event loop
|
|
106
|
-
|
|
143
|
+
# create event loop — if top-level class doesn't override new_event_loop,
|
|
144
|
+
# check child modules for one that does (e.g. pyobs_gui.GUI in a MultiModule)
|
|
145
|
+
loop_class = klass
|
|
146
|
+
if klass.new_event_loop is Module.new_event_loop:
|
|
147
|
+
for mod_cfg in cfg.get("modules", {}).values():
|
|
148
|
+
if isinstance(mod_cfg, dict) and "class" in mod_cfg:
|
|
149
|
+
child_klass = get_class_from_string(mod_cfg["class"])
|
|
150
|
+
if child_klass.new_event_loop is not Module.new_event_loop:
|
|
151
|
+
loop_class = child_klass
|
|
152
|
+
break
|
|
153
|
+
self._loop = loop_class.new_event_loop()
|
|
107
154
|
asyncio.set_event_loop(self._loop)
|
|
108
155
|
|
|
109
156
|
# create module and open it
|
|
@@ -137,9 +184,6 @@ class Application:
|
|
|
137
184
|
def _signal_handler(self, sig: int) -> None:
|
|
138
185
|
"""React to signals and quit the module."""
|
|
139
186
|
|
|
140
|
-
# stop loop
|
|
141
|
-
# loop = asyncio.get_running_loop()
|
|
142
|
-
# loop.stop()
|
|
143
187
|
self._module.quit()
|
|
144
188
|
|
|
145
189
|
# reset signal handlers
|
|
@@ -27,6 +27,13 @@ class BackgroundTask:
|
|
|
27
27
|
self._task = asyncio.create_task(self._func_wrapper())
|
|
28
28
|
|
|
29
29
|
async def _func_wrapper(self) -> None:
|
|
30
|
+
# stamp the module name into the context var so all logging within this task
|
|
31
|
+
# (and any tasks it spawns) carries the correct PYOBS_MODULE field
|
|
32
|
+
from pyobs.utils.logging.context import module_name as _module_name_var
|
|
33
|
+
|
|
34
|
+
if hasattr(self._parent, "name"):
|
|
35
|
+
_module_name_var.set(self._parent.name)
|
|
36
|
+
|
|
30
37
|
start = time.time()
|
|
31
38
|
finish_count = 0
|
|
32
39
|
|
|
@@ -41,6 +41,12 @@ class PyobsCLI(CLI):
|
|
|
41
41
|
self._parser.add_argument(
|
|
42
42
|
"-l", "--log-file", type=str, help="file to write log into", default=self._config.get("log_file", None)
|
|
43
43
|
)
|
|
44
|
+
self._parser.add_argument(
|
|
45
|
+
"--syslog",
|
|
46
|
+
action="store_true",
|
|
47
|
+
help="send log to systemd journal",
|
|
48
|
+
default=self._config.get("syslog", False),
|
|
49
|
+
)
|
|
44
50
|
self._parser.add_argument(
|
|
45
51
|
"--influx-log",
|
|
46
52
|
type=str,
|
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import functools
|
|
4
5
|
import inspect
|
|
5
6
|
import logging
|
|
7
|
+
import sys
|
|
6
8
|
from collections.abc import Callable, Coroutine
|
|
7
|
-
from typing import TYPE_CHECKING, Any,
|
|
9
|
+
from typing import TYPE_CHECKING, Any, overload
|
|
8
10
|
|
|
9
11
|
import pyobs.interfaces
|
|
10
12
|
from pyobs.events import Event, LogEvent, ModuleClosedEvent
|
|
11
13
|
from pyobs.interfaces import Interface
|
|
14
|
+
from pyobs.utils.enums import ModuleState
|
|
12
15
|
|
|
13
16
|
from .commlogging import CommLoggingHandler
|
|
14
|
-
from .proxy import Proxy
|
|
17
|
+
from .proxy import Proxy, ProxyType, _ProxyContext
|
|
15
18
|
|
|
16
19
|
if TYPE_CHECKING:
|
|
17
20
|
from pyobs.modules import Module
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
StateCallback = Callable[[Any], None]
|
|
23
|
+
PresenceCallback = Callable[["ModuleState", str], None]
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
log = logging.getLogger(__name__)
|
|
23
26
|
|
|
24
27
|
|
|
25
28
|
class Comm:
|
|
@@ -27,13 +30,13 @@ class Comm:
|
|
|
27
30
|
|
|
28
31
|
__module__ = "pyobs.comm"
|
|
29
32
|
|
|
30
|
-
def __init__(self
|
|
33
|
+
def __init__(self) -> None:
|
|
31
34
|
"""Creates a comm module."""
|
|
32
35
|
|
|
33
36
|
self._proxies: dict[str, Proxy] = {}
|
|
37
|
+
self._state_subscriptions: dict[str, list[tuple[type[Interface], StateCallback]]] = {}
|
|
34
38
|
self._module: Module | None = None
|
|
35
39
|
self._log_queue: asyncio.Queue[LogEvent] = asyncio.Queue()
|
|
36
|
-
self._cache_proxies = cache_proxies
|
|
37
40
|
self._logging_task: asyncio.Task[Any] | None = None
|
|
38
41
|
self._event_handlers: dict[type[Event], list[Callable[[Event, str], Coroutine[Any, Any, bool]]]] = {}
|
|
39
42
|
self._closing = asyncio.Event()
|
|
@@ -64,9 +67,14 @@ class Comm:
|
|
|
64
67
|
"""Open module."""
|
|
65
68
|
|
|
66
69
|
# add handler to global logger
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
root_logger = logging.getLogger()
|
|
71
|
+
if not any(isinstance(h, CommLoggingHandler) for h in root_logger.handlers):
|
|
72
|
+
from pyobs.utils.logging.context import ModuleNameFilter
|
|
73
|
+
|
|
74
|
+
handler = CommLoggingHandler(self)
|
|
75
|
+
handler.setLevel(logging.INFO)
|
|
76
|
+
handler.addFilter(ModuleNameFilter())
|
|
77
|
+
root_logger.addHandler(handler)
|
|
70
78
|
|
|
71
79
|
# start logging thread
|
|
72
80
|
self._logging_task = asyncio.create_task(self._logging())
|
|
@@ -117,7 +125,7 @@ class Comm:
|
|
|
117
125
|
return None
|
|
118
126
|
|
|
119
127
|
# if client doesn't exist or we disabled caching, fetch a new proxy
|
|
120
|
-
if client not in self._proxies
|
|
128
|
+
if client not in self._proxies:
|
|
121
129
|
# get interfaces
|
|
122
130
|
try:
|
|
123
131
|
interfaces = await self.get_interfaces(client)
|
|
@@ -126,18 +134,20 @@ class Comm:
|
|
|
126
134
|
|
|
127
135
|
# create new proxy
|
|
128
136
|
proxy = Proxy(self, client, interfaces)
|
|
137
|
+
|
|
138
|
+
# subscribe to state
|
|
139
|
+
for interface in interfaces:
|
|
140
|
+
if getattr(interface, "State", None) is not None:
|
|
141
|
+
await self.subscribe_state(client, interface, functools.partial(proxy.update_state, interface))
|
|
142
|
+
|
|
129
143
|
self._proxies[client] = proxy
|
|
130
144
|
|
|
131
145
|
# return proxy
|
|
132
146
|
return self._proxies[client]
|
|
133
147
|
|
|
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:
|
|
148
|
+
async def _resolve_proxy(
|
|
149
|
+
self, name_or_object: str | object, obj_type: type[ProxyType] | None = None
|
|
150
|
+
) -> Any | ProxyType:
|
|
141
151
|
"""Returns object directly if it is of given type. Otherwise get proxy of client with given name and check type.
|
|
142
152
|
|
|
143
153
|
If name_or_object is an object:
|
|
@@ -184,16 +194,41 @@ class Comm:
|
|
|
184
194
|
# completely wrong...
|
|
185
195
|
raise ValueError(f'Given parameter is neither a name nor an object of requested type "{obj_type}".')
|
|
186
196
|
|
|
187
|
-
async def
|
|
197
|
+
async def _safe_resolve_proxy(
|
|
188
198
|
self, name_or_object: str | object, obj_type: type[ProxyType] | None = None
|
|
189
199
|
) -> Any | ProxyType | None:
|
|
190
200
|
"""Calls proxy() in a safe way and returns None instead of raising an exception."""
|
|
191
201
|
|
|
192
202
|
try:
|
|
193
|
-
return await self.
|
|
203
|
+
return await self._resolve_proxy(name_or_object, obj_type)
|
|
194
204
|
except ValueError:
|
|
195
205
|
return None
|
|
196
206
|
|
|
207
|
+
@overload
|
|
208
|
+
def proxy(self, name_or_object: str | object, obj_type: type[ProxyType]) -> _ProxyContext[ProxyType]: ...
|
|
209
|
+
@overload
|
|
210
|
+
def proxy(self, name_or_object: str | object, obj_type: None = None) -> _ProxyContext[Any]: ...
|
|
211
|
+
|
|
212
|
+
def proxy(self, name_or_object: str | object, obj_type: type[ProxyType] | None = None) -> _ProxyContext[Any]:
|
|
213
|
+
"""Returns a context manager; use as `async with self.proxy(...) as x:`."""
|
|
214
|
+
return _ProxyContext(self._resolve_proxy(name_or_object, obj_type))
|
|
215
|
+
|
|
216
|
+
@overload
|
|
217
|
+
def safe_proxy(
|
|
218
|
+
self, name_or_object: str | object, obj_type: type[ProxyType]
|
|
219
|
+
) -> _ProxyContext[ProxyType | None]: ...
|
|
220
|
+
@overload
|
|
221
|
+
def safe_proxy(self, name_or_object: str | object, obj_type: None = None) -> _ProxyContext[Any]: ...
|
|
222
|
+
|
|
223
|
+
def safe_proxy(self, name_or_object: str | object, obj_type: type[ProxyType] | None = None) -> _ProxyContext[Any]:
|
|
224
|
+
"""Same as proxy(), but yields None inside the block instead of raising."""
|
|
225
|
+
return _ProxyContext(self._safe_resolve_proxy(name_or_object, obj_type))
|
|
226
|
+
|
|
227
|
+
async def has_proxy(self, name_or_object: str | object, obj_type: type[Any] | None = None) -> bool:
|
|
228
|
+
"""True if a proxy of the given type can currently be resolved. Doesn't keep a reference
|
|
229
|
+
to it, so doesn't need async with the way proxy()/safe_proxy() do."""
|
|
230
|
+
return await self._safe_resolve_proxy(name_or_object, obj_type) is not None
|
|
231
|
+
|
|
197
232
|
async def _client_disconnected(self, event: Event, sender: str) -> bool:
|
|
198
233
|
"""Called when a client disconnects.
|
|
199
234
|
|
|
@@ -203,9 +238,15 @@ class Comm:
|
|
|
203
238
|
|
|
204
239
|
"""
|
|
205
240
|
|
|
206
|
-
# if a client disconnects,
|
|
241
|
+
# if a client disconnects, clear its proxy state then evict it
|
|
207
242
|
if sender in self._proxies:
|
|
243
|
+
self._proxies[sender].clear_state()
|
|
208
244
|
del self._proxies[sender]
|
|
245
|
+
|
|
246
|
+
# tear down any state subscriptions held for that client
|
|
247
|
+
for interface, callback in self._state_subscriptions.pop(sender, []):
|
|
248
|
+
await self.unsubscribe_state(sender, interface, callback)
|
|
249
|
+
|
|
209
250
|
return True
|
|
210
251
|
|
|
211
252
|
@property
|
|
@@ -397,6 +438,143 @@ class Comm:
|
|
|
397
438
|
) -> None:
|
|
398
439
|
pass
|
|
399
440
|
|
|
441
|
+
async def set_state(self, interface: type[Interface], state: Any) -> None:
|
|
442
|
+
"""Publish state for this module.
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
interface: Interface type for the state.
|
|
446
|
+
state: State object to publish.
|
|
447
|
+
"""
|
|
448
|
+
await self._set_state(interface, state)
|
|
449
|
+
|
|
450
|
+
async def _set_state(self, interface: type[Interface], state: Any) -> None:
|
|
451
|
+
pass
|
|
452
|
+
|
|
453
|
+
@staticmethod
|
|
454
|
+
def _interface_from_capabilities(caps_cls: type) -> type:
|
|
455
|
+
outer_name = caps_cls.__qualname__.rsplit(".", 1)[0]
|
|
456
|
+
return getattr(sys.modules[caps_cls.__module__], outer_name)
|
|
457
|
+
|
|
458
|
+
async def set_capabilities(self, capabilities: Any) -> None:
|
|
459
|
+
"""Publish capabilities for this module.
|
|
460
|
+
|
|
461
|
+
Called by Module.open() for each interface that defines a Capabilities
|
|
462
|
+
dataclass. Not intended to be called directly by module authors after
|
|
463
|
+
that point — capabilities are fixed for the module lifetime.
|
|
464
|
+
|
|
465
|
+
Args:
|
|
466
|
+
capabilities: Capabilities dataclass instance.
|
|
467
|
+
"""
|
|
468
|
+
interface = Comm._interface_from_capabilities(type(capabilities))
|
|
469
|
+
await self._set_capabilities(interface, capabilities)
|
|
470
|
+
|
|
471
|
+
async def _set_capabilities(self, interface: type[Interface], capabilities: Any) -> None:
|
|
472
|
+
pass
|
|
473
|
+
|
|
474
|
+
async def get_capabilities(self, module: str, interface: type[Interface]) -> Any | None:
|
|
475
|
+
"""Fetch and deserialize capabilities for a remote module's interface.
|
|
476
|
+
|
|
477
|
+
Args:
|
|
478
|
+
module: Module name (e.g. "camera").
|
|
479
|
+
interface: Interface class whose Capabilities dataclass to fetch.
|
|
480
|
+
|
|
481
|
+
Returns:
|
|
482
|
+
Deserialized Capabilities dataclass instance, or None if not published.
|
|
483
|
+
"""
|
|
484
|
+
return await self._get_capabilities(module, interface)
|
|
485
|
+
|
|
486
|
+
async def _get_capabilities(self, module: str, interface: type[Interface]) -> Any | None:
|
|
487
|
+
return None
|
|
488
|
+
|
|
489
|
+
async def set_presence(self, state: ModuleState, error_string: str = "") -> None:
|
|
490
|
+
"""Publish presence for this module (module lifecycle state).
|
|
491
|
+
|
|
492
|
+
Called automatically by Module.set_state — not intended to be called
|
|
493
|
+
directly by module authors.
|
|
494
|
+
|
|
495
|
+
Args:
|
|
496
|
+
state: Current module lifecycle state.
|
|
497
|
+
error_string: Error message, used when state is ERROR.
|
|
498
|
+
"""
|
|
499
|
+
await self._set_presence(state, error_string)
|
|
500
|
+
|
|
501
|
+
async def _set_presence(self, state: ModuleState, error_string: str = "") -> None:
|
|
502
|
+
pass
|
|
503
|
+
|
|
504
|
+
def get_client_state(self, module: str) -> tuple[ModuleState, str] | None:
|
|
505
|
+
"""Return the last known presence state of a connected module.
|
|
506
|
+
|
|
507
|
+
Returns (ModuleState, error_string) or None if the module is not connected.
|
|
508
|
+
This replaces the old get_state()/get_error_string() RPC pattern.
|
|
509
|
+
"""
|
|
510
|
+
return self._get_client_state(module)
|
|
511
|
+
|
|
512
|
+
def _get_client_state(self, module: str) -> tuple[ModuleState, str] | None:
|
|
513
|
+
return None
|
|
514
|
+
|
|
515
|
+
async def subscribe_state(
|
|
516
|
+
self,
|
|
517
|
+
module: str,
|
|
518
|
+
interface: type[Interface],
|
|
519
|
+
callback: StateCallback,
|
|
520
|
+
) -> None:
|
|
521
|
+
"""Subscribe to state updates for a given module and interface.
|
|
522
|
+
|
|
523
|
+
Delivers the current value immediately on subscribe.
|
|
524
|
+
|
|
525
|
+
Args:
|
|
526
|
+
module: Name of remote module.
|
|
527
|
+
interface: Interface type to subscribe to.
|
|
528
|
+
callback: Called with state object on each update.
|
|
529
|
+
"""
|
|
530
|
+
self._state_subscriptions.setdefault(module, []).append((interface, callback))
|
|
531
|
+
await self._subscribe_state(module, interface, callback)
|
|
532
|
+
|
|
533
|
+
async def _subscribe_state(
|
|
534
|
+
self,
|
|
535
|
+
module: str,
|
|
536
|
+
interface: type[Interface],
|
|
537
|
+
callback: StateCallback,
|
|
538
|
+
) -> None:
|
|
539
|
+
pass
|
|
540
|
+
|
|
541
|
+
async def unsubscribe_state(
|
|
542
|
+
self,
|
|
543
|
+
module: str,
|
|
544
|
+
interface: type[Interface],
|
|
545
|
+
callback: StateCallback,
|
|
546
|
+
) -> None:
|
|
547
|
+
"""Unsubscribe from state updates.
|
|
548
|
+
|
|
549
|
+
Args:
|
|
550
|
+
module: Name of remote module.
|
|
551
|
+
interface: Interface type to unsubscribe from.
|
|
552
|
+
callback: Callback that was registered.
|
|
553
|
+
"""
|
|
554
|
+
await self._unsubscribe_state(module, interface, callback)
|
|
555
|
+
|
|
556
|
+
async def _unsubscribe_state(
|
|
557
|
+
self,
|
|
558
|
+
module: str,
|
|
559
|
+
interface: type[Interface],
|
|
560
|
+
callback: StateCallback,
|
|
561
|
+
) -> None:
|
|
562
|
+
pass
|
|
563
|
+
|
|
564
|
+
async def subscribe_presence(self, module: str, callback: PresenceCallback) -> None:
|
|
565
|
+
"""Subscribe to presence updates for a given module.
|
|
566
|
+
|
|
567
|
+
Delivers the current value immediately, then on every change.
|
|
568
|
+
|
|
569
|
+
Args:
|
|
570
|
+
module: Name of remote module.
|
|
571
|
+
callback: Called with (ModuleState, error_string) on each update.
|
|
572
|
+
"""
|
|
573
|
+
await self._subscribe_presence(module, callback)
|
|
574
|
+
|
|
575
|
+
async def _subscribe_presence(self, module: str, callback: PresenceCallback) -> None:
|
|
576
|
+
pass
|
|
577
|
+
|
|
400
578
|
def _send_event_to_module(self, event: Event, from_client: str) -> None:
|
|
401
579
|
"""Send an event to all connected modules.
|
|
402
580
|
|
|
@@ -34,9 +34,12 @@ class CommLoggingHandler(logging.Handler):
|
|
|
34
34
|
# format message
|
|
35
35
|
msg = self._formatter.format(rec) # noqa: UP031
|
|
36
36
|
|
|
37
|
-
# create and send event
|
|
37
|
+
# create and send event — use pyobs_module if set (MultiModule context)
|
|
38
38
|
time = datetime.fromtimestamp(rec.created, tz=UTC).strftime("%Y-%m-%dT%H:%M:%S.%f")
|
|
39
|
-
|
|
39
|
+
sender = getattr(rec, "pyobs_module", "") or ""
|
|
40
|
+
entry = LogEvent(
|
|
41
|
+
time, rec.levelname, os.path.basename(rec.pathname), rec.funcName, rec.lineno, msg, sender=sender
|
|
42
|
+
)
|
|
40
43
|
self._comm.log_message(entry)
|
|
41
44
|
|
|
42
45
|
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Coroutine
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from pyobs.comm import Comm
|
|
7
|
+
from pyobs.comm.comm import PresenceCallback
|
|
8
|
+
from pyobs.events import Event
|
|
9
|
+
from pyobs.interfaces import Interface
|
|
10
|
+
from pyobs.utils.enums import ModuleState
|
|
11
|
+
from pyobs.utils.types import cast_response_to_real
|
|
12
|
+
|
|
13
|
+
from .localnetwork import LocalNetwork
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class LocalComm(Comm):
|
|
17
|
+
def __init__(self, name: str, *args: Any, **kwargs: Any):
|
|
18
|
+
Comm.__init__(self, *args, **kwargs)
|
|
19
|
+
|
|
20
|
+
self._name = name
|
|
21
|
+
self._network = LocalNetwork()
|
|
22
|
+
self._network.connect_client(self)
|
|
23
|
+
|
|
24
|
+
# in-memory state and capabilities storage
|
|
25
|
+
self._states: dict[str, Any] = {} # node -> state object
|
|
26
|
+
self._state_handlers: dict[str, list[tuple[type[Interface], Callable[[Any], None]]]] = {}
|
|
27
|
+
self._capabilities: dict[type[Interface], Any] = {} # interface -> Capabilities object
|
|
28
|
+
self._presence: tuple[ModuleState, str] = (ModuleState.READY, "")
|
|
29
|
+
self._presence_callbacks: dict[str, list[PresenceCallback]] = {}
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def name(self) -> str:
|
|
33
|
+
"""Name of this client."""
|
|
34
|
+
return self._name
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def clients(self) -> list[str]:
|
|
38
|
+
"""Returns list of currently connected clients."""
|
|
39
|
+
return self._network.get_client_names()
|
|
40
|
+
|
|
41
|
+
async def get_interfaces(self, client: str) -> list[type[Interface]]:
|
|
42
|
+
"""Returns list of interfaces for given client."""
|
|
43
|
+
remote_client = self._network.get_client(client)
|
|
44
|
+
return [] if not remote_client.has_module else remote_client.module.interfaces
|
|
45
|
+
|
|
46
|
+
async def _supports_interface(self, client: str, interface: type[Interface]) -> bool:
|
|
47
|
+
"""Checks whether the given client supports the given interface."""
|
|
48
|
+
interfaces = await self.get_interfaces(client)
|
|
49
|
+
return interface in interfaces
|
|
50
|
+
|
|
51
|
+
async def execute(self, client: str, method: str, annotation: dict[str, Any], *args: Any) -> Any:
|
|
52
|
+
"""Execute a given method on a remote client."""
|
|
53
|
+
remote_client = self._network.get_client(client)
|
|
54
|
+
if remote_client.module is None:
|
|
55
|
+
raise ValueError
|
|
56
|
+
simple_results = await remote_client.module.execute(method, *args, sender=self.name)
|
|
57
|
+
real_results = cast_response_to_real(
|
|
58
|
+
simple_results, annotation["return"], self.cast_to_real_pre, self.cast_to_real_post
|
|
59
|
+
)
|
|
60
|
+
return real_results
|
|
61
|
+
|
|
62
|
+
async def send_event(self, event: Event) -> None:
|
|
63
|
+
"""Send an event to other clients."""
|
|
64
|
+
from pyobs.events import LogEvent as _LogEvent
|
|
65
|
+
|
|
66
|
+
sender = self.name
|
|
67
|
+
if isinstance(event, _LogEvent) and event.sender:
|
|
68
|
+
sender = event.sender
|
|
69
|
+
remote_clients = self._network.get_clients()
|
|
70
|
+
for client in remote_clients:
|
|
71
|
+
client._send_event_to_module(event, sender)
|
|
72
|
+
|
|
73
|
+
async def _register_events(
|
|
74
|
+
self, events: list[type[Event]], handler: Callable[[Event, str], Coroutine[Any, Any, bool]] | None = None
|
|
75
|
+
) -> None:
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
# -------------------------------------------------------------------------
|
|
79
|
+
# State
|
|
80
|
+
# -------------------------------------------------------------------------
|
|
81
|
+
|
|
82
|
+
async def _set_state(self, interface: type[Interface], state: Any) -> None:
|
|
83
|
+
"""Publish state locally and dispatch to subscribers."""
|
|
84
|
+
node = f"pyobs:state:{self._name}:{interface.__name__}:{interface.version}"
|
|
85
|
+
self._states[node] = state
|
|
86
|
+
|
|
87
|
+
# dispatch to all subscribers for this node
|
|
88
|
+
if node in self._state_handlers:
|
|
89
|
+
for _, callback in self._state_handlers[node]:
|
|
90
|
+
callback(state)
|
|
91
|
+
|
|
92
|
+
async def _subscribe_state(self, module: str, interface: type[Interface], callback: Callable[[Any], None]) -> None:
|
|
93
|
+
"""Subscribe to state updates from a remote module."""
|
|
94
|
+
node = f"pyobs:state:{module}:{interface.__name__}:{interface.version}"
|
|
95
|
+
|
|
96
|
+
if node not in self._state_handlers:
|
|
97
|
+
self._state_handlers[node] = []
|
|
98
|
+
self._state_handlers[node].append((interface, callback))
|
|
99
|
+
|
|
100
|
+
# also register on the remote comm so it can dispatch to us
|
|
101
|
+
try:
|
|
102
|
+
remote = self._network.get_client(module)
|
|
103
|
+
if node not in remote._state_handlers:
|
|
104
|
+
remote._state_handlers[node] = []
|
|
105
|
+
remote._state_handlers[node].append((interface, callback))
|
|
106
|
+
|
|
107
|
+
# deliver current value immediately if available
|
|
108
|
+
if node in remote._states:
|
|
109
|
+
callback(remote._states[node])
|
|
110
|
+
except KeyError:
|
|
111
|
+
pass # remote not connected yet
|
|
112
|
+
|
|
113
|
+
# -------------------------------------------------------------------------
|
|
114
|
+
# Capabilities
|
|
115
|
+
# -------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
async def _set_capabilities(self, interface: type[Interface], capabilities: Any) -> None:
|
|
118
|
+
"""Store capabilities locally."""
|
|
119
|
+
self._capabilities[interface] = capabilities
|
|
120
|
+
|
|
121
|
+
async def _get_capabilities(self, module: str, interface: type[Interface]) -> Any | None:
|
|
122
|
+
"""Fetch capabilities from a remote module."""
|
|
123
|
+
if not hasattr(interface, "Capabilities"):
|
|
124
|
+
return None
|
|
125
|
+
try:
|
|
126
|
+
remote = self._network.get_client(module)
|
|
127
|
+
return remote._capabilities.get(interface)
|
|
128
|
+
except KeyError:
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
# -------------------------------------------------------------------------
|
|
132
|
+
# Presence
|
|
133
|
+
# -------------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
async def _set_presence(self, state: ModuleState, error_string: str = "") -> None:
|
|
136
|
+
"""Store presence state and dispatch to all subscribers."""
|
|
137
|
+
self._presence = (state, error_string)
|
|
138
|
+
for client in self._network.get_clients():
|
|
139
|
+
for cb in client._presence_callbacks.get(self._name, []):
|
|
140
|
+
cb(state, error_string)
|
|
141
|
+
|
|
142
|
+
def _get_client_state(self, module: str) -> tuple[ModuleState, str] | None:
|
|
143
|
+
"""Return presence state of a connected module."""
|
|
144
|
+
try:
|
|
145
|
+
remote = self._network.get_client(module)
|
|
146
|
+
return remote._presence
|
|
147
|
+
except KeyError:
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
async def _subscribe_presence(self, module: str, callback: PresenceCallback) -> None:
|
|
151
|
+
"""Register a presence callback and deliver the current state immediately."""
|
|
152
|
+
self._presence_callbacks.setdefault(module, []).append(callback)
|
|
153
|
+
try:
|
|
154
|
+
remote = self._network.get_client(module)
|
|
155
|
+
callback(*remote._presence)
|
|
156
|
+
except KeyError:
|
|
157
|
+
pass
|