pyobs-core 2.0.0.dev52__tar.gz → 2.0.0.dev54__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/PKG-INFO +1 -1
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/comm.py +11 -5
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xmppcomm.py +22 -4
- pyobs_core-2.0.0.dev54/pyobs/images/processor.py +63 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/dotnet.py +34 -26
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/pipeline.py +16 -2
- pyobs_core-2.0.0.dev54/pyobs/robotic/scheduler/_executor.py +28 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +1 -1
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +3 -4
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +2 -3
- pyobs_core-2.0.0.dev54/pyobs/robotic/scheduler/dataprovider.py +78 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/ondemandscheduler.py +6 -3
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/vfs.py +15 -6
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyproject.toml +1 -1
- pyobs_core-2.0.0.dev52/pyobs/images/processor.py +0 -28
- pyobs_core-2.0.0.dev52/pyobs/robotic/scheduler/dataprovider.py +0 -49
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/.gitignore +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/LICENSE +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/application.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/background_task.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/cli/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/cli/_cli.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/cli/pyobs.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/cli/pyobsd.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/cli/pyobsw.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/commlogging.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/dummy/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/dummy/dummycomm.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/local/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/local/localcomm.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/local/localnetwork.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/proxy.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/rpc.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/serializer.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009/rpc.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/comm/xmpp/xmppclient.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/badweather.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/event.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/exposurestatuschanged.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/filterchanged.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/focusfound.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/goodweather.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/log.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/modechanged.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/moduleclosed.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/moduleopened.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/motionstatuschanged.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/move.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/newimage.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/newspectrum.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/offsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/roofclosing.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/roofopened.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/taskfailed.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/taskfinished.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/taskstarted.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/events/testevent.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/image.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/altazoffsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/exptime.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/genericoffset.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/onskydistance.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/pixeloffsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/radecoffsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/meta/skyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/_daobackgroundremover.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/annotation/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/annotation/_pillow.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/annotation/circle.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/annotation/crosshair.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/annotation/text.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/astrometry.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/calibration/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/calibration/calibration.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/_source_catalog.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/daophot.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/pysep.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/simpledisk.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/detection/sourcedetection.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/exptime/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/exptime/exptime.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/exptime/star.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/addfitsheaders.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/download.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/flip.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/grayscale.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/httpserver.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/normalize.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/save.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/saveimage.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/smooth.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/image/softbin.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/addmask.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/circularmask.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/createfilename.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/misc/removebackground.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/modules/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/modules/getfitsheaders.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/astrometry.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/brighteststar.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/fitsheader.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/offsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/projected.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/offsets/spilled_light.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/photometry.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/photutil.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/photometry/pysep.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/wcs/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IAbortable.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IAcquisition.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IAutoFocus.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IAutoGuiding.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IAutonomous.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IBinning.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ICalibrate.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ICamera.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IConfig.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ICooling.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IData.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IDataSequence.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IDome.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IExposure.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IExposureTime.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFilters.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFlatField.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFocusModel.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IFocuser.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IGain.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IImageFormat.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IImageType.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IMode.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IModule.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IMotion.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IMultiFiber.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IOffsetsAltAz.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IOffsetsRaDec.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingAltAz.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingBody.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingHeliocentricPolar.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingHeliographicStonyhurst.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingHelioprojective.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingOrbitalElements.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingRaDec.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IPointingSeries.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IReady.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IRoof.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IRotation.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IRunnable.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IRunning.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IScriptRunner.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ISpectrograph.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IStartStop.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IStructuredConfig.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ISyncTarget.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ITelescope.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ITemperatures.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ITrackingMode.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/ITrackingRate.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IVideo.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IWeather.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/IWindow.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/interfaces/interface.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/camerasettings.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/fitsheader.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/fitsnamespace.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/follow.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/motionstatus.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/waitformotion.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/mixins/weatheraware.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/adaptive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/basecamera.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/basespectrograph.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/basevideo.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/dummycamera.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/dummyspectrograph.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/dummyvideo.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/camera/pipelinecamera.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/flatfield/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/flatfield/flatfield.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/flatfield/pointing.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/flatfield/scheduler.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/focus/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/focus/dummyautofocus.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/focus/focusmodel.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/focus/focusseries.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/image/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/image/imagewatcher.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/image/imagewriter.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/image/pipeline.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/image/seeing.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/module.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/_base.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/_baseguiding.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/acquisition.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/autoguiding.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/dummyacquisition.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/dummyguiding.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/pointing/scienceframeguiding.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/robotic/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/robotic/mastermind.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/robotic/pointing.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/robotic/scheduler.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/robotic/scriptrunner.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/roof/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/roof/basedome.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/roof/baseroof.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/roof/dummyroof.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/_dummytelescopebase.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/basetelescope.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/dummyaltaztelescope.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/dummyradectelescope.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/telescope/dummysolartelescope.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/test/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/test/standalone.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/dummymode.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/fluentlogger.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/httpfilecache.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/kiosk.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/matrix.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/stellarium.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/telegram.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/utils/trigger.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/weather/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/weather/mockweather.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/weather/weather.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/weather/weather_api.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/modules/weather/weather_state.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/object.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/py.typed +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/observation.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/constant.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/follow.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/interval.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/merit.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/random.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/merits/transit.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/heliocentricpolartarget.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/helioprojectivetarget.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/targets/target.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/calibration/darkbias.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/calibration/pointing.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/calibration/skyflats.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/cases.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/conditional.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/parallel.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/selector.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/control/sequential.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/exceptions.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/imaging/autofocus.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/imaging/imaging.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/script.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/utils/callmodule.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scripts/utils/log.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/backend/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/backend/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/backend/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/_portal.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/configdb.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/scripts/autofocus.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/scripts/default.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/task.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/memory/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/storage/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/task.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/taskrunner.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/archive/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/archive/archive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/archive/local_archive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/exptime/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/exptime/exptime.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/exptime/stellarexptime.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/flatfielder.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/average.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/cache.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/config.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/config_schema.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/coordinates.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/curvefit.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/enums.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/exceptions.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/fits.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/focusseries/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/focusseries/base.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/focusseries/photometry.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/focusseries/projection.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/grids/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/grids/filters.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/grids/grid.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/grids/gridnode.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/grids/pipeline.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/binningwidget.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/exposewidget.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/http.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/influxdb.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/logger.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/logging/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/logging/context.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/logging/resolvableerror.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/modulegui.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/offsets/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/offsets/applyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/parallel.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/pipeline/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/pipeline/night.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/pipeline/pipeline.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/csv.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/http.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/log.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/multi.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/publisher/publisher.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/serialization.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/shellcommand.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/threads/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/threads/lockwithabort.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/time.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/utils/units.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/version.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/archivefile.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/bufferedfile.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/file.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/filelists/__init__.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/filelists/filelist.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/filelists/testing.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/httpfile.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/localfile.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/memfile.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/sftpfile.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/smbfile.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/sshfile.py +0 -0
- {pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/vfs/tempfile.py +0 -0
|
@@ -39,7 +39,8 @@ class Comm:
|
|
|
39
39
|
self._log_queue: asyncio.Queue[LogEvent] = asyncio.Queue()
|
|
40
40
|
self._logging_task: asyncio.Task[Any] | None = None
|
|
41
41
|
self._event_handlers: dict[type[Event], list[Callable[[Event, str], Coroutine[Any, Any, bool]]]] = {}
|
|
42
|
-
self.
|
|
42
|
+
self._events_sent: set[type[Event]] = set()
|
|
43
|
+
self._events_subscribed: set[type[Event]] = set()
|
|
43
44
|
self._closing = asyncio.Event()
|
|
44
45
|
self._published_state: set[type[Interface]] = set()
|
|
45
46
|
|
|
@@ -434,10 +435,10 @@ class Comm:
|
|
|
434
435
|
|
|
435
436
|
# we also want to register all events derived from the given one
|
|
436
437
|
event_classes = self._get_derived_events(event_class)
|
|
437
|
-
self._registered_events.update(event_classes)
|
|
438
438
|
|
|
439
|
-
# do we have a handler?
|
|
439
|
+
# do we have a handler? then we subscribe, otherwise we just declare that we send it
|
|
440
440
|
if handler:
|
|
441
|
+
self._events_subscribed.update(event_classes)
|
|
441
442
|
# loop classes
|
|
442
443
|
for ev in event_classes:
|
|
443
444
|
# initialize list
|
|
@@ -447,6 +448,8 @@ class Comm:
|
|
|
447
448
|
if handler not in self._event_handlers[ev]:
|
|
448
449
|
# add handler
|
|
449
450
|
self._event_handlers[ev].append(handler)
|
|
451
|
+
else:
|
|
452
|
+
self._events_sent.update(event_classes)
|
|
450
453
|
|
|
451
454
|
# if event is not a local one, we also need to do some XMPP stuff
|
|
452
455
|
if not event_class.local:
|
|
@@ -457,8 +460,9 @@ class Comm:
|
|
|
457
460
|
) -> None:
|
|
458
461
|
"""Remove a handler previously added via register_event().
|
|
459
462
|
|
|
460
|
-
Leaves the event type itself registered
|
|
461
|
-
|
|
463
|
+
Leaves the event type itself registered as *sent* if the module also declared it via a
|
|
464
|
+
handler-less register_event() call, only stops calling this handler and, once no handler
|
|
465
|
+
is left for the event, drops it from what's advertised as *subscribed*.
|
|
462
466
|
|
|
463
467
|
Args:
|
|
464
468
|
event_class: Class of event that was registered.
|
|
@@ -470,6 +474,8 @@ class Comm:
|
|
|
470
474
|
handlers = self._event_handlers.get(ev)
|
|
471
475
|
if handlers is not None and handler in handlers:
|
|
472
476
|
handlers.remove(handler)
|
|
477
|
+
if not handlers:
|
|
478
|
+
self._events_subscribed.discard(ev)
|
|
473
479
|
|
|
474
480
|
async def _register_events(
|
|
475
481
|
self, events: list[type[Event]], handler: Callable[[Event, str], Coroutine[Any, Any, bool]] | None = None
|
|
@@ -37,6 +37,18 @@ if TYPE_CHECKING:
|
|
|
37
37
|
log = logging.getLogger(__name__)
|
|
38
38
|
|
|
39
39
|
|
|
40
|
+
def _event_role(ev_cls: type[Event], events_sent: set[type[Event]], events_subscribed: set[type[Event]]) -> str:
|
|
41
|
+
"""Space-separated role(s) ("send", "subscribe", or both) for an event class, for the
|
|
42
|
+
disco#info `role` attribute -- lets consumers with no access to the pyobs.events catalog
|
|
43
|
+
(e.g. pyobs-web-client) tell producers from consumers instead of guessing from the union."""
|
|
44
|
+
roles = []
|
|
45
|
+
if ev_cls in events_sent:
|
|
46
|
+
roles.append("send")
|
|
47
|
+
if ev_cls in events_subscribed:
|
|
48
|
+
roles.append("subscribe")
|
|
49
|
+
return " ".join(roles)
|
|
50
|
+
|
|
51
|
+
|
|
40
52
|
def _retry_delay(attempt: int, cap: float = 30.0, base: float = 1.0) -> float:
|
|
41
53
|
"""Capped exponential backoff with full jitter.
|
|
42
54
|
|
|
@@ -984,10 +996,16 @@ class XmppComm(Comm):
|
|
|
984
996
|
for interface in self._module.interfaces:
|
|
985
997
|
info.xml.append(_interface_schema_to_xml(interface))
|
|
986
998
|
|
|
987
|
-
# Append event schemas
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
999
|
+
# Append event schemas, tagged with a role attribute so consumers that have no access
|
|
1000
|
+
# to the pyobs.events catalog themselves (e.g. pyobs-web-client) can tell which events
|
|
1001
|
+
# a module actually sends vs. which it only subscribes to receive.
|
|
1002
|
+
registered_events = self._events_sent | self._events_subscribed
|
|
1003
|
+
for ev_cls in sorted(registered_events, key=lambda e: e.__name__):
|
|
1004
|
+
if ev_cls.local:
|
|
1005
|
+
continue
|
|
1006
|
+
event_xml = _event_schema_to_xml(ev_cls)
|
|
1007
|
+
event_xml.attrib["role"] = _event_role(ev_cls, self._events_sent, self._events_subscribed)
|
|
1008
|
+
info.xml.append(event_xml)
|
|
991
1009
|
|
|
992
1010
|
return info
|
|
993
1011
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from abc import ABCMeta, abstractmethod
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from pyobs.images import Image
|
|
5
|
+
from pyobs.object import Object
|
|
6
|
+
from pyobs.utils.exceptions import ImageError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ImageProcessor(Object, metaclass=ABCMeta):
|
|
10
|
+
VALID_ERROR_MODES = frozenset(("raise", "error", "info", "ignore"))
|
|
11
|
+
|
|
12
|
+
def __init__(self, on_error: str = "raise", **kwargs: Any):
|
|
13
|
+
"""Init new image processor.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
on_error: How the pipeline should handle an ImageError raised by this step. One of:
|
|
17
|
+
- "raise" (default): re-raise the exception, aborting the pipeline.
|
|
18
|
+
- "error": call handle_error(), pass its return value downstream.
|
|
19
|
+
- "info": log at INFO level, pass the pre-step image downstream unmodified.
|
|
20
|
+
- "ignore": silently pass the pre-step image downstream unmodified.
|
|
21
|
+
"""
|
|
22
|
+
Object.__init__(self, **kwargs)
|
|
23
|
+
|
|
24
|
+
self._on_error = on_error
|
|
25
|
+
if self._on_error not in self.VALID_ERROR_MODES:
|
|
26
|
+
raise ValueError(f"on_error must be one of {sorted(self.VALID_ERROR_MODES)}, got {self._on_error!r}.")
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def on_error(self) -> str:
|
|
30
|
+
"""The error handling mode for this step."""
|
|
31
|
+
return self._on_error
|
|
32
|
+
|
|
33
|
+
@abstractmethod
|
|
34
|
+
async def __call__(self, image: Image) -> Image:
|
|
35
|
+
"""Processes an image.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
image: Image to process.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Processed image.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def handle_error(self, image: Image, error: ImageError) -> Image:
|
|
45
|
+
"""Handle an ImageError raised by this step, when on_error == "error".
|
|
46
|
+
|
|
47
|
+
Override this to customize error handling (e.g. tag the image with a FITS header).
|
|
48
|
+
The default implementation re-raises the error.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
image: The image that caused the error.
|
|
52
|
+
error: The ImageError that was raised.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
The image to pass to the next pipeline step.
|
|
56
|
+
"""
|
|
57
|
+
raise error
|
|
58
|
+
|
|
59
|
+
async def reset(self) -> None:
|
|
60
|
+
"""Resets state of image processor"""
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
__all__ = ["ImageProcessor"]
|
{pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/images/processors/astrometry/dotnet.py
RENAMED
|
@@ -31,11 +31,15 @@ class AstrometryDotNet(Astrometry):
|
|
|
31
31
|
(commonly degrees for astrometry.net). Default: ``3.0``.
|
|
32
32
|
:param int timeout: Timeout in seconds for the network call to the astrometry
|
|
33
33
|
web service. Default: ``10``.
|
|
34
|
-
:param bool exceptions:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
:param bool exceptions: Deprecated, use ``on_error`` instead. ``exceptions=False`` is
|
|
35
|
+
equivalent to ``on_error="error"``; ``exceptions=True`` (the
|
|
36
|
+
default) is equivalent to ``on_error="raise"``.
|
|
37
|
+
:param str on_error: How the pipeline should handle a failed solve: ``"raise"`` (default,
|
|
38
|
+
abort the pipeline), ``"error"`` (mark ``WCSERR=1`` in the header, log
|
|
39
|
+
a warning, and pass the image through -- see ``handle_error``),
|
|
40
|
+
``"info"``, or ``"ignore"``. Only takes effect when this processor
|
|
41
|
+
runs as a step in a ``PipelineMixin`` pipeline; a direct call always
|
|
42
|
+
raises on failure.
|
|
39
43
|
:param kwargs: Additional keyword arguments forwarded to
|
|
40
44
|
:class:`pyobs.images.processors.astrometry.Astrometry`.
|
|
41
45
|
|
|
@@ -48,11 +52,9 @@ class AstrometryDotNet(Astrometry):
|
|
|
48
52
|
- On success, receives solver output and writes the resulting WCS into a copy of
|
|
49
53
|
the input image using :class:`pyobs.images.processors.astrometry._ResponseImageWriter`.
|
|
50
54
|
- Logs the outcome, including WCS information, and returns the result image.
|
|
51
|
-
- On failure:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
- If ``exceptions=False``, sets ``WCSERR=1`` in the FITS header, logs a warning, and returns the original
|
|
55
|
-
image unchanged.
|
|
55
|
+
- On failure, raises the underlying :class:`pyobs.images.exceptions.ImageError`. When run as
|
|
56
|
+
a pipeline step with ``on_error="error"``, the pipeline calls ``handle_error``, which sets
|
|
57
|
+
``WCSERR=1`` in the FITS header, logs a warning, and returns the original image unchanged.
|
|
56
58
|
|
|
57
59
|
Input/Output
|
|
58
60
|
------------
|
|
@@ -69,20 +71,20 @@ class AstrometryDotNet(Astrometry):
|
|
|
69
71
|
class: pyobs.images.processors.astrometry.AstrometryDotNet
|
|
70
72
|
url: "http://localhost:8080/api"
|
|
71
73
|
|
|
72
|
-
Handle failures without
|
|
74
|
+
Handle failures without aborting the pipeline:
|
|
73
75
|
|
|
74
76
|
.. code-block:: yaml
|
|
75
77
|
|
|
76
78
|
class: pyobs.images.processors.astrometry.AstrometryDotNet
|
|
77
79
|
url: "http://localhost:8080/api"
|
|
78
|
-
|
|
80
|
+
on_error: error
|
|
79
81
|
|
|
80
82
|
Notes
|
|
81
83
|
-----
|
|
82
84
|
- The ``_DotNetRequestBuilder`` determines how sources are extracted and how the
|
|
83
85
|
request is formed (including any unit conventions for ``radius``). Consult its
|
|
84
86
|
documentation for details.
|
|
85
|
-
- ``WCSERR`` is used as a failure marker in the FITS header when ``
|
|
87
|
+
- ``WCSERR`` is used as a failure marker in the FITS header when ``handle_error`` runs.
|
|
86
88
|
"""
|
|
87
89
|
|
|
88
90
|
__module__ = "pyobs.images.processors.astrometry"
|
|
@@ -93,7 +95,8 @@ class AstrometryDotNet(Astrometry):
|
|
|
93
95
|
source_count: int = 50,
|
|
94
96
|
radius: float = 3.0,
|
|
95
97
|
timeout: int = 10,
|
|
96
|
-
exceptions: bool =
|
|
98
|
+
exceptions: bool | None = None,
|
|
99
|
+
on_error: str = "raise",
|
|
97
100
|
**kwargs: Any,
|
|
98
101
|
):
|
|
99
102
|
"""Init new astronomy.net processor.
|
|
@@ -103,17 +106,28 @@ class AstrometryDotNet(Astrometry):
|
|
|
103
106
|
source_count: Number of sources to send.
|
|
104
107
|
radius: Radius to search in.
|
|
105
108
|
timeout: Timeout in seconds for call to astrometry web service.
|
|
106
|
-
exceptions: Whether to raise Exceptions.
|
|
109
|
+
exceptions: Deprecated, use on_error instead. Whether to raise Exceptions.
|
|
110
|
+
on_error: How to handle a failed solve. One of "raise", "error", "info", "ignore".
|
|
111
|
+
On "error", handle_error() marks the image with WCSERR=1 and logs a warning.
|
|
107
112
|
"""
|
|
108
|
-
Astrometry.__init__(self, **kwargs)
|
|
113
|
+
Astrometry.__init__(self, on_error=on_error, **kwargs)
|
|
109
114
|
|
|
110
115
|
self.url = url
|
|
111
116
|
|
|
112
117
|
self.timeout = timeout
|
|
113
|
-
|
|
118
|
+
|
|
119
|
+
# backwards compat: if 'exceptions' is set but 'on_error' is left at its default,
|
|
120
|
+
# derive on_error from it.
|
|
121
|
+
if exceptions is not None and on_error == "raise":
|
|
122
|
+
self._on_error = "raise" if exceptions else "error"
|
|
114
123
|
|
|
115
124
|
self._request_builder = _DotNetRequestBuilder(source_count, radius)
|
|
116
125
|
|
|
126
|
+
@property
|
|
127
|
+
def exceptions(self) -> bool:
|
|
128
|
+
"""Deprecated, use on_error instead."""
|
|
129
|
+
return self.on_error != "error"
|
|
130
|
+
|
|
117
131
|
async def _process(self, image: Image) -> Image:
|
|
118
132
|
# build the request
|
|
119
133
|
request = self._request_builder(image)
|
|
@@ -132,10 +146,7 @@ class AstrometryDotNet(Astrometry):
|
|
|
132
146
|
|
|
133
147
|
return result_image
|
|
134
148
|
|
|
135
|
-
def
|
|
136
|
-
if self.exceptions:
|
|
137
|
-
raise error
|
|
138
|
-
|
|
149
|
+
def handle_error(self, image: Image, error: exc.ImageError) -> Image:
|
|
139
150
|
image.header["WCSERR"] = 1
|
|
140
151
|
|
|
141
152
|
log.warning(error.message)
|
|
@@ -145,16 +156,13 @@ class AstrometryDotNet(Astrometry):
|
|
|
145
156
|
async def __call__(self, image: Image) -> Image:
|
|
146
157
|
"""Find astrometric solution on given image.
|
|
147
158
|
|
|
148
|
-
Writes WCSERR=1 into FITS header on failure.
|
|
159
|
+
Writes WCSERR=1 into FITS header on failure (see handle_error).
|
|
149
160
|
|
|
150
161
|
Args:
|
|
151
162
|
image: Image to analyse.
|
|
152
163
|
"""
|
|
153
164
|
|
|
154
|
-
|
|
155
|
-
return await self._process(image)
|
|
156
|
-
except exc.ImageError as e:
|
|
157
|
-
return self._handle_error(image, e)
|
|
165
|
+
return await self._process(image)
|
|
158
166
|
|
|
159
167
|
|
|
160
168
|
__all__ = ["AstrometryDotNet"]
|
|
@@ -5,6 +5,7 @@ from typing import Any
|
|
|
5
5
|
|
|
6
6
|
from pyobs.images import Image, ImageProcessor
|
|
7
7
|
from pyobs.object import Object
|
|
8
|
+
from pyobs.utils.exceptions import ImageError
|
|
8
9
|
|
|
9
10
|
log = logging.getLogger(__name__)
|
|
10
11
|
|
|
@@ -37,6 +38,10 @@ class PipelineMixin:
|
|
|
37
38
|
async def run_pipeline(self, image: Image) -> Image:
|
|
38
39
|
"""Run the pipeline on the given image.
|
|
39
40
|
|
|
41
|
+
Each step is run, and an ImageError it raises is handled according to the step's
|
|
42
|
+
on_error setting (default "raise"): re-raised, dispatched to the step's handle_error(),
|
|
43
|
+
logged, or ignored. Non-ImageError exceptions always propagate.
|
|
44
|
+
|
|
40
45
|
Args:
|
|
41
46
|
image: Image to run pipeline on.
|
|
42
47
|
|
|
@@ -44,9 +49,18 @@ class PipelineMixin:
|
|
|
44
49
|
Image after pipeline run.
|
|
45
50
|
"""
|
|
46
51
|
|
|
47
|
-
# loop steps, just let any exception pass
|
|
48
52
|
for step in self.__pipeline_steps:
|
|
49
|
-
|
|
53
|
+
try:
|
|
54
|
+
image = await step(image)
|
|
55
|
+
except ImageError as e:
|
|
56
|
+
if step.on_error == "raise":
|
|
57
|
+
raise
|
|
58
|
+
elif step.on_error == "error":
|
|
59
|
+
image = step.handle_error(image, e)
|
|
60
|
+
elif step.on_error == "info":
|
|
61
|
+
log.info("Step %s: %s", type(step).__name__, e)
|
|
62
|
+
elif step.on_error == "ignore":
|
|
63
|
+
pass
|
|
50
64
|
|
|
51
65
|
# finished
|
|
52
66
|
return image
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from collections.abc import Callable, Coroutine
|
|
5
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
6
|
+
from typing import Any, TypeVar
|
|
7
|
+
|
|
8
|
+
_T = TypeVar("_T")
|
|
9
|
+
|
|
10
|
+
# single worker: evaluate_constraints_and_merits calls are always awaited sequentially by the
|
|
11
|
+
# caller (never fired concurrently), and DataProvider's functools.cache is not safe under real
|
|
12
|
+
# concurrent access -- one worker keeps that access serialized while still freeing the main loop.
|
|
13
|
+
_executor = ThreadPoolExecutor(max_workers=1, thread_name_prefix="pyobs-scheduler")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def run_cpu_bound(coro_fn: Callable[..., Coroutine[Any, Any, _T]], *args: object) -> _T:
|
|
17
|
+
"""Runs an async callable to completion on a dedicated worker thread, off the caller's loop.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
coro_fn: An async callable whose body does not itself need to run on the caller's
|
|
21
|
+
event loop (no dependency on the caller's other tasks, timers, or comm state).
|
|
22
|
+
args: Positional args for coro_fn.
|
|
23
|
+
"""
|
|
24
|
+
loop = asyncio.get_running_loop()
|
|
25
|
+
return await loop.run_in_executor(_executor, lambda: asyncio.run(coro_fn(*args)))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__all__ = ["run_cpu_bound"]
|
|
@@ -24,7 +24,7 @@ class MoonIlluminationConstraint(Constraint):
|
|
|
24
24
|
return astroplan.MoonIlluminationConstraint(max=self.max_phase)
|
|
25
25
|
|
|
26
26
|
async def __call__(self, time: Time, task: Task, data: DataProvider) -> bool:
|
|
27
|
-
moon_illumination =
|
|
27
|
+
moon_illumination = data.moon_illumination(time)
|
|
28
28
|
return moon_illumination <= self.max_phase
|
|
29
29
|
|
|
30
30
|
|
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
import astroplan
|
|
6
|
-
import astropy.coordinates
|
|
7
6
|
import astropy.units as u
|
|
8
7
|
import numpy as np
|
|
9
8
|
from astropy.coordinates import SkyCoord
|
|
@@ -32,12 +31,12 @@ class MoonSeparationConstraint(Constraint):
|
|
|
32
31
|
if task.target is None:
|
|
33
32
|
return True
|
|
34
33
|
coord = task.target.coordinates(time)
|
|
35
|
-
moon_separation =
|
|
34
|
+
moon_separation = data.moon(time).separation(coord, origin_mismatch="ignore") # type: ignore[unexpected-keyword]
|
|
36
35
|
return float(moon_separation.degree) >= self.min_distance
|
|
37
36
|
|
|
38
37
|
async def filter_skycoord(self, time: Time, coords: SkyCoord, data: DataProvider) -> np.ndarray:
|
|
39
|
-
moon =
|
|
40
|
-
separations = moon.separation(coords, origin_mismatch="ignore").deg
|
|
38
|
+
moon = data.moon(time)
|
|
39
|
+
separations = moon.separation(coords, origin_mismatch="ignore").deg # type: ignore[unexpected-keyword]
|
|
41
40
|
return np.asarray(separations >= self.min_distance, dtype=np.bool_)
|
|
42
41
|
|
|
43
42
|
|
|
@@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Literal
|
|
|
5
5
|
|
|
6
6
|
import astroplan
|
|
7
7
|
import astropy.units as u
|
|
8
|
-
from astropy.coordinates import get_sun
|
|
9
8
|
from pydantic import Field
|
|
10
9
|
|
|
11
10
|
from pyobs.utils.time import Time
|
|
@@ -34,12 +33,12 @@ class SolarElevationConstraint(Constraint):
|
|
|
34
33
|
return astroplan.AtNightConstraint(max_solar_altitude=self.max_elevation * u.deg)
|
|
35
34
|
|
|
36
35
|
async def __call__(self, time: Time, task: Task, data: DataProvider) -> bool:
|
|
37
|
-
sun = data.
|
|
36
|
+
sun = data.sun_altaz(time)
|
|
38
37
|
in_range = self.min_elevation <= float(sun.alt.degree) <= self.max_elevation
|
|
39
38
|
if self.direction == "both":
|
|
40
39
|
return in_range
|
|
41
40
|
else:
|
|
42
|
-
sun_coord =
|
|
41
|
+
sun_coord = data.sun(time)
|
|
43
42
|
transit = data.observer.target_meridian_transit_time(time, sun_coord, which="nearest")
|
|
44
43
|
midnight = data.observer.midnight(time, which="nearest")
|
|
45
44
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from functools import cache
|
|
6
|
+
|
|
7
|
+
import astropy.coordinates
|
|
8
|
+
from astroplan import Observer
|
|
9
|
+
from astropy.coordinates import SkyCoord
|
|
10
|
+
|
|
11
|
+
from pyobs.robotic.scheduler.observationarchiveevolution import (
|
|
12
|
+
ObservationArchiveEvolution,
|
|
13
|
+
)
|
|
14
|
+
from pyobs.utils.time import Time
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class TaskSuccess:
|
|
19
|
+
date: Time
|
|
20
|
+
night: Time
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DataProvider:
|
|
24
|
+
"""Data provider for Merit classes.
|
|
25
|
+
|
|
26
|
+
The ``@cache``d methods below are only safe to call from a single thread at a time -- they're
|
|
27
|
+
used exclusively from within the scheduler's dedicated single-worker executor
|
|
28
|
+
(`pyobs.robotic.scheduler._executor.run_cpu_bound`), never concurrently from the caller's main
|
|
29
|
+
event loop. A new `DataProvider` is created per `schedule()` call, so cache lifetime is bounded
|
|
30
|
+
to one schedule computation and never leaks stale values across runs.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, observer: Observer, archive: ObservationArchiveEvolution | None = None):
|
|
34
|
+
self.observer = observer
|
|
35
|
+
self.archive = archive if archive else ObservationArchiveEvolution(observer)
|
|
36
|
+
|
|
37
|
+
@cache
|
|
38
|
+
def last_sunset(self, time: Time) -> Time:
|
|
39
|
+
"""Returns the time of the last sunset."""
|
|
40
|
+
|
|
41
|
+
# get last sunset
|
|
42
|
+
return Time(self.observer.sun_set_time(time, which="previous"))
|
|
43
|
+
|
|
44
|
+
@cache
|
|
45
|
+
def last_sunrise(self, time: Time) -> Time:
|
|
46
|
+
"""Returns the time of the last sunrise."""
|
|
47
|
+
|
|
48
|
+
# get last sunset
|
|
49
|
+
return Time(self.observer.sun_rise_time(time, which="previous"))
|
|
50
|
+
|
|
51
|
+
@cache
|
|
52
|
+
def night(self, time: Time) -> datetime.date:
|
|
53
|
+
"""Returns the time of the last sunset."""
|
|
54
|
+
sunset = self.last_sunset(time)
|
|
55
|
+
return sunset.to_datetime().date()
|
|
56
|
+
|
|
57
|
+
@cache
|
|
58
|
+
def sun(self, time: Time) -> SkyCoord:
|
|
59
|
+
"""Returns the Sun's coordinates at the given time."""
|
|
60
|
+
return astropy.coordinates.get_sun(time)
|
|
61
|
+
|
|
62
|
+
@cache
|
|
63
|
+
def sun_altaz(self, time: Time) -> SkyCoord:
|
|
64
|
+
"""Returns the Sun's AltAz coordinates at the given time, as seen by the observer."""
|
|
65
|
+
return self.observer.sun_altaz(time)
|
|
66
|
+
|
|
67
|
+
@cache
|
|
68
|
+
def moon(self, time: Time) -> SkyCoord:
|
|
69
|
+
"""Returns the Moon's coordinates at the given time."""
|
|
70
|
+
return astropy.coordinates.get_body("moon", time)
|
|
71
|
+
|
|
72
|
+
@cache
|
|
73
|
+
def moon_illumination(self, time: Time) -> float:
|
|
74
|
+
"""Returns the Moon's illumination fraction at the given time."""
|
|
75
|
+
return float(self.observer.moon_illumination(time))
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
__all__ = ["DataProvider"]
|
{pyobs_core-2.0.0.dev52 → pyobs_core-2.0.0.dev54}/pyobs/robotic/scheduler/ondemandscheduler.py
RENAMED
|
@@ -14,6 +14,7 @@ from pyobs.robotic.storage.observationarchive import ObservationArchive
|
|
|
14
14
|
from pyobs.utils.time import Time
|
|
15
15
|
|
|
16
16
|
from . import DataProvider
|
|
17
|
+
from ._executor import run_cpu_bound
|
|
17
18
|
from .constraints import Constraint
|
|
18
19
|
from .observationarchiveevolution import ObservationArchiveEvolution
|
|
19
20
|
from .taskscheduler import TaskScheduler
|
|
@@ -250,7 +251,7 @@ class OnDemandScheduler(TaskScheduler):
|
|
|
250
251
|
) -> tuple[Task | None, float]:
|
|
251
252
|
|
|
252
253
|
# evaluate all merit functions at given time
|
|
253
|
-
merits = await self.evaluate_constraints_and_merits
|
|
254
|
+
merits = await run_cpu_bound(self.evaluate_constraints_and_merits, tasks, projects, start, end, data)
|
|
254
255
|
|
|
255
256
|
# find max one
|
|
256
257
|
idx = np.argmax(merits)
|
|
@@ -274,7 +275,7 @@ class OnDemandScheduler(TaskScheduler):
|
|
|
274
275
|
other_tasks = [t for t in tasks if t is not task]
|
|
275
276
|
t = start + TimeDelta(step * u.second)
|
|
276
277
|
while t < start + TimeDelta(task.estimate_duration(time=start) * u.second):
|
|
277
|
-
merits = await self.evaluate_constraints_and_merits
|
|
278
|
+
merits = await run_cpu_bound(self.evaluate_constraints_and_merits, other_tasks, projects, t, end, data)
|
|
278
279
|
for i, m in enumerate(merits):
|
|
279
280
|
if m > merit:
|
|
280
281
|
return other_tasks[i], t, m
|
|
@@ -295,7 +296,9 @@ class OnDemandScheduler(TaskScheduler):
|
|
|
295
296
|
better_start: Time = start + TimeDelta(task.estimate_duration(time=start) * u.second)
|
|
296
297
|
|
|
297
298
|
# evaluate merit of better_task at new start time
|
|
298
|
-
merit = (
|
|
299
|
+
merit = (
|
|
300
|
+
await run_cpu_bound(self.evaluate_constraints_and_merits, [better_task], projects, better_start, end, data)
|
|
301
|
+
)[0]
|
|
299
302
|
|
|
300
303
|
# if it got better, return it, otherwise return Nones
|
|
301
304
|
if merit >= better_merit:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
3
4
|
import io
|
|
4
5
|
import logging
|
|
5
6
|
from collections.abc import Awaitable, Callable
|
|
@@ -114,11 +115,15 @@ class VirtualFileSystem:
|
|
|
114
115
|
hdulist: hdu list to write.
|
|
115
116
|
"""
|
|
116
117
|
|
|
117
|
-
|
|
118
|
-
async with self.open_file(filename, "wb") as f:
|
|
118
|
+
def _serialize() -> bytes:
|
|
119
119
|
with io.BytesIO() as bio:
|
|
120
120
|
hdulist.writeto(bio, *args, **kwargs)
|
|
121
|
-
|
|
121
|
+
return bio.getvalue()
|
|
122
|
+
|
|
123
|
+
# open file
|
|
124
|
+
async with self.open_file(filename, "wb") as f:
|
|
125
|
+
data = await asyncio.to_thread(_serialize)
|
|
126
|
+
await f.write(data)
|
|
122
127
|
|
|
123
128
|
async def read_image(self, filename: str) -> Image:
|
|
124
129
|
"""Convenience function that wraps around open_file() to read an Image.
|
|
@@ -145,11 +150,15 @@ class VirtualFileSystem:
|
|
|
145
150
|
image: Image to write.
|
|
146
151
|
"""
|
|
147
152
|
|
|
148
|
-
|
|
149
|
-
async with self.open_file(filename, "wb") as f:
|
|
153
|
+
def _serialize() -> bytes:
|
|
150
154
|
with io.BytesIO() as bio:
|
|
151
155
|
image.writeto(bio, *args, **kwargs)
|
|
152
|
-
|
|
156
|
+
return bio.getvalue()
|
|
157
|
+
|
|
158
|
+
# open file
|
|
159
|
+
async with self.open_file(filename, "wb") as f:
|
|
160
|
+
data = await asyncio.to_thread(_serialize)
|
|
161
|
+
await f.write(data)
|
|
153
162
|
|
|
154
163
|
async def write_bytes(self, filename: str, data: bytes, *args: Any, **kwargs: Any) -> None:
|
|
155
164
|
"""Convenience function for writing bytes to a file.
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
from abc import ABCMeta, abstractmethod
|
|
2
|
-
from typing import Any
|
|
3
|
-
|
|
4
|
-
from pyobs.images import Image
|
|
5
|
-
from pyobs.object import Object
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class ImageProcessor(Object, metaclass=ABCMeta):
|
|
9
|
-
def __init__(self, **kwargs: Any):
|
|
10
|
-
"""Init new image processor."""
|
|
11
|
-
Object.__init__(self, **kwargs)
|
|
12
|
-
|
|
13
|
-
@abstractmethod
|
|
14
|
-
async def __call__(self, image: Image) -> Image:
|
|
15
|
-
"""Processes an image.
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
image: Image to process.
|
|
19
|
-
|
|
20
|
-
Returns:
|
|
21
|
-
Processed image.
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
async def reset(self) -> None:
|
|
25
|
-
"""Resets state of image processor"""
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
__all__ = ["ImageProcessor"]
|