pyobs-core 2.20.0__tar.gz → 2.22.0__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.20.0 → pyobs_core-2.22.0}/PKG-INFO +1 -1
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/application.py +18 -2
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/comm.py +7 -4
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/rpc.py +31 -10
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/__init__.py +2 -0
- pyobs_core-2.22.0/pyobs/events/newdata.py +47 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/newimage.py +7 -10
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/newspectrum.py +7 -14
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IMotion.py +2 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/fitsheader.py +1 -1
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/follow.py +1 -1
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/__init__.py +2 -0
- pyobs_core-2.22.0/pyobs/modules/camera/basedata.py +73 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/basespectrograph.py +5 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/module.py +7 -4
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/mastermind.py +37 -24
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/pointing.py +1 -1
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/basetelescope.py +116 -5
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/exceptions.py +12 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/shellcommand.py +1 -1
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyproject.toml +1 -1
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/.gitignore +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/LICENSE +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/README.md +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/background_task.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/cli/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/cli/_cli.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/cli/pyobs.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/cli/pyobsd.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/cli/pyobsw.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/commlogging.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/dummy/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/dummy/dummycomm.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/local/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/local/localcomm.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/local/localnetwork.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/proxy.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/serializer.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xmppclient.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/comm/xmpp/xmppcomm.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/badweather.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/event.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/exposurestatuschanged.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/filewritten.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/filterchanged.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/focusfound.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/goodweather.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/log.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/modechanged.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/moduleclosed.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/moduleopened.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/motionstatuschanged.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/move.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/offsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/roofclosing.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/roofopened.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/taskfailed.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/taskfinished.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/taskskipped.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/taskstarted.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/events/testevent.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/image.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/altazoffsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/datapipeline.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/exptime.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/genericoffset.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/onskydistance.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/pixeloffsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/radecoffsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/meta/skyoffsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processor.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/_daobackgroundremover.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/annotation/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/annotation/_pillow.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/annotation/circle.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/annotation/crosshair.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/annotation/text.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/astrometry.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/astrometry/dotnet.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/calibration/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/calibration/calibration.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/_source_catalog.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/daophot.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/pysep.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/simpledisk.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/detection/sourcedetection.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/exptime/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/exptime/exptime.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/exptime/star.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/addfitsheaders.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/download.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/flip.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/grayscale.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/httpserver.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/normalize.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/save.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/saveimage.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/smooth.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/image/softbin.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/addmask.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/circularmask.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/createfilename.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/misc/removebackground.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/modules/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/modules/getfitsheaders.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/astrometry.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/brighteststar.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/fitsheader.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/offsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/projected.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/offsets/spilled_light.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/photometry.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/photutil.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/photometry/pysep.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/combinestack.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/mean.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/median.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/sigmaclip.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/stack/sum.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/wcs/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IAbortable.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IAcquisition.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IAutoFocus.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IAutoGuiding.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IAutonomous.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IBinning.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ICalibrate.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ICamera.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IConfig.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ICooling.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IData.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IDataPipeline.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IDataSequence.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IDataStack.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IDome.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IExposure.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IExposureTime.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFilters.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFlatField.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFocusModel.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IFocuser.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IGain.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IImageFormat.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IImageType.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IMode.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IModule.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IMultiFiber.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IOffsetsAltAz.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IOffsetsRaDec.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingAltAz.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingBody.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingHeliocentricPolar.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingHeliographicStonyhurst.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingHelioprojective.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingOrbitalElements.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingRaDec.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPointingSeries.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IPushNotifications.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IReady.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IResettable.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRobotic.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRoboticScheduler.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRoof.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRotation.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRunnable.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IRunning.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IScriptRunner.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ISpectrograph.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IStartStop.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IStructuredConfig.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ISyncTarget.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ITelescope.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ITemperatures.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ITrackingMode.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/ITrackingRate.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IVideo.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IWeather.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/IWindow.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/interfaces/interface.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/camerasettings.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/datapipeline.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/datasequence.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/fitsnamespace.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/motionstatus.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/pipeline.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/waitformotion.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/mixins/weatheraware.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/adaptive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/basecamera.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/basevideo.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/dummycamera.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/dummyspectrograph.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/dummyvideo.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/pipelinecamera.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/camera/videoframes.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/flatfield/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/flatfield/flatfield.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/flatfield/pointing.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/flatfield/scheduler.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/focus/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/focus/dummyautofocus.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/focus/focusmodel.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/focus/focusseries.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/image/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/image/imagewatcher.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/image/imagewriter.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/image/pipeline.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/image/seeing.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/_base.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/_baseguiding.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/acquisition.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/autoguiding.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/dummyacquisition.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/dummyguiding.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingsource.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/pointing/scienceframeguiding.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/dummymastermind.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/dummyscheduler.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/scheduler.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/robotic/scriptrunner.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/roof/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/roof/basedome.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/roof/baseroof.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/roof/dummyroof.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/_dummytelescopebase.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/dummyaltaztelescope.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/dummyradectelescope.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/telescope/dummysolartelescope.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/test/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/test/standalone.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/dummymode.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/dummystructuredconfig.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/fluentlogger.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/httpfilecache.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/kiosk.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/matrix.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/pushnotifier.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/stellarium.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/telegram.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/utils/trigger.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/weather/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/weather/mockweather.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/weather/weather.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/weather/weather_api.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/modules/weather/weather_state.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/object.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/py.typed +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/instruments.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/observation.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/_executor.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/dataprovider.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/constant.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/follow.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/interval.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/merit.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/random.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/merits/transit.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/observingperiod.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/ondemandscheduler.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/heliocentricpolartarget.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/helioprojectivetarget.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/targets/target.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/calibration/darkbias.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/calibration/pointing.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/calibration/skyflats.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/cases.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/conditional.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/parallel.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/selector.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/control/sequential.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/exceptions.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/imaging/autofocus.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/imaging/imaging.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/script.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/utils/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/utils/callmodule.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/scripts/utils/log.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/_portal.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/configdb.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/scripts/autofocus.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/scripts/default.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/task.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/memory/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/observationarchive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/portal/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/portal/observationarchive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/portal/taskarchive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/storage/taskarchive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/task.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/taskrunner.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/archive/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/archive/archive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/archive/local_archive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/calibration.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/exptime/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/exptime/exptime.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/exptime/stellarexptime.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/flatfielder.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/average.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/cache.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/config.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/config_schema.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/coordinates.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/curvefit.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/enums.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/exptime_grouping.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/fits.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/focusseries/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/focusseries/base.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/focusseries/photometry.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/focusseries/projection.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/grids/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/grids/filters.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/grids/grid.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/grids/gridnode.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/grids/pipeline.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/binningwidget.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/exposewidget.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/http.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/influxdb.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/logger.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/logging/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/logging/context.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/logging/resolvableerror.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/modulegui.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/offsets/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/offsets/applyoffsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/parallel.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/pipeline/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/pipeline/pipeline.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/pipeline/progress.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/pipeline/reduction.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/pipeline/reduction_base.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/csv.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/http.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/log.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/multi.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/publisher/publisher.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/serialization.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/stretch.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/threads/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/threads/lockwithabort.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/time.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/units.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/utils/versions.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/version.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/archivefile.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/bufferedfile.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/file.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/filelists/__init__.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/filelists/filelist.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/filelists/testing.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/httpfile.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/localfile.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/memfile.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/sftpfile.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/smbfile.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/sshfile.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/tempfile.py +0 -0
- {pyobs_core-2.20.0 → pyobs_core-2.22.0}/pyobs/vfs/vfs.py +0 -0
|
@@ -65,14 +65,30 @@ def _warm_iers_cache() -> None:
|
|
|
65
65
|
conversion needs it -- update_leap_seconds() (not the lower-level LeapSeconds.auto_open())
|
|
66
66
|
is the call that also installs the result into erfa so real usage later doesn't re-fetch.
|
|
67
67
|
|
|
68
|
+
If the refresh fails, auto-download is disabled for the process and the error re-raised.
|
|
69
|
+
|
|
68
70
|
Meant to run inside an executor thread (see Application._main) -- calling this directly
|
|
69
71
|
on the event loop would defeat the point.
|
|
70
72
|
"""
|
|
73
|
+
from astropy.time import Time
|
|
71
74
|
from astropy.time.core import update_leap_seconds
|
|
72
75
|
from astropy.utils.iers import IERS_Auto
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
try:
|
|
78
|
+
table = IERS_Auto.open()
|
|
79
|
+
# open() alone does not refresh a stale table: that only happens on the first lookup
|
|
80
|
+
# for an actual time (IERS_Auto._interpolate -> _refresh_table_as_needed), which would
|
|
81
|
+
# otherwise be the first alt/az on the event loop. Do that lookup here, covering both
|
|
82
|
+
# UT1-UTC and polar motion.
|
|
83
|
+
now = Time.now()
|
|
84
|
+
table.ut1_utc(now)
|
|
85
|
+
table.pm_xy(now)
|
|
86
|
+
update_leap_seconds()
|
|
87
|
+
except Exception:
|
|
88
|
+
# refresh failed (e.g. offline): astropy would otherwise raise (or retry the download)
|
|
89
|
+
# on every later alt/az, so fall back to the bundled table for this process
|
|
90
|
+
_disable_iers_auto_download()
|
|
91
|
+
raise
|
|
76
92
|
|
|
77
93
|
|
|
78
94
|
class InfluxLogConfig(TypedDict):
|
|
@@ -423,16 +423,19 @@ class Comm:
|
|
|
423
423
|
|
|
424
424
|
async def register_event(self, event_class: type[Event], handler: EventHandler | None = None) -> None:
|
|
425
425
|
"""Register an event type. If a handler is given, we also receive those events, otherwise we just
|
|
426
|
-
send them.
|
|
427
|
-
|
|
426
|
+
send them.
|
|
427
|
+
|
|
428
|
+
With a handler, event classes derived from the given one are subscribed, too, but only those that have
|
|
429
|
+
been imported (and therefore registered) by now. Without a handler, only the given class itself is
|
|
430
|
+
declared as sent: a module that sends several related events registers each of them.
|
|
428
431
|
|
|
429
432
|
Args:
|
|
430
433
|
event_class: Class of event to register.
|
|
431
434
|
handler: Event handler method.
|
|
432
435
|
"""
|
|
433
436
|
|
|
434
|
-
#
|
|
435
|
-
event_classes = self._get_derived_events(event_class)
|
|
437
|
+
# a handler also covers derived events, but we only declare to send exactly the given class
|
|
438
|
+
event_classes = self._get_derived_events(event_class) if handler else [event_class]
|
|
436
439
|
|
|
437
440
|
# do we have a handler? then we subscribe, otherwise we just declare that we send it
|
|
438
441
|
if handler:
|
|
@@ -135,17 +135,38 @@ def fault_to_xml(exception: Exception) -> ET.Element:
|
|
|
135
135
|
return fault
|
|
136
136
|
|
|
137
137
|
|
|
138
|
+
def _pyobs_fault(fault_elem: ET.Element) -> ET.Element | None:
|
|
139
|
+
"""Return the <pyobs:fault> element inside a <fault><value>, or None."""
|
|
140
|
+
value_elem = fault_elem.find(f"{{{_NS}}}value")
|
|
141
|
+
if value_elem is None:
|
|
142
|
+
return None
|
|
143
|
+
return value_elem.find(f"{{{_PYOBS_NS}}}fault")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _fault_child(parent: ET.Element, name: str) -> ET.Element | None:
|
|
147
|
+
"""Find a child of a fault element, with or without the pyobs namespace.
|
|
148
|
+
|
|
149
|
+
Depending on the sender's slixmpp version, the children of <pyobs:fault> go over the wire either with
|
|
150
|
+
an explicit xmlns="" (slixmpp >= 1.17, parsed without namespace) or without it, in which case they
|
|
151
|
+
inherit urn:pyobs:rpc:1 from their parent when parsed (slixmpp <= 1.16). Both forms must be accepted (#1030).
|
|
152
|
+
"""
|
|
153
|
+
child = parent.find(f"{{{_PYOBS_NS}}}{name}")
|
|
154
|
+
return child if child is not None else parent.find(name)
|
|
155
|
+
|
|
156
|
+
|
|
138
157
|
def xml_to_fault(fault_elem: ET.Element) -> tuple[str, str]:
|
|
139
158
|
"""Parse <fault> and return (exception_qualified_name, message)."""
|
|
140
159
|
_fallback_name = f"{exc.RemoteError.__module__}.{exc.RemoteError.__qualname__}"
|
|
141
|
-
|
|
142
|
-
if value_elem is None:
|
|
160
|
+
if fault_elem.find(f"{{{_NS}}}value") is None:
|
|
143
161
|
return _fallback_name, "Unknown error"
|
|
144
|
-
pyobs_fault =
|
|
162
|
+
pyobs_fault = _pyobs_fault(fault_elem)
|
|
145
163
|
if pyobs_fault is None:
|
|
146
164
|
return _fallback_name, "Unknown error"
|
|
147
|
-
exc_el = pyobs_fault
|
|
148
|
-
msg_el = pyobs_fault
|
|
165
|
+
exc_el = _fault_child(pyobs_fault, "exception")
|
|
166
|
+
msg_el = _fault_child(pyobs_fault, "message")
|
|
167
|
+
if exc_el is None:
|
|
168
|
+
# would otherwise silently become an empty RemoteError, which is how #1030 stayed hidden
|
|
169
|
+
log.warning("Received fault without exception element: %s", ET.tostring(fault_elem, encoding="unicode"))
|
|
149
170
|
exc_name = (exc_el.text if exc_el is not None else None) or _fallback_name
|
|
150
171
|
msg = (msg_el.text if msg_el is not None else None) or ""
|
|
151
172
|
return exc_name, msg
|
|
@@ -156,13 +177,13 @@ def xml_to_fault_bases(fault_elem: ET.Element) -> list[str]:
|
|
|
156
177
|
|
|
157
178
|
Empty if the fault has none, e.g. when it comes from a peer that does not send them.
|
|
158
179
|
"""
|
|
159
|
-
|
|
160
|
-
if value_elem is None:
|
|
161
|
-
return []
|
|
162
|
-
pyobs_fault = value_elem.find(f"{{{_PYOBS_NS}}}fault")
|
|
180
|
+
pyobs_fault = _pyobs_fault(fault_elem)
|
|
163
181
|
if pyobs_fault is None:
|
|
164
182
|
return []
|
|
165
|
-
|
|
183
|
+
bases_elem = _fault_child(pyobs_fault, "bases")
|
|
184
|
+
if bases_elem is None:
|
|
185
|
+
return []
|
|
186
|
+
return [b.text for b in bases_elem if b.tag.split("}")[-1] == "base" and b.text]
|
|
166
187
|
|
|
167
188
|
|
|
168
189
|
def reconstruct_fault(name: str, message: str, bases: list[str], remote_module: str) -> exc.PyobsError:
|
|
@@ -17,6 +17,7 @@ from .moduleclosed import ModuleClosedEvent
|
|
|
17
17
|
from .moduleopened import ModuleOpenedEvent
|
|
18
18
|
from .motionstatuschanged import MotionStatusChangedEvent
|
|
19
19
|
from .move import MoveAltAzEvent, MoveEvent, MoveRaDecEvent
|
|
20
|
+
from .newdata import NewDataEvent
|
|
20
21
|
from .newimage import NewImageEvent
|
|
21
22
|
from .newspectrum import NewSpectrumEvent
|
|
22
23
|
from .offsets import OffsetsAltAzEvent, OffsetsEvent, OffsetsRaDecEvent
|
|
@@ -47,6 +48,7 @@ __all__ = [
|
|
|
47
48
|
"MoveEvent",
|
|
48
49
|
"MoveRaDecEvent",
|
|
49
50
|
"MoveAltAzEvent",
|
|
51
|
+
"NewDataEvent",
|
|
50
52
|
"NewImageEvent",
|
|
51
53
|
"NewSpectrumEvent",
|
|
52
54
|
"RoofClosingEvent",
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, TypedDict
|
|
4
|
+
|
|
5
|
+
from pyobs.events.event import Event
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DataType(TypedDict):
|
|
9
|
+
filename: str
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class NewDataEvent(Event):
|
|
13
|
+
"""Event to be sent on new data, e.g. a file that is neither an image nor a spectrum.
|
|
14
|
+
|
|
15
|
+
``filename`` is a VFS path. :class:`NewImageEvent` and :class:`NewSpectrumEvent` derive from this class, so a
|
|
16
|
+
handler registered for ``NewDataEvent`` also receives those; use ``type(event) is NewDataEvent`` to select only
|
|
17
|
+
generic data.
|
|
18
|
+
Registering ``NewDataEvent`` without a handler declares only this class as sent, not the derived events.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
__module__ = "pyobs.events"
|
|
22
|
+
|
|
23
|
+
def __init__(self, filename: str, **kwargs: Any):
|
|
24
|
+
"""Initializes new NewDataEvent.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
filename: Name of new data file.
|
|
28
|
+
"""
|
|
29
|
+
Event.__init__(self)
|
|
30
|
+
self.data: DataType = {"filename": filename}
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def from_dict(cls, d: dict[str, Any]) -> Event:
|
|
34
|
+
# get filename
|
|
35
|
+
if "filename" not in d or not isinstance(d["filename"], str):
|
|
36
|
+
raise ValueError("Invalid type for filename.")
|
|
37
|
+
filename: str = d["filename"]
|
|
38
|
+
|
|
39
|
+
# return object
|
|
40
|
+
return cls(filename)
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def filename(self) -> str:
|
|
44
|
+
return self.data["filename"]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
__all__ = ["NewDataEvent"]
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
from pyobs.events.event import Event
|
|
6
|
+
from pyobs.events.newdata import DataType as NewDataType
|
|
7
|
+
from pyobs.events.newdata import NewDataEvent
|
|
6
8
|
from pyobs.utils.enums import ImageType
|
|
7
9
|
|
|
8
10
|
|
|
9
|
-
class DataType(
|
|
10
|
-
filename: str
|
|
11
|
+
class DataType(NewDataType):
|
|
11
12
|
image_type: str | None
|
|
12
13
|
raw: str | None
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
class NewImageEvent(
|
|
16
|
+
class NewImageEvent(NewDataEvent):
|
|
16
17
|
"""Event to be sent on a new image."""
|
|
17
18
|
|
|
18
19
|
__module__ = "pyobs.events"
|
|
@@ -25,7 +26,7 @@ class NewImageEvent(Event):
|
|
|
25
26
|
image_type: Type of image.
|
|
26
27
|
raw: Only for reduced images, references raw frame.
|
|
27
28
|
"""
|
|
28
|
-
|
|
29
|
+
NewDataEvent.__init__(self, filename)
|
|
29
30
|
self.data: DataType = {
|
|
30
31
|
"filename": filename,
|
|
31
32
|
"image_type": image_type if image_type is not None else None,
|
|
@@ -50,11 +51,7 @@ class NewImageEvent(Event):
|
|
|
50
51
|
raw = d["raw"]
|
|
51
52
|
|
|
52
53
|
# return object
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def filename(self) -> str:
|
|
57
|
-
return self.data["filename"]
|
|
54
|
+
return cls(filename, image_type, raw)
|
|
58
55
|
|
|
59
56
|
@property
|
|
60
57
|
def image_type(self) -> ImageType | None:
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
from pyobs.events.event import Event
|
|
6
|
+
from pyobs.events.newdata import DataType, NewDataEvent
|
|
6
7
|
|
|
7
8
|
|
|
8
|
-
class
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class NewSpectrumEvent(Event):
|
|
13
|
-
"""Event to be sent on a new image."""
|
|
9
|
+
class NewSpectrumEvent(NewDataEvent):
|
|
10
|
+
"""Event to be sent on a new spectrum."""
|
|
14
11
|
|
|
15
12
|
__module__ = "pyobs.events"
|
|
16
13
|
|
|
@@ -18,9 +15,9 @@ class NewSpectrumEvent(Event):
|
|
|
18
15
|
"""Initializes new NewSpectrumEvent.
|
|
19
16
|
|
|
20
17
|
Args:
|
|
21
|
-
filename: Name of new
|
|
18
|
+
filename: Name of new spectrum file.
|
|
22
19
|
"""
|
|
23
|
-
|
|
20
|
+
NewDataEvent.__init__(self, filename)
|
|
24
21
|
self.data: DataType = {"filename": filename}
|
|
25
22
|
|
|
26
23
|
@classmethod
|
|
@@ -31,11 +28,7 @@ class NewSpectrumEvent(Event):
|
|
|
31
28
|
filename: str = d["filename"]
|
|
32
29
|
|
|
33
30
|
# return object
|
|
34
|
-
return
|
|
35
|
-
|
|
36
|
-
@property
|
|
37
|
-
def filename(self) -> str:
|
|
38
|
-
return self.data["filename"]
|
|
31
|
+
return cls(filename)
|
|
39
32
|
|
|
40
33
|
|
|
41
34
|
__all__ = ["NewSpectrumEvent"]
|
|
@@ -103,7 +103,7 @@ async def add_requested_fits_headers(
|
|
|
103
103
|
|
|
104
104
|
try:
|
|
105
105
|
headers = future.result()
|
|
106
|
-
except exc.
|
|
106
|
+
except exc.PyobsError as e:
|
|
107
107
|
log.warning("Could not fetch FITS headers from %s: %s.", client, str(e))
|
|
108
108
|
continue
|
|
109
109
|
except Exception as e:
|
|
@@ -173,7 +173,7 @@ class FollowMixin:
|
|
|
173
173
|
continue
|
|
174
174
|
other_coords = build_skycoord(xy_coords, this.__follow_mode)
|
|
175
175
|
connected = True
|
|
176
|
-
except (ValueError, exc.
|
|
176
|
+
except (ValueError, exc.PyobsError):
|
|
177
177
|
if connected:
|
|
178
178
|
log.warning("Could not fetch coordinates.")
|
|
179
179
|
connected = False
|
|
@@ -6,6 +6,7 @@ TODO: write doc
|
|
|
6
6
|
__title__ = "Cameras"
|
|
7
7
|
|
|
8
8
|
from .basecamera import BaseCamera
|
|
9
|
+
from .basedata import BaseData
|
|
9
10
|
from .basespectrograph import BaseSpectrograph
|
|
10
11
|
from .basevideo import BaseVideo
|
|
11
12
|
from .dummycamera import DummyCamera
|
|
@@ -15,6 +16,7 @@ from .videoframes import Frame, FrameRecord, StartSource
|
|
|
15
16
|
|
|
16
17
|
__all__ = [
|
|
17
18
|
"BaseCamera",
|
|
19
|
+
"BaseData",
|
|
18
20
|
"BaseVideo",
|
|
19
21
|
"BaseSpectrograph",
|
|
20
22
|
"DummyCamera",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from abc import ABCMeta
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pyobs.events import NewDataEvent
|
|
8
|
+
from pyobs.interfaces import IData
|
|
9
|
+
from pyobs.mixins.datasequence import DataSequenceMixin
|
|
10
|
+
from pyobs.mixins.fitsheader import FitsHeaderMixin
|
|
11
|
+
from pyobs.modules import Module
|
|
12
|
+
|
|
13
|
+
log = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BaseData(Module, FitsHeaderMixin, IData, DataSequenceMixin, metaclass=ABCMeta):
|
|
17
|
+
"""Base class for modules that grab data that is neither an image nor a spectrum.
|
|
18
|
+
|
|
19
|
+
Provides the FITS header handling and file naming of :class:`~pyobs.mixins.FitsHeaderMixin`, grab sequences
|
|
20
|
+
via :class:`~pyobs.mixins.DataSequenceMixin`, and sends a :class:`~pyobs.events.NewDataEvent` for new data.
|
|
21
|
+
Derived classes implement ``grab_data()`` and ``_sequence_busy()``, call :meth:`_send_new_data` once the data
|
|
22
|
+
is stored, and extend :meth:`abort` with the actual hardware abort.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
__module__ = "pyobs.modules.camera"
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
fits_headers: dict[str, Any] | None = None,
|
|
30
|
+
filenames: str = "/cache/pyobs-{DAY-OBS|date:}-{FRAMENUM|string:04d}.fits.gz",
|
|
31
|
+
fits_namespaces: list[str] | None = None,
|
|
32
|
+
**kwargs: Any,
|
|
33
|
+
):
|
|
34
|
+
"""Creates a new BaseData.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
fits_headers: Additional FITS headers.
|
|
38
|
+
filenames: Template for file naming.
|
|
39
|
+
fits_namespaces: List of namespaces for FITS headers that this module should request.
|
|
40
|
+
"""
|
|
41
|
+
super().__init__(fits_namespaces=fits_namespaces, fits_headers=fits_headers, filenames=filenames, **kwargs)
|
|
42
|
+
|
|
43
|
+
if self._comm is None:
|
|
44
|
+
log.warning("No comm module given, will not be able to signal new data!")
|
|
45
|
+
|
|
46
|
+
async def open(self) -> None:
|
|
47
|
+
"""Open module."""
|
|
48
|
+
await Module.open(self)
|
|
49
|
+
|
|
50
|
+
# declare the event we send, exactly this class (NewImageEvent and NewSpectrumEvent are not sent)
|
|
51
|
+
if self._comm:
|
|
52
|
+
await self.comm.register_event(NewDataEvent)
|
|
53
|
+
|
|
54
|
+
# publish initial state
|
|
55
|
+
await self._datasequence_open()
|
|
56
|
+
|
|
57
|
+
async def _send_new_data(self, filename: str, broadcast: bool = True) -> None:
|
|
58
|
+
"""Send a NewDataEvent for stored data.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
filename: VFS path of the stored data.
|
|
62
|
+
broadcast: Whether to send the event at all.
|
|
63
|
+
"""
|
|
64
|
+
if broadcast and self._comm:
|
|
65
|
+
await self.comm.send_event(NewDataEvent(filename))
|
|
66
|
+
|
|
67
|
+
async def abort(self, **kwargs: Any) -> None:
|
|
68
|
+
"""Aborts the current grab and sequence. Derived classes must implement the actual hardware abort and
|
|
69
|
+
call this."""
|
|
70
|
+
self._abort_data_sequence()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
__all__ = ["BaseData"]
|
|
@@ -65,6 +65,11 @@ class BaseSpectrograph(
|
|
|
65
65
|
"""Open module."""
|
|
66
66
|
await Module.open(self)
|
|
67
67
|
|
|
68
|
+
# declare the events we send
|
|
69
|
+
if self._comm:
|
|
70
|
+
await self.comm.register_event(NewSpectrumEvent)
|
|
71
|
+
await self.comm.register_event(ExposureStatusChangedEvent)
|
|
72
|
+
|
|
68
73
|
# publish initial state
|
|
69
74
|
await self.comm.set_state(
|
|
70
75
|
IExposure, ExposureState(status=self._spectrograph_status, progress=0.0, exposure_time_left=0.0)
|
|
@@ -251,7 +251,8 @@ class Module(Object, IModule, IConfig):
|
|
|
251
251
|
|
|
252
252
|
Args:
|
|
253
253
|
exc_type: Exception type (or a shared ancestor) to watch for. RemoteError also
|
|
254
|
-
counts remote domain faults, except expected PointingLimitError
|
|
254
|
+
counts remote domain faults, except expected PointingLimitError and
|
|
255
|
+
InitAbortedError rejections.
|
|
255
256
|
limit: Number of occurrences that triggers the callback.
|
|
256
257
|
timespan: If given, only count occurrences within the last timespan seconds.
|
|
257
258
|
module: If given, only count occurrences tagged as coming from this remote module
|
|
@@ -281,17 +282,19 @@ class Module(Object, IModule, IConfig):
|
|
|
281
282
|
|
|
282
283
|
@staticmethod
|
|
283
284
|
def _counts_as_remote_error(exception: Exception) -> bool:
|
|
284
|
-
"""Classify remote domain failures for broad handlers, excluding expected
|
|
285
|
+
"""Classify remote domain failures for broad handlers, excluding expected rejections.
|
|
286
|
+
|
|
287
|
+
Expected rejections are PointingLimitError and InitAbortedError.
|
|
285
288
|
|
|
286
289
|
Actual RemoteError inheritance and explicit domain handlers are handled separately.
|
|
287
290
|
"""
|
|
288
291
|
return getattr(exception, "remote_module", None) is not None and not isinstance(
|
|
289
|
-
exception, exc.PointingLimitError
|
|
292
|
+
exception, exc.PointingLimitError | exc.InitAbortedError
|
|
290
293
|
)
|
|
291
294
|
|
|
292
295
|
def _store_exception(self, exception: exc.PyobsError, module: str | None) -> None:
|
|
293
296
|
# Preserve actual ancestors and classify eligible remote domain faults as RemoteError
|
|
294
|
-
# for broad severity handlers. Expected pointing
|
|
297
|
+
# for broad severity handlers. Expected rejections (pointing limits, aborted init) retain their domain buckets.
|
|
295
298
|
classes: list[type] = list(type(exception).__mro__)
|
|
296
299
|
if self._counts_as_remote_error(exception) and exc.RemoteError not in classes:
|
|
297
300
|
classes.append(exc.RemoteError)
|
|
@@ -43,7 +43,7 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
|
|
|
43
43
|
runner: TaskRunner | dict[str, Any],
|
|
44
44
|
tasks: TaskArchive | dict[str, Any] | None = None,
|
|
45
45
|
allowed_late_start: int = 300,
|
|
46
|
-
allowed_overrun: int = 300,
|
|
46
|
+
allowed_overrun: int | None = 300,
|
|
47
47
|
after_task_sleep: int = 0,
|
|
48
48
|
**kwargs: Any,
|
|
49
49
|
):
|
|
@@ -52,7 +52,8 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
|
|
|
52
52
|
Args:
|
|
53
53
|
schedule: Object that can return schedule.
|
|
54
54
|
allowed_late_start: Allowed seconds to start late.
|
|
55
|
-
allowed_overrun: Allowed time for a task to exceed
|
|
55
|
+
allowed_overrun: Allowed time for a task to exceed its window in seconds, after which it is aborted.
|
|
56
|
+
None disables the check.
|
|
56
57
|
"""
|
|
57
58
|
Module.__init__(self, **kwargs)
|
|
58
59
|
|
|
@@ -119,6 +120,7 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
|
|
|
119
120
|
# subscribe to events
|
|
120
121
|
if self._comm:
|
|
121
122
|
await self.comm.register_event(TaskStartedEvent)
|
|
123
|
+
await self.comm.register_event(TaskFailedEvent)
|
|
122
124
|
await self.comm.register_event(TaskFinishedEvent)
|
|
123
125
|
await self.comm.register_event(TaskSkippedEvent)
|
|
124
126
|
|
|
@@ -141,6 +143,17 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
|
|
|
141
143
|
await self.comm.set_state(IRunning, RunningState(running=self._running))
|
|
142
144
|
await self._publish_robotic_state()
|
|
143
145
|
|
|
146
|
+
async def _clear_current_task(self) -> None:
|
|
147
|
+
"""Forget the current task and publish the state."""
|
|
148
|
+
self._task = None
|
|
149
|
+
self._project_priority = None
|
|
150
|
+
self._observation = None
|
|
151
|
+
self._task_target = None
|
|
152
|
+
self._obsnum = None
|
|
153
|
+
self._task_start = None
|
|
154
|
+
self._task_eta = None
|
|
155
|
+
await self._publish_robotic_state()
|
|
156
|
+
|
|
144
157
|
async def _publish_robotic_state(self) -> None:
|
|
145
158
|
"""Publish IRobotic state: current task (from self._task/...), and self._next_observation
|
|
146
159
|
/ self._cant_run_reason as last updated by _run_thread."""
|
|
@@ -268,6 +281,7 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
|
|
|
268
281
|
# ETA
|
|
269
282
|
now = Time.now()
|
|
270
283
|
eta = now + self._task.duration * u.second
|
|
284
|
+
window_end = observation.end # scheduled end, observation.end is overwritten below
|
|
271
285
|
self._task_start = now
|
|
272
286
|
self._task_eta = eta
|
|
273
287
|
|
|
@@ -282,31 +296,37 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
|
|
|
282
296
|
await self._observation_archive.update_observation(observation)
|
|
283
297
|
await self._publish_robotic_state()
|
|
284
298
|
|
|
285
|
-
# run task
|
|
299
|
+
# run task, abort if it exceeds its window by more than allowed_overrun
|
|
286
300
|
log.info("Running task %s...", self._task.name)
|
|
301
|
+
deadline: float | None = None
|
|
302
|
+
if self._allowed_overrun is not None:
|
|
303
|
+
deadline = (window_end + self._allowed_overrun * u.second - Time.now()).to_value("second")
|
|
287
304
|
try:
|
|
288
|
-
|
|
305
|
+
async with asyncio.timeout(deadline) as timeout:
|
|
306
|
+
await self._task_runner.run_task(self._task, self._task_target)
|
|
289
307
|
except Exception as e:
|
|
308
|
+
if isinstance(e, TimeoutError) and timeout.expired():
|
|
309
|
+
log.warning(
|
|
310
|
+
"Task %s exceeded its window by more than %d s, aborted.",
|
|
311
|
+
self._task.name,
|
|
312
|
+
self._allowed_overrun,
|
|
313
|
+
)
|
|
314
|
+
state = ObservationState.ABORTED
|
|
290
315
|
# a PyobsError is an expected/domain failure (e.g. acquisition out of tolerance) --
|
|
291
316
|
# quiet INFO line, no traceback. Anything else is unexpected and needs a full
|
|
292
317
|
# traceback to debug. e.log() also skips re-logging if some deeper layer (e.g. the
|
|
293
318
|
# module's own execute()) already logged this same exception.
|
|
294
|
-
if isinstance(e, exc.PyobsError):
|
|
295
|
-
e.log(log, "INFO", f"Task {self._task.name} failed: {e}")
|
|
296
319
|
else:
|
|
297
|
-
|
|
320
|
+
if isinstance(e, exc.PyobsError):
|
|
321
|
+
e.log(log, "INFO", f"Task {self._task.name} failed: {e}")
|
|
322
|
+
else:
|
|
323
|
+
log.exception("Task %s failed.", self._task.name)
|
|
324
|
+
state = ObservationState.FAILED
|
|
298
325
|
observation.end = Time.now()
|
|
299
|
-
observation.state =
|
|
326
|
+
observation.state = state
|
|
300
327
|
await self._observation_archive.update_observation(observation)
|
|
301
328
|
await self.comm.send_event(TaskFailedEvent(name=self._task.name, id=self._task.id, obsnum=self._obsnum))
|
|
302
|
-
self.
|
|
303
|
-
self._project_priority = None
|
|
304
|
-
self._observation = None
|
|
305
|
-
self._task_target = None
|
|
306
|
-
self._obsnum = None
|
|
307
|
-
self._task_start = None
|
|
308
|
-
self._task_eta = None
|
|
309
|
-
await self._publish_robotic_state()
|
|
329
|
+
await self._clear_current_task()
|
|
310
330
|
continue
|
|
311
331
|
|
|
312
332
|
# send event and change state
|
|
@@ -317,14 +337,7 @@ class Mastermind(Module, IAutonomous, IRobotic, IFitsHeaderBefore):
|
|
|
317
337
|
|
|
318
338
|
# finish
|
|
319
339
|
log.info("Finished task %s.", self._task.name)
|
|
320
|
-
self.
|
|
321
|
-
self._project_priority = None
|
|
322
|
-
self._observation = None
|
|
323
|
-
self._task_target = None
|
|
324
|
-
self._obsnum = None
|
|
325
|
-
self._task_start = None
|
|
326
|
-
self._task_eta = None
|
|
327
|
-
await self._publish_robotic_state()
|
|
340
|
+
await self._clear_current_task()
|
|
328
341
|
|
|
329
342
|
# sleep?
|
|
330
343
|
await asyncio.sleep(self._after_task_sleep)
|