pyobs-core 2.0.0.dev23__tar.gz → 2.0.0.dev26__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-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/PKG-INFO +1 -1
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/comm.py +12 -9
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/proxy.py +29 -1
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/xmppclient.py +1 -1
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/xmppcomm.py +25 -11
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/image.py +41 -1
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/calibration/_ccddata_calibrator.py +2 -8
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/misc/circularmask.py +21 -14
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/projected.py +3 -11
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/ICamera.py +1 -2
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IDataSequence.py +8 -2
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/ISpectrograph.py +1 -2
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/mixins/camerasettings.py +5 -1
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/camera/basecamera.py +22 -4
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/camera/basespectrograph.py +1 -1
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/camera/pipelinecamera.py +2 -11
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/robotic/scheduler.py +9 -2
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/telescope/basetelescope.py +12 -2
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/scripts/script.py +7 -1
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/task.py +6 -3
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/task.py +7 -2
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/fits.py +42 -15
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/pipeline/pipeline.py +2 -21
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/time.py +4 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyproject.toml +1 -1
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/.gitignore +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/LICENSE +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/application.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/background_task.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/cli/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/cli/_cli.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/cli/pyobs.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/cli/pyobsd.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/cli/pyobsw.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/commlogging.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/dummy/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/dummy/dummycomm.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/local/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/local/localcomm.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/local/localnetwork.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/rpc.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/serializer.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/badweather.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/event.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/exposurestatuschanged.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/filterchanged.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/focusfound.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/goodweather.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/log.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/modechanged.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/moduleclosed.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/moduleopened.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/motionstatuschanged.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/move.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/newimage.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/newspectrum.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/offsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/roofclosing.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/roofopened.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/taskfailed.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/taskfinished.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/taskstarted.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/events/testevent.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/meta/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/meta/altazoffsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/meta/exptime.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/meta/genericoffset.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/meta/onskydistance.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/meta/pixeloffsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/meta/radecoffsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/meta/skyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processor.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/_daobackgroundremover.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/annotation/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/annotation/_pillow.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/annotation/circle.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/annotation/crosshair.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/annotation/text.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/astrometry/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/astrometry/astrometry.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/astrometry/dotnet.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/calibration/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/calibration/calibration.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/detection/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/detection/_source_catalog.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/detection/daophot.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/detection/pysep.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/detection/simpledisk.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/detection/sourcedetection.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/exptime/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/exptime/exptime.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/exptime/star.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/image/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/image/addfitsheaders.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/image/download.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/image/flip.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/image/grayscale.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/image/httpserver.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/image/normalize.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/image/save.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/image/saveimage.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/image/smooth.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/image/softbin.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/misc/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/misc/addmask.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/misc/createfilename.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/misc/removebackground.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/modules/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/modules/getfitsheaders.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/astrometry.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/brighteststar.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/fitsheader.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/offsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/spilled_light.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/photometry/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/photometry/photometry.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/photometry/photutil.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/photometry/pysep.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/wcs/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IAbortable.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IAcquisition.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IAutoFocus.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IAutoGuiding.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IAutonomous.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IBinning.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/ICalibrate.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IConfig.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/ICooling.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IData.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IDome.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IExposure.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IExposureTime.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IFilters.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IFlatField.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IFocusModel.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IFocuser.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IGain.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IImageFormat.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IImageType.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IMode.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IModule.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IMotion.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IMultiFiber.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IOffsetsAltAz.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IOffsetsRaDec.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IPointingAltAz.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IPointingBody.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IPointingHeliocentricPolar.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IPointingHeliographicStonyhurst.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IPointingHelioprojective.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IPointingOrbitalElements.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IPointingRaDec.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IPointingSeries.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IReady.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IRoof.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IRotation.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IRunnable.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IRunning.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IScriptRunner.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IStartStop.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IStructuredConfig.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/ISyncTarget.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/ITelescope.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/ITemperatures.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/ITrackingMode.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/ITrackingRate.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IVideo.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IWeather.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/IWindow.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/interfaces/interface.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/mixins/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/mixins/fitsheader.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/mixins/fitsnamespace.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/mixins/follow.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/mixins/motionstatus.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/mixins/pipeline.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/mixins/waitformotion.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/mixins/weatheraware.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/camera/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/camera/adaptive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/camera/basevideo.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/camera/dummycamera.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/camera/dummyspectrograph.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/camera/dummyvideo.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/flatfield/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/flatfield/flatfield.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/flatfield/pointing.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/flatfield/scheduler.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/focus/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/focus/dummyautofocus.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/focus/focusmodel.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/focus/focusseries.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/image/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/image/imagewatcher.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/image/imagewriter.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/image/pipeline.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/image/seeing.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/module.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/_base.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/_baseguiding.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/acquisition.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/autoguiding.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/dummyacquisition.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/dummyguiding.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/pointing/scienceframeguiding.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/robotic/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/robotic/mastermind.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/robotic/pointing.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/robotic/scriptrunner.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/roof/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/roof/basedome.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/roof/baseroof.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/roof/dummyroof.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/telescope/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/telescope/_dummytelescopebase.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/telescope/dummyaltaztelescope.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/telescope/dummyradectelescope.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/telescope/dummysolartelescope.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/test/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/test/standalone.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/utils/dummymode.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/utils/fluentlogger.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/utils/httpfilecache.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/utils/kiosk.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/utils/matrix.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/utils/stellarium.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/utils/telegram.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/utils/trigger.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/weather/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/weather/mockweather.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/weather/weather.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/weather/weather_api.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/modules/weather/weather_state.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/object.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/py.typed +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/observation.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/dataprovider.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/merits/constant.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/merits/follow.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/merits/interval.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/merits/merit.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/merits/random.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/merits/transit.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/ondemandscheduler.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/targets/heliocentricpolartarget.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/targets/helioprojectivetarget.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/targets/target.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/calibration/darkbias.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/calibration/pointing.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/calibration/skyflats.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/control/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/control/cases.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/control/conditional.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/control/parallel.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/control/selector.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/control/sequential.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/imaging/autofocus.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/imaging/imaging.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/script.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/utils/callmodule.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/scripts/utils/log.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/backend/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/backend/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/backend/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/_portal.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/configdb.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/scripts/autofocus.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/scripts/default.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/memory/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/taskrunner.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/archive/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/archive/archive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/archive/local_archive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/exptime/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/exptime/exptime.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/exptime/stellarexptime.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/skyflats/flatfielder.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/average.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/cache.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/config.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/config_schema.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/coordinates.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/curvefit.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/enums.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/exceptions.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/focusseries/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/focusseries/base.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/focusseries/photometry.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/focusseries/projection.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/grids/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/grids/filters.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/grids/grid.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/grids/gridnode.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/grids/pipeline.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/gui/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/gui/camera/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/gui/camera/binningwidget.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/gui/camera/exposewidget.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/http.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/influxdb.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/logger.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/logging/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/logging/context.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/logging/resolvableerror.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/modulegui.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/offsets/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/offsets/applyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/parallel.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/pipeline/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/pipeline/night.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/publisher/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/publisher/csv.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/publisher/http.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/publisher/log.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/publisher/multi.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/publisher/publisher.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/serialization.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/shellcommand.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/threads/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/threads/lockwithabort.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/utils/units.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/version.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/archivefile.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/bufferedfile.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/file.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/filelists/__init__.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/filelists/filelist.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/filelists/testing.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/httpfile.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/localfile.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/memfile.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/sftpfile.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/smbfile.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/sshfile.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/tempfile.py +0 -0
- {pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/vfs/vfs.py +0 -0
|
@@ -133,16 +133,14 @@ class Comm:
|
|
|
133
133
|
except IndexError:
|
|
134
134
|
return None
|
|
135
135
|
|
|
136
|
-
#
|
|
137
|
-
|
|
136
|
+
# create new proxy
|
|
137
|
+
proxy = Proxy(self, client, interfaces)
|
|
138
|
+
|
|
139
|
+
# fetch capabilities in the background, so a peer that isn't fully up yet doesn't block
|
|
140
|
+
# proxy construction -- Proxy.wait_for_capabilities() can be used to wait for the result
|
|
138
141
|
for interface in interfaces:
|
|
139
142
|
if interface.capabilities is not None:
|
|
140
|
-
|
|
141
|
-
if cap is not None:
|
|
142
|
-
capabilities[interface] = cap
|
|
143
|
-
|
|
144
|
-
# create new proxy
|
|
145
|
-
proxy = Proxy(self, client, interfaces, capabilities)
|
|
143
|
+
asyncio.create_task(self._fetch_and_update_capabilities(client, interface, proxy))
|
|
146
144
|
|
|
147
145
|
# subscribe to state
|
|
148
146
|
for interface in interfaces:
|
|
@@ -151,9 +149,14 @@ class Comm:
|
|
|
151
149
|
|
|
152
150
|
self._proxies[client] = proxy
|
|
153
151
|
|
|
154
|
-
# return proxy
|
|
155
152
|
return self._proxies[client]
|
|
156
153
|
|
|
154
|
+
async def _fetch_and_update_capabilities(self, client: str, interface: type[Interface], proxy: Proxy) -> None:
|
|
155
|
+
"""Fetch capabilities for a single interface and push them into the given proxy once available."""
|
|
156
|
+
cap = await self._get_capabilities(client, interface)
|
|
157
|
+
if cap is not None:
|
|
158
|
+
proxy.update_capabilities(interface, cap)
|
|
159
|
+
|
|
157
160
|
async def _resolve_proxy(
|
|
158
161
|
self, name_or_object: str | object, obj_type: type[ProxyType] | None = None
|
|
159
162
|
) -> Any | ProxyType:
|
|
@@ -62,6 +62,7 @@ class Proxy:
|
|
|
62
62
|
# store state and capabilities
|
|
63
63
|
self._state: dict[type[Interface], Any] = {}
|
|
64
64
|
self._capabilities: dict[type[Interface], Any] = capabilities if capabilities is not None else {}
|
|
65
|
+
self._capabilities_events: dict[type[Interface], asyncio.Event] = {}
|
|
65
66
|
|
|
66
67
|
@property
|
|
67
68
|
def name(self) -> str:
|
|
@@ -175,8 +176,18 @@ class Proxy:
|
|
|
175
176
|
"""Latest known state for the given interface, or None if nothing has arrived yet."""
|
|
176
177
|
return self._state.get(interface)
|
|
177
178
|
|
|
179
|
+
def update_capabilities(self, interface: type[Interface], capabilities: Any) -> None:
|
|
180
|
+
"""Called by Comm once capabilities for an interface arrive.
|
|
181
|
+
|
|
182
|
+
Not intended to be called directly by module code.
|
|
183
|
+
"""
|
|
184
|
+
self._capabilities[interface] = capabilities
|
|
185
|
+
event = self._capabilities_events.get(interface)
|
|
186
|
+
if event is not None:
|
|
187
|
+
event.set()
|
|
188
|
+
|
|
178
189
|
def get_capabilities(self, interface: type[Interface]) -> Any | None:
|
|
179
|
-
"""Capabilities for the given interface,
|
|
190
|
+
"""Capabilities for the given interface, or None if not (yet) fetched."""
|
|
180
191
|
return self._capabilities.get(interface)
|
|
181
192
|
|
|
182
193
|
async def wait_for_state(
|
|
@@ -203,6 +214,23 @@ class Proxy:
|
|
|
203
214
|
|
|
204
215
|
return self._state.get(interface)
|
|
205
216
|
|
|
217
|
+
async def wait_for_capabilities(
|
|
218
|
+
self,
|
|
219
|
+
interface: type[Interface],
|
|
220
|
+
timeout: float = 10.0,
|
|
221
|
+
) -> Any | None:
|
|
222
|
+
"""Return capabilities immediately if available, otherwise wait for the background fetch to complete."""
|
|
223
|
+
if self._capabilities.get(interface) is not None:
|
|
224
|
+
return self._capabilities[interface]
|
|
225
|
+
|
|
226
|
+
event = self._capabilities_events.setdefault(interface, asyncio.Event())
|
|
227
|
+
try:
|
|
228
|
+
await asyncio.wait_for(event.wait(), timeout=timeout)
|
|
229
|
+
except TimeoutError:
|
|
230
|
+
pass
|
|
231
|
+
|
|
232
|
+
return self._capabilities.get(interface)
|
|
233
|
+
|
|
206
234
|
|
|
207
235
|
class _ProxyContext(Generic[ProxyType]):
|
|
208
236
|
"""Returned by Comm.proxy() / Object.proxy() / Comm.safe_proxy(). Must be used as:
|
|
@@ -48,7 +48,7 @@ class XmppClient(slixmpp.ClientXMPP):
|
|
|
48
48
|
self.register_plugin("xep_0199") # XMPP Ping
|
|
49
49
|
|
|
50
50
|
# enable keep alive pings
|
|
51
|
-
self["xep_0199"].enable_keepalive()
|
|
51
|
+
self.plugin["xep_0199"].enable_keepalive()
|
|
52
52
|
|
|
53
53
|
# handle session_start and message events
|
|
54
54
|
self.add_event_handler("session_start", self.session_start)
|
|
@@ -909,20 +909,34 @@ class XmppComm(Comm):
|
|
|
909
909
|
return self._capabilities.get(interface)
|
|
910
910
|
|
|
911
911
|
async def _get_capabilities(self, module: str, interface: type[Interface]) -> Any | None:
|
|
912
|
-
"""Fetch and deserialize capabilities for a remote module's interface.
|
|
912
|
+
"""Fetch and deserialize capabilities for a remote module's interface.
|
|
913
|
+
|
|
914
|
+
Retries a few times, since this may run right as the peer is still starting up and hasn't
|
|
915
|
+
published its capabilities yet.
|
|
916
|
+
"""
|
|
913
917
|
if interface.capabilities is None:
|
|
914
918
|
return None
|
|
915
|
-
# Use full JID (with resource) if we know it — bare JID may not route correctly
|
|
916
|
-
full_jid = next(
|
|
917
|
-
(jid for jid in self._online_clients if jid.startswith(f"{module}@")),
|
|
918
|
-
f"{module}@{self._domain}",
|
|
919
|
-
)
|
|
920
|
-
jid = full_jid
|
|
921
919
|
ns = f"urn:pyobs:capabilities:{interface.__name__}:{interface.version}"
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
920
|
+
|
|
921
|
+
result = None
|
|
922
|
+
last_error: BaseException | None = None
|
|
923
|
+
for attempt in range(3):
|
|
924
|
+
# Use full JID (with resource) if we know it — bare JID may not route correctly
|
|
925
|
+
full_jid = next(
|
|
926
|
+
(jid for jid in self._online_clients if jid.startswith(f"{module}@")),
|
|
927
|
+
f"{module}@{self._domain}",
|
|
928
|
+
)
|
|
929
|
+
try:
|
|
930
|
+
result = await asyncio.wait_for(
|
|
931
|
+
self.client.plugin["xep_0030"].get_info(jid=JID(full_jid)), timeout=10.0
|
|
932
|
+
)
|
|
933
|
+
break
|
|
934
|
+
except (TimeoutError, Exception) as e:
|
|
935
|
+
last_error = e
|
|
936
|
+
if attempt < 2:
|
|
937
|
+
await asyncio.sleep(2)
|
|
938
|
+
else:
|
|
939
|
+
log.warning("Failed to get capabilities for %s from %s: %s", interface.__name__, module, last_error)
|
|
926
940
|
return None
|
|
927
941
|
log.debug("get_capabilities disco result XML: %s", ET.tostring(result.xml).decode()[:500])
|
|
928
942
|
# result.xml is the <iq> — the <query> is its child, capabilities are grandchildren
|
|
@@ -13,7 +13,7 @@ from astropy.table import Table
|
|
|
13
13
|
from numpy.typing import NDArray
|
|
14
14
|
|
|
15
15
|
import pyobs.utils.exceptions as exc
|
|
16
|
-
from pyobs.utils.fits import FilenameFormatter
|
|
16
|
+
from pyobs.utils.fits import FilenameFormatter, parse_section_bounds
|
|
17
17
|
|
|
18
18
|
MetaClass = TypeVar("MetaClass")
|
|
19
19
|
|
|
@@ -378,6 +378,46 @@ class Image:
|
|
|
378
378
|
unit="adu",
|
|
379
379
|
)
|
|
380
380
|
|
|
381
|
+
def trim(self) -> Image:
|
|
382
|
+
"""Return a copy of this image cropped to its TRIMSEC header, if present.
|
|
383
|
+
|
|
384
|
+
If no TRIMSEC is set, returns an unmodified copy. CRPIX1/CRPIX2 are shifted to
|
|
385
|
+
account for the new origin if present. TRIMSEC/DATASEC/BIASSEC are removed from
|
|
386
|
+
the result's header, since none remain valid coordinates into the trimmed data.
|
|
387
|
+
|
|
388
|
+
Raises:
|
|
389
|
+
ValueError: If TRIMSEC is malformed, or a catalog is already attached (its
|
|
390
|
+
pixel coordinates would silently go stale against the trimmed frame).
|
|
391
|
+
"""
|
|
392
|
+
|
|
393
|
+
if self._catalog is not None:
|
|
394
|
+
raise ValueError("Cannot trim an image with an attached catalog.")
|
|
395
|
+
|
|
396
|
+
bounds = parse_section_bounds(self._header, "TRIMSEC")
|
|
397
|
+
trimmed = self.copy()
|
|
398
|
+
if bounds is None:
|
|
399
|
+
return trimmed
|
|
400
|
+
|
|
401
|
+
x0, x1, y0, y1 = bounds
|
|
402
|
+
trimmed._data = None if self._data is None else self._data[y0:y1, x0:x1]
|
|
403
|
+
trimmed._mask = None if self._mask is None else self._mask[y0:y1, x0:x1]
|
|
404
|
+
trimmed._uncertainty = None if self._uncertainty is None else self._uncertainty[y0:y1, x0:x1]
|
|
405
|
+
|
|
406
|
+
if trimmed._data is not None:
|
|
407
|
+
trimmed._header["NAXIS1"] = trimmed._data.shape[1]
|
|
408
|
+
trimmed._header["NAXIS2"] = trimmed._data.shape[0]
|
|
409
|
+
|
|
410
|
+
if "CRPIX1" in trimmed._header:
|
|
411
|
+
trimmed._header["CRPIX1"] -= x0
|
|
412
|
+
if "CRPIX2" in trimmed._header:
|
|
413
|
+
trimmed._header["CRPIX2"] -= y0
|
|
414
|
+
|
|
415
|
+
for keyword in ("TRIMSEC", "DATASEC", "BIASSEC"):
|
|
416
|
+
if keyword in trimmed._header:
|
|
417
|
+
del trimmed._header[keyword]
|
|
418
|
+
|
|
419
|
+
return trimmed
|
|
420
|
+
|
|
381
421
|
def format_filename(self, formatter: FilenameFormatter) -> str:
|
|
382
422
|
"""Format filename with given formatter."""
|
|
383
423
|
self._header["FNAME"] = formatter(self._header)
|
|
@@ -4,17 +4,16 @@ import astropy.units as u
|
|
|
4
4
|
from astropy.nddata import CCDData
|
|
5
5
|
|
|
6
6
|
from pyobs.images import Image
|
|
7
|
-
from pyobs.utils.pipeline import Pipeline
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
class _CCDDataCalibrator:
|
|
11
10
|
def __init__(self, image: Image, bias: Image | None = None, dark: Image | None = None, flat: Image | None = None):
|
|
12
|
-
self._image = image
|
|
11
|
+
self._image = image.trim()
|
|
13
12
|
self._bias = self._optional_to_ccddata(bias)
|
|
14
13
|
self._dark = self._optional_to_ccddata(dark)
|
|
15
14
|
self._flat = self._optional_to_ccddata(flat)
|
|
16
15
|
|
|
17
|
-
self._ccd_data =
|
|
16
|
+
self._ccd_data = self._image.to_ccddata()
|
|
18
17
|
|
|
19
18
|
if dark is not None:
|
|
20
19
|
self._dark_exp_time = dark.header["EXPTIME"]
|
|
@@ -26,16 +25,11 @@ class _CCDDataCalibrator:
|
|
|
26
25
|
return image.to_ccddata()
|
|
27
26
|
|
|
28
27
|
def __call__(self) -> Image:
|
|
29
|
-
self._trim_image()
|
|
30
|
-
|
|
31
28
|
calibrated_ccd_data = self._calibrate_image()
|
|
32
29
|
|
|
33
30
|
calibrated = Image.from_ccddata(calibrated_ccd_data)
|
|
34
31
|
return calibrated
|
|
35
32
|
|
|
36
|
-
def _trim_image(self) -> None:
|
|
37
|
-
self._ccd_data = Pipeline.trim_ccddata(self._ccd_data)
|
|
38
|
-
|
|
39
33
|
def _calibrate_image(self) -> CCDData:
|
|
40
34
|
import ccdproc
|
|
41
35
|
|
{pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/misc/circularmask.py
RENAMED
|
@@ -17,8 +17,9 @@ class CircularMask(ImageProcessor):
|
|
|
17
17
|
|
|
18
18
|
This processor reads the circle center from two FITS header keywords
|
|
19
19
|
(e.g., CRPIX1/CRPIX2) and constructs a circular mask in pixel coordinates. Pixels
|
|
20
|
-
outside the circle are
|
|
21
|
-
|
|
20
|
+
outside the circle are flagged in ``image.mask``; pixel data are left untouched. Any
|
|
21
|
+
pre-existing mask on the image is combined (logical OR) with the new one rather than
|
|
22
|
+
being overwritten.
|
|
22
23
|
|
|
23
24
|
:param float radius: Radius of the circular pass region in pixels. Pixels with
|
|
24
25
|
squared distance to the center less than or equal to
|
|
@@ -33,17 +34,19 @@ class CircularMask(ImageProcessor):
|
|
|
33
34
|
--------
|
|
34
35
|
- Reads the circle center from ``image.header[center[0]]`` and
|
|
35
36
|
``image.header[center[1]]``.
|
|
36
|
-
- Builds a boolean
|
|
37
|
-
``
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
- Builds a boolean mask on the 2D pixel grid that is ``True`` outside the circle
|
|
38
|
+
and ``False`` inside it (boundary inclusive), and assigns it to a copy of the
|
|
39
|
+
image's ``mask``. If the image already has a mask, the new mask is combined with
|
|
40
|
+
it via logical OR instead of replacing it.
|
|
41
|
+
- Returns a copy of the image with the updated mask; pixel data, header, and
|
|
40
42
|
catalog are not changed.
|
|
41
43
|
|
|
42
44
|
Input/Output
|
|
43
45
|
------------
|
|
44
46
|
- Input: :class:`pyobs.images.Image` with 2D pixel data and FITS header containing
|
|
45
47
|
the specified center keywords.
|
|
46
|
-
- Output: :class:`pyobs.images.Image` with
|
|
48
|
+
- Output: :class:`pyobs.images.Image` (copied) with pixels outside the circle
|
|
49
|
+
marked in ``mask``; pixel data are unchanged.
|
|
47
50
|
|
|
48
51
|
Configuration (YAML)
|
|
49
52
|
--------------------
|
|
@@ -70,8 +73,6 @@ class CircularMask(ImageProcessor):
|
|
|
70
73
|
ensure consistency to avoid off-by-one shifts.
|
|
71
74
|
- The implementation operates on 2D images. Multi-plane/color images are not
|
|
72
75
|
supported by this processor as written.
|
|
73
|
-
- Masking is performed in place; if you need to preserve the original image data,
|
|
74
|
-
copy the image before applying this processor.
|
|
75
76
|
"""
|
|
76
77
|
|
|
77
78
|
__module__ = "pyobs.images.processors.misc"
|
|
@@ -90,13 +91,13 @@ class CircularMask(ImageProcessor):
|
|
|
90
91
|
self._radius = radius
|
|
91
92
|
|
|
92
93
|
async def __call__(self, image: Image) -> Image:
|
|
93
|
-
"""
|
|
94
|
+
"""Mask everything outside the given radius from the image.
|
|
94
95
|
|
|
95
96
|
Args:
|
|
96
97
|
image: Image to mask.
|
|
97
98
|
|
|
98
99
|
Returns:
|
|
99
|
-
|
|
100
|
+
Image with pixels outside the circle marked in its mask.
|
|
100
101
|
"""
|
|
101
102
|
|
|
102
103
|
center_x, center_y = image.header[self._center[0]], image.header[self._center[1]]
|
|
@@ -105,10 +106,16 @@ class CircularMask(ImageProcessor):
|
|
|
105
106
|
x, y = np.arange(0, nx), np.arange(0, ny)
|
|
106
107
|
x_coordinates, y_coordinates = np.meshgrid(x, y)
|
|
107
108
|
|
|
108
|
-
|
|
109
|
+
outside_circle = (x_coordinates - center_x) ** 2 + (y_coordinates - center_y) ** 2 > self._radius**2
|
|
110
|
+
outside_circle = outside_circle.transpose()
|
|
109
111
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
output_image = image.copy()
|
|
113
|
+
if output_image.safe_mask is not None:
|
|
114
|
+
output_image.mask = np.logical_or(output_image.mask, outside_circle)
|
|
115
|
+
else:
|
|
116
|
+
output_image.mask = outside_circle
|
|
117
|
+
|
|
118
|
+
return output_image
|
|
112
119
|
|
|
113
120
|
|
|
114
121
|
__all__ = ["CircularMask"]
|
{pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/images/processors/offsets/projected.py
RENAMED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
import re
|
|
3
2
|
from typing import Any, cast
|
|
4
3
|
|
|
5
4
|
import numpy as np
|
|
@@ -9,6 +8,7 @@ from scipy.optimize import fmin
|
|
|
9
8
|
|
|
10
9
|
from pyobs.images import Image
|
|
11
10
|
from pyobs.images.meta import PixelOffsets
|
|
11
|
+
from pyobs.utils.fits import fitssec
|
|
12
12
|
|
|
13
13
|
from .offsets import Offsets
|
|
14
14
|
|
|
@@ -155,16 +155,8 @@ class ProjectedOffsets(Offsets):
|
|
|
155
155
|
Projected images.
|
|
156
156
|
"""
|
|
157
157
|
|
|
158
|
-
#
|
|
159
|
-
data
|
|
160
|
-
|
|
161
|
-
# trimsec
|
|
162
|
-
if "TRIMSEC" in hdr:
|
|
163
|
-
m = re.match(r"\[([0-9]+):([0-9]+),([0-9]+):([0-9]+)\]", hdr["TRIMSEC"])
|
|
164
|
-
if m is None:
|
|
165
|
-
raise ValueError("Invalid trimsec.")
|
|
166
|
-
x0, x1, y0, y1 = [int(f) for f in m.groups()]
|
|
167
|
-
data = data[y0 - 1 : y1, x0 - 1 : x1]
|
|
158
|
+
# trim to trimsec, if set
|
|
159
|
+
data = fitssec(image)
|
|
168
160
|
|
|
169
161
|
# collapse
|
|
170
162
|
sum_x = np.nansum(data, 0)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from abc import ABCMeta
|
|
2
2
|
|
|
3
3
|
from .IData import IData
|
|
4
|
-
from .IExposure import IExposure
|
|
5
4
|
|
|
6
5
|
|
|
7
|
-
class ICamera(IData,
|
|
6
|
+
class ICamera(IData, metaclass=ABCMeta):
|
|
8
7
|
"""The module controls a camera."""
|
|
9
8
|
|
|
10
9
|
__module__ = "pyobs.interfaces"
|
|
@@ -2,8 +2,9 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from abc import ABCMeta, abstractmethod
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Annotated, Any
|
|
6
6
|
|
|
7
|
+
from ..utils.enums import Unit
|
|
7
8
|
from ..utils.time import Time
|
|
8
9
|
from .IAbortable import IAbortable
|
|
9
10
|
|
|
@@ -23,13 +24,18 @@ class IDataSequence(IAbortable, metaclass=ABCMeta):
|
|
|
23
24
|
state = DataSequenceState
|
|
24
25
|
|
|
25
26
|
@abstractmethod
|
|
26
|
-
async def grab_sequence(
|
|
27
|
+
async def grab_sequence(
|
|
28
|
+
self, count: int, broadcast: bool = True, delay: Annotated[float, Unit.SECONDS] = 0, **kwargs: Any
|
|
29
|
+
) -> None:
|
|
27
30
|
"""Start a sequence of `count` grabs. Returns immediately; progress is available via
|
|
28
31
|
the pushed DataSequenceState.
|
|
29
32
|
|
|
30
33
|
Args:
|
|
31
34
|
count: Number of grabs to take.
|
|
32
35
|
broadcast: Broadcast existence of each grab.
|
|
36
|
+
delay: Seconds to wait between the end of one grab and the start of the next.
|
|
37
|
+
Does not apply after the last grab. Skipped early if the sequence is aborted
|
|
38
|
+
during the wait.
|
|
33
39
|
|
|
34
40
|
Raises:
|
|
35
41
|
GrabImageError: If the device is already busy (exposing or already running a
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from abc import ABCMeta
|
|
2
2
|
|
|
3
3
|
from .IData import IData
|
|
4
|
-
from .IExposure import IExposure
|
|
5
4
|
|
|
6
5
|
|
|
7
|
-
class ISpectrograph(IData,
|
|
6
|
+
class ISpectrograph(IData, metaclass=ABCMeta):
|
|
8
7
|
"""The module controls a camera."""
|
|
9
8
|
|
|
10
9
|
__module__ = "pyobs.interfaces"
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
from typing import Any, cast
|
|
5
5
|
|
|
6
|
+
from pyobs.comm.proxy import Proxy
|
|
6
7
|
from pyobs.interfaces import IBinning, IData, IFilters, IWindow
|
|
7
8
|
from pyobs.modules import Module
|
|
8
9
|
|
|
@@ -54,7 +55,10 @@ class CameraSettingsMixin:
|
|
|
54
55
|
await camera.set_binning(self.__camerasettings_binning, self.__camerasettings_binning)
|
|
55
56
|
if isinstance(camera, IWindow):
|
|
56
57
|
log.info("Set window to full frame...")
|
|
57
|
-
|
|
58
|
+
if isinstance(camera, Proxy):
|
|
59
|
+
cap = await camera.wait_for_capabilities(IWindow)
|
|
60
|
+
else:
|
|
61
|
+
cap = camera.get_capabilities(IWindow)
|
|
58
62
|
if cap is not None:
|
|
59
63
|
await camera.set_window(cap.full_frame_x, cap.full_frame_y, cap.full_frame_width, cap.full_frame_height)
|
|
60
64
|
else:
|
|
@@ -46,7 +46,9 @@ async def calc_expose_timeout(camera: BaseCamera, *args: Any, **kwargs: Any) ->
|
|
|
46
46
|
return camera._exposure_time + 30
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
class BaseCamera(
|
|
49
|
+
class BaseCamera(
|
|
50
|
+
Module, ImageFitsHeaderMixin, ICamera, IExposure, IExposureTime, IImageType, IDataSequence, metaclass=ABCMeta
|
|
51
|
+
):
|
|
50
52
|
"""Base class for all camera modules."""
|
|
51
53
|
|
|
52
54
|
__module__ = "pyobs.modules.camera"
|
|
@@ -108,6 +110,7 @@ class BaseCamera(Module, ImageFitsHeaderMixin, ICamera, IExposureTime, IImageTyp
|
|
|
108
110
|
# (also between individual grabs, while _camera_status is briefly IDLE again)
|
|
109
111
|
self._sequence_count_left = 0
|
|
110
112
|
self._sequence_task: asyncio.Task[None] | None = None
|
|
113
|
+
self._sequence_delay_abort = asyncio.Event()
|
|
111
114
|
|
|
112
115
|
# register exception
|
|
113
116
|
exc.register_exception(exc.GrabImageError, 3, timespan=600, callback=self._default_remote_error_callback)
|
|
@@ -370,19 +373,23 @@ class BaseCamera(Module, ImageFitsHeaderMixin, ICamera, IExposureTime, IImageTyp
|
|
|
370
373
|
# return filename
|
|
371
374
|
return filename
|
|
372
375
|
|
|
373
|
-
async def grab_sequence(self, count: int, broadcast: bool = True, **kwargs: Any) -> None:
|
|
376
|
+
async def grab_sequence(self, count: int, broadcast: bool = True, delay: float = 0, **kwargs: Any) -> None:
|
|
374
377
|
"""Start a sequence of `count` images. Returns immediately; progress is available via
|
|
375
378
|
the pushed DataSequenceState.
|
|
376
379
|
|
|
377
380
|
Args:
|
|
378
381
|
count: Number of images to take.
|
|
379
382
|
broadcast: Broadcast existence of each image.
|
|
383
|
+
delay: Seconds to wait between the end of one image and the start of the next.
|
|
384
|
+
Does not apply after the last image.
|
|
380
385
|
|
|
381
386
|
Raises:
|
|
382
387
|
CameraException: If camera is already busy (exposing or already running a sequence).
|
|
383
388
|
"""
|
|
384
389
|
if count < 1:
|
|
385
390
|
raise ValueError("count must be >= 1.")
|
|
391
|
+
if delay < 0:
|
|
392
|
+
raise ValueError("delay must be >= 0.")
|
|
386
393
|
|
|
387
394
|
# already running a sequence, or mid-exposure outside of one?
|
|
388
395
|
if self._sequence_count_left > 0 or self._camera_status != ExposureStatus.IDLE:
|
|
@@ -391,9 +398,9 @@ class BaseCamera(Module, ImageFitsHeaderMixin, ICamera, IExposureTime, IImageTyp
|
|
|
391
398
|
log.info("Starting sequence of %d images...", count)
|
|
392
399
|
self._sequence_count_left = count
|
|
393
400
|
await self.comm.set_state(IDataSequence, DataSequenceState(count_total=count, count_left=count))
|
|
394
|
-
self._sequence_task = asyncio.create_task(self._run_sequence(count, broadcast))
|
|
401
|
+
self._sequence_task = asyncio.create_task(self._run_sequence(count, broadcast, delay))
|
|
395
402
|
|
|
396
|
-
async def _run_sequence(self, count_total: int, broadcast: bool) -> None:
|
|
403
|
+
async def _run_sequence(self, count_total: int, broadcast: bool, delay: float) -> None:
|
|
397
404
|
"""Runs a sequence of grab_data() calls, started by grab_sequence()."""
|
|
398
405
|
try:
|
|
399
406
|
while self._sequence_count_left > 0:
|
|
@@ -406,6 +413,15 @@ class BaseCamera(Module, ImageFitsHeaderMixin, ICamera, IExposureTime, IImageTyp
|
|
|
406
413
|
await self.comm.set_state(
|
|
407
414
|
IDataSequence, DataSequenceState(count_total=count_total, count_left=self._sequence_count_left)
|
|
408
415
|
)
|
|
416
|
+
|
|
417
|
+
# wait between images, unless this was the last one or the sequence was
|
|
418
|
+
# aborted in the meantime -- either abort_sequence() or abort() cuts this short
|
|
419
|
+
if self._sequence_count_left > 0 and delay > 0:
|
|
420
|
+
self._sequence_delay_abort.clear()
|
|
421
|
+
try:
|
|
422
|
+
await asyncio.wait_for(self._sequence_delay_abort.wait(), timeout=delay)
|
|
423
|
+
except TimeoutError:
|
|
424
|
+
pass
|
|
409
425
|
finally:
|
|
410
426
|
log.info("Finished sequence.")
|
|
411
427
|
self._sequence_count_left = 0
|
|
@@ -418,6 +434,7 @@ class BaseCamera(Module, ImageFitsHeaderMixin, ICamera, IExposureTime, IImageTyp
|
|
|
418
434
|
"""
|
|
419
435
|
log.info("Aborting sequence after current image...")
|
|
420
436
|
self._sequence_count_left = 0
|
|
437
|
+
self._sequence_delay_abort.set()
|
|
421
438
|
|
|
422
439
|
async def _abort_exposure(self) -> None:
|
|
423
440
|
"""Abort the running exposure. Should be implemented by derived class.
|
|
@@ -438,6 +455,7 @@ class BaseCamera(Module, ImageFitsHeaderMixin, ICamera, IExposureTime, IImageTyp
|
|
|
438
455
|
log.info("Aborting current image and sequence...")
|
|
439
456
|
self.expose_abort.set()
|
|
440
457
|
self._sequence_count_left = 0
|
|
458
|
+
self._sequence_delay_abort.set()
|
|
441
459
|
|
|
442
460
|
# do camera-specific abort
|
|
443
461
|
await self._abort_exposure()
|
|
@@ -23,7 +23,7 @@ class ExposureInfo(NamedTuple):
|
|
|
23
23
|
start: datetime
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
class BaseSpectrograph(Module, SpectrumFitsHeaderMixin, ISpectrograph, metaclass=ABCMeta):
|
|
26
|
+
class BaseSpectrograph(Module, SpectrumFitsHeaderMixin, ISpectrograph, IExposure, metaclass=ABCMeta):
|
|
27
27
|
"""Base class for all spectrograph modules."""
|
|
28
28
|
|
|
29
29
|
__module__ = "pyobs.modules.camera"
|
|
@@ -3,11 +3,11 @@ from typing import Any
|
|
|
3
3
|
|
|
4
4
|
from pyobs.events import NewImageEvent
|
|
5
5
|
from pyobs.images import Image
|
|
6
|
-
from pyobs.interfaces import
|
|
6
|
+
from pyobs.interfaces import ICamera
|
|
7
7
|
from pyobs.mixins import ImageFitsHeaderMixin
|
|
8
8
|
from pyobs.mixins.pipeline import PipelineMixin
|
|
9
9
|
from pyobs.modules import Module
|
|
10
|
-
from pyobs.utils.enums import
|
|
10
|
+
from pyobs.utils.enums import ImageType
|
|
11
11
|
from pyobs.utils.exceptions import GrabImageError
|
|
12
12
|
|
|
13
13
|
log = logging.getLogger(__name__)
|
|
@@ -24,15 +24,6 @@ class PipelineCamera(Module, ICamera, ImageFitsHeaderMixin, PipelineMixin):
|
|
|
24
24
|
PipelineMixin.__init__(self, **kwargs)
|
|
25
25
|
ImageFitsHeaderMixin.__init__(self, **kwargs)
|
|
26
26
|
|
|
27
|
-
async def open(self) -> None:
|
|
28
|
-
"""Open module."""
|
|
29
|
-
await Module.open(self)
|
|
30
|
-
|
|
31
|
-
# publish initial state
|
|
32
|
-
await self.comm.set_state(
|
|
33
|
-
IExposure, ExposureState(status=ExposureStatus.IDLE, progress=0.0, exposure_time_left=0.0)
|
|
34
|
-
)
|
|
35
|
-
|
|
36
27
|
async def grab_data(self, broadcast: bool = True, **kwargs: Any) -> str:
|
|
37
28
|
"""Grabs an image and returns reference.
|
|
38
29
|
|
|
@@ -281,14 +281,21 @@ class Scheduler(Module, IStartStop, IRunnable):
|
|
|
281
281
|
# sleep a little
|
|
282
282
|
await asyncio.sleep(1)
|
|
283
283
|
|
|
284
|
-
|
|
285
|
-
|
|
284
|
+
def _log_scheduled_task(self, scheduled_tasks: ObservationList) -> None:
|
|
285
|
+
try:
|
|
286
|
+
observer = self._scheduler.observer
|
|
287
|
+
except AttributeError:
|
|
288
|
+
observer = None
|
|
286
289
|
for scheduled_task in scheduled_tasks:
|
|
287
290
|
msg = f" - {scheduled_task.start.strftime('%H:%M:%S')} to {scheduled_task.end.strftime('%H:%M:%S')}: "
|
|
288
291
|
msg += f"{scheduled_task.task.name} ({scheduled_task.task.id}"
|
|
289
292
|
if scheduled_task.priority is not None:
|
|
290
293
|
msg += f", priority: {scheduled_task.priority}"
|
|
291
294
|
msg += ")"
|
|
295
|
+
if scheduled_task.target is not None and observer is not None:
|
|
296
|
+
start = Time(scheduled_task.start)
|
|
297
|
+
altaz = observer.altaz(start, scheduled_task.target.coordinates(start))
|
|
298
|
+
msg += f" [{scheduled_task.target.name}: alt={altaz.alt.degree:.1f}°, airmass={float(altaz.secz):.2f}]"
|
|
292
299
|
log.info(msg)
|
|
293
300
|
|
|
294
301
|
async def run(self, **kwargs: Any) -> None:
|
|
@@ -308,7 +308,14 @@ class BaseTelescope(
|
|
|
308
308
|
|
|
309
309
|
# check altitude
|
|
310
310
|
if alt_az.alt.degree < self._min_altitude:
|
|
311
|
-
raise ValueError(
|
|
311
|
+
raise ValueError(
|
|
312
|
+
f"Destination altitude below limit: alt={alt_az.alt.degree:.2f}° "
|
|
313
|
+
f"az={alt_az.az.degree:.2f}° (min={self._min_altitude:.2f}°) for "
|
|
314
|
+
f"ra={ra:.5f}° dec={dec:.5f}° at {Time.now().isot} from "
|
|
315
|
+
f"lon={self.observer.location.lon.degree:.4f}° "
|
|
316
|
+
f"lat={self.observer.location.lat.degree:.4f}° "
|
|
317
|
+
f"height={self.observer.location.height.value:.1f}m."
|
|
318
|
+
)
|
|
312
319
|
|
|
313
320
|
# acquire lock
|
|
314
321
|
async with LockWithAbort(self._lock_moving, self._abort_move):
|
|
@@ -382,7 +389,10 @@ class BaseTelescope(
|
|
|
382
389
|
|
|
383
390
|
# check altitude
|
|
384
391
|
if alt < self._min_altitude:
|
|
385
|
-
raise ValueError(
|
|
392
|
+
raise ValueError(
|
|
393
|
+
f"Destination altitude below limit: alt={alt:.2f}° az={az:.2f}° "
|
|
394
|
+
f"(min={self._min_altitude:.2f}°) at {Time.now().isot}."
|
|
395
|
+
)
|
|
386
396
|
|
|
387
397
|
# acquire lock
|
|
388
398
|
async with LockWithAbort(self._lock_moving, self._abort_move):
|
{pyobs_core-2.0.0.dev23 → pyobs_core-2.0.0.dev26}/pyobs/robotic/storage/lco/scripts/script.py
RENAMED
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
from typing import TYPE_CHECKING, Any
|
|
5
5
|
|
|
6
|
+
from pydantic import PrivateAttr
|
|
7
|
+
|
|
6
8
|
from pyobs.interfaces import FitsHeaderEntry
|
|
7
9
|
from pyobs.robotic.scripts import Script
|
|
8
10
|
from pyobs.robotic.storage.lco._portal import LcoRequest
|
|
@@ -24,6 +26,8 @@ class LcoScript(Script):
|
|
|
24
26
|
request: LcoRequest
|
|
25
27
|
scripts: dict[str, dict[str, Any]] = {}
|
|
26
28
|
|
|
29
|
+
_running_script: Script | None = PrivateAttr(default=None)
|
|
30
|
+
|
|
27
31
|
def _create_script(self) -> Script:
|
|
28
32
|
"""Build the script selected via the configuration's extra_params["script_name"].
|
|
29
33
|
|
|
@@ -55,6 +59,7 @@ class LcoScript(Script):
|
|
|
55
59
|
InterruptedError: If interrupted
|
|
56
60
|
"""
|
|
57
61
|
script = self._create_script()
|
|
62
|
+
self._running_script = script
|
|
58
63
|
try:
|
|
59
64
|
await script.run(data)
|
|
60
65
|
finally:
|
|
@@ -69,7 +74,8 @@ class LcoScript(Script):
|
|
|
69
74
|
Returns:
|
|
70
75
|
Dictionary containing FITS headers.
|
|
71
76
|
"""
|
|
72
|
-
|
|
77
|
+
script = self._running_script if self._running_script is not None else self._create_script()
|
|
78
|
+
return script.get_fits_headers(namespaces)
|
|
73
79
|
|
|
74
80
|
def estimate_duration(self, data: TaskData | None = None, time: Time | None = None) -> float:
|
|
75
81
|
"""Estimate duration based on the duration calculated by the LCO portal."""
|