pyobs-core 2.0.2__tar.gz → 2.1.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.0.2 → pyobs_core-2.1.0}/PKG-INFO +1 -1
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/xmppclient.py +0 -9
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/xmppcomm.py +92 -41
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/taskfailed.py +9 -3
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/taskfinished.py +8 -2
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/taskstarted.py +12 -3
- pyobs_core-2.1.0/pyobs/interfaces/IRobotic.py +60 -0
- pyobs_core-2.1.0/pyobs/interfaces/IRoboticScheduler.py +40 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/__init__.py +7 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/camera/dummycamera.py +3 -1
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/robotic/__init__.py +3 -1
- pyobs_core-2.1.0/pyobs/modules/robotic/dummymastermind.py +178 -0
- pyobs_core-2.1.0/pyobs/modules/robotic/dummyscheduler.py +155 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/robotic/mastermind.py +85 -12
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/robotic/scheduler.py +50 -2
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyproject.toml +1 -1
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/.gitignore +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/LICENSE +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/application.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/background_task.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/cli/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/cli/_cli.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/cli/pyobs.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/cli/pyobsd.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/cli/pyobsw.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/comm.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/commlogging.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/dummy/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/dummy/dummycomm.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/local/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/local/localcomm.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/local/localnetwork.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/proxy.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/rpc.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/serializer.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/badweather.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/event.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/exposurestatuschanged.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/filterchanged.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/focusfound.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/goodweather.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/log.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/modechanged.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/moduleclosed.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/moduleopened.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/motionstatuschanged.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/move.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/newimage.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/newspectrum.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/offsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/roofclosing.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/roofopened.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/events/testevent.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/image.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/meta/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/meta/altazoffsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/meta/exptime.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/meta/genericoffset.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/meta/onskydistance.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/meta/pixeloffsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/meta/radecoffsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/meta/skyoffsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processor.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/_daobackgroundremover.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/annotation/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/annotation/_pillow.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/annotation/circle.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/annotation/crosshair.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/annotation/text.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/astrometry/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/astrometry/astrometry.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/astrometry/dotnet.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/calibration/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/calibration/calibration.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/detection/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/detection/_source_catalog.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/detection/daophot.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/detection/pysep.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/detection/simpledisk.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/detection/sourcedetection.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/exptime/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/exptime/exptime.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/exptime/star.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/image/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/image/addfitsheaders.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/image/download.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/image/flip.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/image/grayscale.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/image/httpserver.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/image/normalize.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/image/save.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/image/saveimage.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/image/smooth.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/image/softbin.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/misc/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/misc/addmask.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/misc/circularmask.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/misc/createfilename.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/misc/removebackground.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/modules/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/modules/getfitsheaders.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/offsets/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/offsets/astrometry.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/offsets/brighteststar.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/offsets/fitsheader.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/offsets/offsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/offsets/projected.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/offsets/spilled_light.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/photometry/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/photometry/photometry.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/photometry/photutil.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/photometry/pysep.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/wcs/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IAbortable.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IAcquisition.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IAutoFocus.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IAutoGuiding.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IAutonomous.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IBinning.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/ICalibrate.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/ICamera.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IConfig.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/ICooling.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IData.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IDataSequence.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IDome.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IExposure.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IExposureTime.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IFilters.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IFlatField.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IFocusModel.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IFocuser.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IGain.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IImageFormat.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IImageType.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IMode.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IModule.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IMotion.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IMultiFiber.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IOffsetsAltAz.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IOffsetsRaDec.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IPointingAltAz.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IPointingBody.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IPointingHeliocentricPolar.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IPointingHeliographicStonyhurst.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IPointingHelioprojective.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IPointingOrbitalElements.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IPointingRaDec.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IPointingSeries.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IReady.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IRoof.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IRotation.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IRunnable.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IRunning.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IScriptRunner.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/ISpectrograph.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IStartStop.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IStructuredConfig.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/ISyncTarget.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/ITelescope.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/ITemperatures.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/ITrackingMode.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/ITrackingRate.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IVideo.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IWeather.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/IWindow.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/interfaces/interface.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/mixins/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/mixins/camerasettings.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/mixins/fitsheader.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/mixins/fitsnamespace.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/mixins/follow.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/mixins/motionstatus.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/mixins/pipeline.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/mixins/waitformotion.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/mixins/weatheraware.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/camera/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/camera/adaptive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/camera/basecamera.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/camera/basespectrograph.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/camera/basevideo.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/camera/dummyspectrograph.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/camera/dummyvideo.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/camera/pipelinecamera.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/flatfield/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/flatfield/flatfield.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/flatfield/pointing.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/flatfield/scheduler.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/focus/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/focus/dummyautofocus.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/focus/focusmodel.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/focus/focusseries.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/image/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/image/imagewatcher.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/image/imagewriter.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/image/pipeline.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/image/seeing.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/module.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/_base.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/_baseguiding.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/acquisition.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/autoguiding.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/dummyacquisition.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/dummyguiding.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/pointing/scienceframeguiding.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/robotic/pointing.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/robotic/scriptrunner.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/roof/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/roof/basedome.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/roof/baseroof.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/roof/dummyroof.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/telescope/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/telescope/_dummytelescopebase.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/telescope/basetelescope.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/telescope/dummyaltaztelescope.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/telescope/dummyradectelescope.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/telescope/dummysolartelescope.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/test/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/test/standalone.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/utils/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/utils/dummymode.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/utils/fluentlogger.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/utils/httpfilecache.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/utils/kiosk.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/utils/matrix.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/utils/stellarium.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/utils/telegram.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/utils/trigger.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/weather/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/weather/mockweather.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/weather/weather.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/weather/weather_api.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/modules/weather/weather_state.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/object.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/py.typed +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/observation.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/_executor.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/dataprovider.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/merits/constant.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/merits/follow.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/merits/interval.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/merits/merit.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/merits/random.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/merits/transit.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/ondemandscheduler.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/targets/heliocentricpolartarget.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/targets/helioprojectivetarget.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/targets/target.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/calibration/darkbias.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/calibration/pointing.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/calibration/skyflats.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/control/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/control/cases.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/control/conditional.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/control/parallel.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/control/selector.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/control/sequential.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/exceptions.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/imaging/autofocus.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/imaging/imaging.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/script.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/utils/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/utils/callmodule.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/scripts/utils/log.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/_portal.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/configdb.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/scripts/autofocus.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/scripts/default.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/task.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/memory/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/observationarchive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/portal/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/portal/observationarchive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/portal/taskarchive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/storage/taskarchive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/task.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/taskrunner.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/archive/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/archive/archive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/archive/local_archive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/exptime/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/exptime/exptime.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/exptime/stellarexptime.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/skyflats/flatfielder.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/average.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/cache.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/config.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/config_schema.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/coordinates.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/curvefit.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/enums.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/exceptions.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/fits.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/focusseries/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/focusseries/base.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/focusseries/photometry.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/focusseries/projection.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/grids/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/grids/filters.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/grids/grid.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/grids/gridnode.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/grids/pipeline.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/gui/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/gui/camera/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/gui/camera/binningwidget.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/gui/camera/exposewidget.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/http.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/influxdb.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/logger.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/logging/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/logging/context.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/logging/resolvableerror.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/modulegui.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/offsets/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/offsets/applyoffsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/parallel.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/pipeline/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/pipeline/pipeline.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/pipeline/progress.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/pipeline/reduction.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/pipeline/reduction_base.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/publisher/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/publisher/csv.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/publisher/http.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/publisher/log.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/publisher/multi.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/publisher/publisher.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/serialization.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/shellcommand.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/threads/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/threads/lockwithabort.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/time.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/units.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/utils/versions.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/version.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/archivefile.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/bufferedfile.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/file.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/filelists/__init__.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/filelists/filelist.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/filelists/testing.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/httpfile.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/localfile.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/memfile.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/sftpfile.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/smbfile.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/sshfile.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/tempfile.py +0 -0
- {pyobs_core-2.0.2 → pyobs_core-2.1.0}/pyobs/vfs/vfs.py +0 -0
|
@@ -4,7 +4,6 @@ from typing import Any
|
|
|
4
4
|
|
|
5
5
|
import slixmpp
|
|
6
6
|
import slixmpp.xmlstream
|
|
7
|
-
from slixmpp.xmlstream import StanzaBase
|
|
8
7
|
|
|
9
8
|
from pyobs.comm.xmpp.xep_0009.rpc import XEP_0009
|
|
10
9
|
from pyobs.comm.xmpp.xep_0009_timeout import XEP_0009_timeout
|
|
@@ -71,7 +70,6 @@ class XmppClient(slixmpp.ClientXMPP):
|
|
|
71
70
|
self.add_event_handler("failed_auth", lambda ev: self._auth(False))
|
|
72
71
|
self.add_event_handler("failed_all_auth", self.failed_all_auth)
|
|
73
72
|
self.add_event_handler("stream_error", self._stream_error)
|
|
74
|
-
self.add_filter("in", self._filter_messages)
|
|
75
73
|
|
|
76
74
|
def send_presence(self, *args: Any, **kwargs: Any) -> Any:
|
|
77
75
|
"""Override slixmpp's send_presence to hold back every presence broadcast -- the initial
|
|
@@ -112,13 +110,6 @@ class XmppClient(slixmpp.ClientXMPP):
|
|
|
112
110
|
"""
|
|
113
111
|
return self.disconnect(0.0, reason=reason)
|
|
114
112
|
|
|
115
|
-
def _filter_messages(self, stanza: StanzaBase) -> StanzaBase | None:
|
|
116
|
-
# if a user with same JID is already connected, we get a conflict
|
|
117
|
-
if '<conflict xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />' in str(stanza):
|
|
118
|
-
self._jid_conflict = True
|
|
119
|
-
return None
|
|
120
|
-
return stanza
|
|
121
|
-
|
|
122
113
|
def _stream_error(self, error: Any) -> None:
|
|
123
114
|
"""Called when the server sends a <stream:error/>, e.g. when this connection gets
|
|
124
115
|
kicked because another session took over the same JID/resource.
|
|
@@ -56,8 +56,13 @@ def _retry_delay(attempt: int, cap: float = 30.0, base: float = 1.0) -> float:
|
|
|
56
56
|
every module reconnecting to ejabberd simultaneously after a mass restart). Fixed-interval
|
|
57
57
|
retries stay in lockstep across all of them, repeatedly hammering the server at the same
|
|
58
58
|
instants; jitter decorrelates that so retries spread out over time instead.
|
|
59
|
+
|
|
60
|
+
The `min(attempt, 60)` doesn't affect real backoff behavior -- with the defaults, `cap`
|
|
61
|
+
already clamps the delay from attempt 5 onward. It only exists so `2 ** attempt` can't grow
|
|
62
|
+
past what a float can hold for retry loops with no attempt limit (#824: attempt 1024 raised
|
|
63
|
+
OverflowError here and killed the retrying task).
|
|
59
64
|
"""
|
|
60
|
-
return random.uniform(0, min(cap, base * (2**attempt)))
|
|
65
|
+
return random.uniform(0, min(cap, base * (2 ** min(attempt, 60))))
|
|
61
66
|
|
|
62
67
|
|
|
63
68
|
def _log_task_exception(task: asyncio.Task[Any]) -> None:
|
|
@@ -743,7 +748,8 @@ class XmppComm(Comm):
|
|
|
743
748
|
continue
|
|
744
749
|
if (ev.__name__, ev.version) not in peer_sent_events:
|
|
745
750
|
continue
|
|
746
|
-
asyncio.create_task(self._subscribe_event_with_retry(module_name, ev))
|
|
751
|
+
task = asyncio.create_task(self._subscribe_event_with_retry(module_name, ev))
|
|
752
|
+
task.add_done_callback(_log_task_exception)
|
|
747
753
|
|
|
748
754
|
# send event
|
|
749
755
|
self._send_event_to_module(ModuleOpenedEvent(), msg["from"].username)
|
|
@@ -904,7 +910,17 @@ class XmppComm(Comm):
|
|
|
904
910
|
if (ev.__name__, ev.version) not in self._peer_sent_events.get(peer_jid, set()):
|
|
905
911
|
continue
|
|
906
912
|
peer_module = peer_jid[: peer_jid.index("@")]
|
|
907
|
-
asyncio.create_task(self._subscribe_event_with_retry(peer_module, ev))
|
|
913
|
+
task = asyncio.create_task(self._subscribe_event_with_retry(peer_module, ev))
|
|
914
|
+
task.add_done_callback(_log_task_exception)
|
|
915
|
+
elif self._module is not None:
|
|
916
|
+
# send-only declaration -- pre-create the node now, before this module announces
|
|
917
|
+
# presence, so peers reacting to it in _got_online land their subscribe on the
|
|
918
|
+
# first attempt instead of falling back to the retry loop (see #824). Sequential
|
|
919
|
+
# and awaited inside open(): each _create_node can burn up to ~90s against an
|
|
920
|
+
# unresponsive pubsub service (_safe_send's 5 x 15s timeout budget plus jittered
|
|
921
|
+
# waits between attempts), times the number of send-only events this module
|
|
922
|
+
# declares. Accepted since connect fails anyway in that scenario.
|
|
923
|
+
await self._create_node(self._event_node(self._module.name, ev))
|
|
908
924
|
|
|
909
925
|
# update caps and send presence
|
|
910
926
|
await self._safe_send(self.client.plugin["xep_0115"].update_caps)
|
|
@@ -939,6 +955,20 @@ class XmppComm(Comm):
|
|
|
939
955
|
return parts[2]
|
|
940
956
|
return None
|
|
941
957
|
|
|
958
|
+
async def _create_node(self, node: str) -> None:
|
|
959
|
+
"""Pre-create a pubsub node so a subscriber doesn't have to wait for the first publish.
|
|
960
|
+
|
|
961
|
+
The realistic error here is <conflict/> on restart (nodes persist server-side), and a
|
|
962
|
+
permission denial should degrade gracefully to today's lazy auto-create, never block
|
|
963
|
+
startup -- so IqError is swallowed. IqTimeout is already retried inside _safe_send; if it
|
|
964
|
+
still runs out, a dead server shouldn't hang open() any longer than that existing budget,
|
|
965
|
+
so it's swallowed here too rather than propagating.
|
|
966
|
+
"""
|
|
967
|
+
try:
|
|
968
|
+
await self._safe_send(self.client.plugin["xep_0060"].create_node, self._pubsub_service, node)
|
|
969
|
+
except (slixmpp.exceptions.IqError, slixmpp.exceptions.IqTimeout) as e:
|
|
970
|
+
log.debug("Could not pre-create pubsub node %s (%s), will lazy-create on first publish.", node, e)
|
|
971
|
+
|
|
942
972
|
async def _subscribe_event_with_retry(self, peer_module: str, event_class: type[Event]) -> None:
|
|
943
973
|
"""Subscribe to a peer's event node, retrying until the node exists.
|
|
944
974
|
|
|
@@ -952,20 +982,28 @@ class XmppComm(Comm):
|
|
|
952
982
|
return
|
|
953
983
|
self._event_subscriptions.add(key)
|
|
954
984
|
node = self._event_node(peer_module, event_class)
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
985
|
+
try:
|
|
986
|
+
attempt = 0
|
|
987
|
+
while key in self._event_subscriptions:
|
|
988
|
+
try:
|
|
989
|
+
await self._safe_send(self.client.plugin["xep_0060"].subscribe, self._pubsub_service, node)
|
|
990
|
+
return
|
|
991
|
+
except (slixmpp.exceptions.IqError, slixmpp.exceptions.IqTimeout):
|
|
992
|
+
attempt += 1
|
|
993
|
+
if attempt == 30:
|
|
994
|
+
log.warning(
|
|
995
|
+
"Still failing to subscribe to event node %s after %d attempts, will keep retrying",
|
|
996
|
+
node,
|
|
997
|
+
attempt,
|
|
998
|
+
)
|
|
999
|
+
await asyncio.sleep(_retry_delay(attempt))
|
|
1000
|
+
except Exception:
|
|
1001
|
+
# an unexpected (non-IqError/IqTimeout) failure must not leave key permanently
|
|
1002
|
+
# marking (peer_module, event_class) as subscribed while nothing is subscribed and
|
|
1003
|
+
# nothing is retrying -- discard it so a later register_event()/_got_online()
|
|
1004
|
+
# re-subscribes from scratch instead of short-circuiting on the stale key (#824).
|
|
1005
|
+
self._event_subscriptions.discard(key)
|
|
1006
|
+
raise
|
|
969
1007
|
|
|
970
1008
|
def _handle_event_sync(self, msg: Any) -> None:
|
|
971
1009
|
"""Synchronous entry point for the MatchXMLMask Callback.
|
|
@@ -1058,11 +1096,7 @@ class XmppComm(Comm):
|
|
|
1058
1096
|
Args:
|
|
1059
1097
|
method: Method to call.
|
|
1060
1098
|
*args: Parameters for method.
|
|
1061
|
-
**kwargs: Parameters for method.
|
|
1062
|
-
raise RemoteException("Could not send command.")
|
|
1063
|
-
except slixmpp.exceptions.IqTimeout:
|
|
1064
|
-
raise exc()
|
|
1065
|
-
|
|
1099
|
+
**kwargs: Parameters for method.
|
|
1066
1100
|
|
|
1067
1101
|
Returns:
|
|
1068
1102
|
Return value from method.
|
|
@@ -1302,24 +1336,40 @@ class XmppComm(Comm):
|
|
|
1302
1336
|
which exits the loop into the else clause (not the break path) and returns.
|
|
1303
1337
|
Once subscribed, fetches the current value and dispatches it.
|
|
1304
1338
|
"""
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1339
|
+
try:
|
|
1340
|
+
attempt = 0
|
|
1341
|
+
while node in self._state_node_handlers:
|
|
1342
|
+
try:
|
|
1343
|
+
await self._safe_send(self.client.plugin["xep_0060"].subscribe, self._pubsub_service, node)
|
|
1344
|
+
break
|
|
1345
|
+
except (slixmpp.exceptions.IqError, slixmpp.exceptions.IqTimeout):
|
|
1346
|
+
attempt += 1
|
|
1347
|
+
if attempt == 30:
|
|
1348
|
+
log.warning(
|
|
1349
|
+
"Still failing to subscribe to state node %s after %d attempts, will keep retrying",
|
|
1350
|
+
node,
|
|
1351
|
+
attempt,
|
|
1352
|
+
)
|
|
1353
|
+
await asyncio.sleep(_retry_delay(attempt))
|
|
1354
|
+
else:
|
|
1355
|
+
return
|
|
1356
|
+
except Exception:
|
|
1357
|
+
# an unexpected failure in the subscribe loop itself must not leave a
|
|
1358
|
+
# _state_node_handlers entry behind forever -- that would permanently short-circuit
|
|
1359
|
+
# _subscribe_state (see its "already subscribed" branch) while nothing is actually
|
|
1360
|
+
# subscribed and nothing is retrying (#824). A later _subscribe_state call starts a
|
|
1361
|
+
# fresh subscribe from scratch instead; note it only carries the callback that
|
|
1362
|
+
# triggered that fresh call, not any earlier ones -- accepted as strictly better than
|
|
1363
|
+
# permanent silent loss for this catastrophic, unexpected case. Logged by the task's
|
|
1364
|
+
# _log_task_exception done-callback, not here, to avoid printing the traceback twice.
|
|
1365
|
+
self._state_node_handlers.pop(node, None)
|
|
1366
|
+
raise
|
|
1367
|
+
|
|
1368
|
+
# Fetch current value immediately after subscribing. Deliberately outside the block
|
|
1369
|
+
# above: a bad payload (_xml_to_dataclass) or a raising callback here must not be treated
|
|
1370
|
+
# as a failed subscription -- the server-side subscription is live either way, so
|
|
1371
|
+
# discarding the handler would just recreate #824's permanent-silent-loss failure via a
|
|
1372
|
+
# different trigger while making it look like a subscribe failure.
|
|
1323
1373
|
try:
|
|
1324
1374
|
result = await self._safe_send(
|
|
1325
1375
|
self.client.plugin["xep_0060"].get_items, self._pubsub_service, node, max_items=1
|
|
@@ -1349,7 +1399,8 @@ class XmppComm(Comm):
|
|
|
1349
1399
|
# Subscribe in a background task so _get_client() returns immediately.
|
|
1350
1400
|
# The retry loop handles the case where the publisher hasn't created
|
|
1351
1401
|
# the node yet (e.g. GUI connects before camera's first publish).
|
|
1352
|
-
asyncio.create_task(self._subscribe_with_retry(node, interface))
|
|
1402
|
+
task = asyncio.create_task(self._subscribe_with_retry(node, interface))
|
|
1403
|
+
task.add_done_callback(_log_task_exception)
|
|
1353
1404
|
|
|
1354
1405
|
# Initial value is fetched in _subscribe_with_retry after the subscribe IQ succeeds
|
|
1355
1406
|
|
|
@@ -6,6 +6,7 @@ from pyobs.events.event import Event
|
|
|
6
6
|
class DataType(TypedDict):
|
|
7
7
|
name: str
|
|
8
8
|
id: Any
|
|
9
|
+
obsnum: str | None
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class TaskFailedEvent(Event):
|
|
@@ -13,15 +14,16 @@ class TaskFailedEvent(Event):
|
|
|
13
14
|
|
|
14
15
|
__module__ = "pyobs.events"
|
|
15
16
|
|
|
16
|
-
def __init__(self, name: str, id: Any, **kwargs: Any):
|
|
17
|
+
def __init__(self, name: str, id: Any, obsnum: str | None = None, **kwargs: Any):
|
|
17
18
|
"""Initializes a new task failed event.
|
|
18
19
|
|
|
19
20
|
Args:
|
|
20
|
-
name: Name of task that just
|
|
21
|
+
name: Name of task that just failed
|
|
21
22
|
id: Unique identifier for task
|
|
23
|
+
obsnum: Per-night observation number of the run that just failed, e.g. "20260810-001"
|
|
22
24
|
"""
|
|
23
25
|
Event.__init__(self)
|
|
24
|
-
self.data: DataType = {"name": name, "id": id}
|
|
26
|
+
self.data: DataType = {"name": name, "id": id, "obsnum": obsnum}
|
|
25
27
|
|
|
26
28
|
@property
|
|
27
29
|
def name(self) -> str:
|
|
@@ -31,5 +33,9 @@ class TaskFailedEvent(Event):
|
|
|
31
33
|
def id(self) -> Any:
|
|
32
34
|
return self.data["id"]
|
|
33
35
|
|
|
36
|
+
@property
|
|
37
|
+
def obsnum(self) -> str | None:
|
|
38
|
+
return self.data["obsnum"]
|
|
39
|
+
|
|
34
40
|
|
|
35
41
|
__all__ = ["TaskFailedEvent"]
|
|
@@ -6,6 +6,7 @@ from pyobs.events.event import Event
|
|
|
6
6
|
class DataType(TypedDict):
|
|
7
7
|
name: str
|
|
8
8
|
id: Any
|
|
9
|
+
obsnum: str | None
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class TaskFinishedEvent(Event):
|
|
@@ -13,15 +14,16 @@ class TaskFinishedEvent(Event):
|
|
|
13
14
|
|
|
14
15
|
__module__ = "pyobs.events"
|
|
15
16
|
|
|
16
|
-
def __init__(self, name: str, id: Any, **kwargs: Any):
|
|
17
|
+
def __init__(self, name: str, id: Any, obsnum: str | None = None, **kwargs: Any):
|
|
17
18
|
"""Initializes a new task finished event.
|
|
18
19
|
|
|
19
20
|
Args:
|
|
20
21
|
name: Name of task that just finished
|
|
21
22
|
id: Unique identifier for task
|
|
23
|
+
obsnum: Per-night observation number of the run that just finished, e.g. "20260810-001"
|
|
22
24
|
"""
|
|
23
25
|
Event.__init__(self)
|
|
24
|
-
self.data: DataType = {"name": name, "id": id}
|
|
26
|
+
self.data: DataType = {"name": name, "id": id, "obsnum": obsnum}
|
|
25
27
|
|
|
26
28
|
@property
|
|
27
29
|
def name(self) -> str:
|
|
@@ -31,5 +33,9 @@ class TaskFinishedEvent(Event):
|
|
|
31
33
|
def id(self) -> Any:
|
|
32
34
|
return self.data["id"]
|
|
33
35
|
|
|
36
|
+
@property
|
|
37
|
+
def obsnum(self) -> str | None:
|
|
38
|
+
return self.data["obsnum"]
|
|
39
|
+
|
|
34
40
|
|
|
35
41
|
__all__ = ["TaskFinishedEvent"]
|
|
@@ -12,6 +12,7 @@ class DataType(TypedDict):
|
|
|
12
12
|
name: str
|
|
13
13
|
id: Any
|
|
14
14
|
eta: str | None
|
|
15
|
+
obsnum: str | None
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class TaskStartedEvent(Event):
|
|
@@ -19,16 +20,17 @@ class TaskStartedEvent(Event):
|
|
|
19
20
|
|
|
20
21
|
__module__ = "pyobs.events"
|
|
21
22
|
|
|
22
|
-
def __init__(self, name: str, id: Any, eta: Time | None = None, **kwargs: Any):
|
|
23
|
+
def __init__(self, name: str, id: Any, eta: Time | None = None, obsnum: str | None = None, **kwargs: Any):
|
|
23
24
|
"""Initializes a new task started event.
|
|
24
25
|
|
|
25
26
|
Args:
|
|
26
27
|
name: Name of task that just started
|
|
27
28
|
id: Unique identifier for task
|
|
28
29
|
eta: Predicted ETA for when the task will finish
|
|
30
|
+
obsnum: Per-night observation number assigned to this run, e.g. "20260810-001"
|
|
29
31
|
"""
|
|
30
32
|
Event.__init__(self)
|
|
31
|
-
self.data: DataType = {"name": name, "id": id, "eta": None if eta is None else eta.isot}
|
|
33
|
+
self.data: DataType = {"name": name, "id": id, "eta": None if eta is None else eta.isot, "obsnum": obsnum}
|
|
32
34
|
|
|
33
35
|
@classmethod
|
|
34
36
|
def from_dict(cls, d: dict[str, Any]) -> Event:
|
|
@@ -49,8 +51,11 @@ class TaskStartedEvent(Event):
|
|
|
49
51
|
if "eta" in d and isinstance(d["eta"], str):
|
|
50
52
|
eta = Time(d["eta"])
|
|
51
53
|
|
|
54
|
+
# get obsnum
|
|
55
|
+
obsnum: str | None = d["obsnum"] if isinstance(d.get("obsnum"), str) else None
|
|
56
|
+
|
|
52
57
|
# return object
|
|
53
|
-
return TaskStartedEvent(name=name, id=id, eta=eta)
|
|
58
|
+
return TaskStartedEvent(name=name, id=id, eta=eta, obsnum=obsnum)
|
|
54
59
|
|
|
55
60
|
@property
|
|
56
61
|
def name(self) -> str:
|
|
@@ -66,5 +71,9 @@ class TaskStartedEvent(Event):
|
|
|
66
71
|
|
|
67
72
|
return Time(self.data["eta"]) if self.data["eta"] is not None else None
|
|
68
73
|
|
|
74
|
+
@property
|
|
75
|
+
def obsnum(self) -> str | None:
|
|
76
|
+
return self.data["obsnum"]
|
|
77
|
+
|
|
69
78
|
|
|
70
79
|
__all__ = ["TaskStartedEvent"]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABCMeta
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
from ..utils.time import Time
|
|
8
|
+
from .IStartStop import IStartStop
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from ..robotic.observation import Observation
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class RoboticTask:
|
|
16
|
+
id: Any
|
|
17
|
+
name: str
|
|
18
|
+
target: str | None = None # target name, resolved if available
|
|
19
|
+
start: Time | None = None # planned start (next) / actual start (current)
|
|
20
|
+
end: Time | None = None # planned end / ETA
|
|
21
|
+
obsnum: str | None = None # "20260810-001" once assigned by the executor
|
|
22
|
+
# ObservationState value (e.g. "in_progress"), kept as a plain str rather than
|
|
23
|
+
# pyobs.robotic.observation.ObservationState: pyobs.interfaces must not depend on
|
|
24
|
+
# pyobs.robotic (which itself depends on pyobs.interfaces), or module import order decides
|
|
25
|
+
# whether it works.
|
|
26
|
+
state: str | None = None
|
|
27
|
+
priority: float | None = None
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def from_observation(cls, observation: Observation) -> RoboticTask:
|
|
31
|
+
"""Build a wire-sized task summary from a full `Observation` record."""
|
|
32
|
+
return cls(
|
|
33
|
+
id=observation.task.id,
|
|
34
|
+
name=observation.task.name,
|
|
35
|
+
target=observation.target.name if observation.target is not None else None,
|
|
36
|
+
start=Time(observation.start),
|
|
37
|
+
end=Time(observation.end),
|
|
38
|
+
obsnum=observation.obsnum,
|
|
39
|
+
state=observation.state.value,
|
|
40
|
+
priority=observation.priority,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class RoboticState:
|
|
46
|
+
current: RoboticTask | None = None
|
|
47
|
+
next: RoboticTask | None = None # immediate next observation to run
|
|
48
|
+
cant_run_reason: str | None = None # from TaskRunner.cant_run_reason(), for `next`
|
|
49
|
+
time: Time = field(default_factory=Time.now)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class IRobotic(IStartStop, metaclass=ABCMeta):
|
|
53
|
+
"""The module executes a schedule of tasks (e.g. Mastermind)."""
|
|
54
|
+
|
|
55
|
+
__module__ = "pyobs.interfaces"
|
|
56
|
+
|
|
57
|
+
state = RoboticState
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
__all__ = ["IRobotic", "RoboticTask", "RoboticState"]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABCMeta, abstractmethod
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ..utils.time import Time
|
|
8
|
+
from .IRobotic import RoboticTask
|
|
9
|
+
from .IStartStop import IStartStop
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class SchedulerState:
|
|
14
|
+
last_reschedule: Time | None = None
|
|
15
|
+
time: Time = field(default_factory=Time.now)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class IRoboticScheduler(IStartStop, metaclass=ABCMeta):
|
|
19
|
+
"""The module plans a schedule of tasks for an IRobotic executor to run (e.g. Scheduler)."""
|
|
20
|
+
|
|
21
|
+
__module__ = "pyobs.interfaces"
|
|
22
|
+
|
|
23
|
+
state = SchedulerState
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
async def get_schedule(self, limit: int = 20, **kwargs: Any) -> list[RoboticTask]:
|
|
27
|
+
"""Return the upcoming (pending/in-progress) schedule, most imminent first.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
limit: Maximum number of entries to return. The implementation also enforces its
|
|
31
|
+
own hard ceiling regardless of what's requested here, so the full schedule
|
|
32
|
+
never has to go over the wire.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Up to `limit` scheduled tasks.
|
|
36
|
+
"""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
__all__ = ["IRoboticScheduler", "SchedulerState"]
|
|
@@ -52,6 +52,8 @@ from .IPointingOrbitalElements import IPointingOrbitalElements, OrbitalElements
|
|
|
52
52
|
from .IPointingRaDec import IPointingRaDec, RaDecState
|
|
53
53
|
from .IPointingSeries import IPointingSeries
|
|
54
54
|
from .IReady import IReady, ReadyState
|
|
55
|
+
from .IRobotic import IRobotic, RoboticState, RoboticTask
|
|
56
|
+
from .IRoboticScheduler import IRoboticScheduler, SchedulerState
|
|
55
57
|
from .IRoof import IRoof
|
|
56
58
|
from .IRotation import IRotation, RotationState
|
|
57
59
|
from .IRunnable import IRunnable
|
|
@@ -149,6 +151,11 @@ __all__ = [
|
|
|
149
151
|
"IPointingSeries",
|
|
150
152
|
"IReady",
|
|
151
153
|
"ReadyState",
|
|
154
|
+
"IRobotic",
|
|
155
|
+
"RoboticTask",
|
|
156
|
+
"RoboticState",
|
|
157
|
+
"IRoboticScheduler",
|
|
158
|
+
"SchedulerState",
|
|
152
159
|
"IRoof",
|
|
153
160
|
"IRotation",
|
|
154
161
|
"RotationState",
|
|
@@ -212,7 +212,9 @@ class DummyCamera(BaseCamera, IWindow, IBinning, ICooling, IGain, IImageFormat):
|
|
|
212
212
|
& (sources["y_mean"] < shape[0])
|
|
213
213
|
]
|
|
214
214
|
model = models.Moffat2D()
|
|
215
|
-
data += make_model_image(
|
|
215
|
+
data += make_model_image(
|
|
216
|
+
shape, model, sources, model_shape=(15, 15), params_map={"x_0": "x_mean", "y_0": "y_mean"}
|
|
217
|
+
)
|
|
216
218
|
|
|
217
219
|
data[data > 65535] = 65535
|
|
218
220
|
return data.astype(np.uint16)
|
|
@@ -5,9 +5,11 @@ TODO: write doc
|
|
|
5
5
|
|
|
6
6
|
__title__ = "Robotic mode"
|
|
7
7
|
|
|
8
|
+
from .dummymastermind import DummyMastermind
|
|
9
|
+
from .dummyscheduler import DummyScheduler
|
|
8
10
|
from .mastermind import Mastermind
|
|
9
11
|
from .pointing import PointingSeries
|
|
10
12
|
from .scheduler import Scheduler
|
|
11
13
|
from .scriptrunner import ScriptRunner
|
|
12
14
|
|
|
13
|
-
__all__ = ["Mastermind", "PointingSeries", "Scheduler", "ScriptRunner"]
|
|
15
|
+
__all__ = ["DummyMastermind", "DummyScheduler", "Mastermind", "PointingSeries", "Scheduler", "ScriptRunner"]
|