pyobs-core 2.0.0.dev10__tar.gz → 2.0.0.dev11__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.dev10 → pyobs_core-2.0.0.dev11}/PKG-INFO +4 -4
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/application.py +5 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/cli/_cli.py +14 -5
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/cli/pyobsd.py +12 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/comm.py +26 -1
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/rpc.py +9 -4
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/serializer.py +181 -1
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/xep_0009/rpc.py +10 -2
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/xmppclient.py +36 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/xmppcomm.py +85 -35
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/testevent.py +1 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/image.py +2 -1
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/astrometry/_dotnet_response_saver.py +6 -2
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/detection/_source_catalog.py +2 -2
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/photometry/_sep_aperture_photometry.py +6 -1
- pyobs_core-2.0.0.dev11/pyobs/interfaces/IAcquisition.py +47 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IBinning.py +8 -2
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IConfig.py +6 -3
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IFlatField.py +4 -3
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IFocusModel.py +1 -1
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IFocuser.py +8 -7
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IModule.py +5 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/__init__.py +7 -3
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/interface.py +9 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/camera/basevideo.py +5 -1
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/camera/dummycamera.py +4 -2
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/flatfield/flatfield.py +1 -1
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/image/imagewatcher.py +5 -2
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/module.py +128 -11
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/acquisition.py +21 -12
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/dummyacquisition.py +13 -15
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/robotic/pointing.py +3 -27
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/telescope/dummytelescope.py +18 -8
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/weather/weather.py +2 -2
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/calibration/skyflats.py +1 -1
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/enums.py +3 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/exceptions.py +9 -0
- pyobs_core-2.0.0.dev11/pyobs/utils/units.py +48 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyproject.toml +7 -8
- pyobs_core-2.0.0.dev10/pyobs/interfaces/IAcquisition.py +0 -31
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/.gitignore +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/LICENSE +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/background_task.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/cli/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/cli/pyobs.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/cli/pyobsw.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/commlogging.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/dummy/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/dummy/dummycomm.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/local/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/local/localcomm.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/local/localnetwork.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/proxy.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/xep_0009/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/xep_0009/binding.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/xep_0009_timeout/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/xep_0009_timeout/rpc.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/xep_0009_timeout/stanza/RPC.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/comm/xmpp/xep_0009_timeout/stanza/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/badweather.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/event.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/exposurestatuschanged.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/filterchanged.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/focusfound.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/goodweather.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/log.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/modechanged.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/moduleclosed.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/moduleopened.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/motionstatuschanged.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/move.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/newimage.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/newspectrum.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/offsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/roofclosing.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/roofopened.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/taskfailed.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/taskfinished.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/events/taskstarted.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/meta/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/meta/altazoffsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/meta/exptime.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/meta/genericoffset.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/meta/onskydistance.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/meta/pixeloffsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/meta/radecoffsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/meta/skyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processor.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/_daobackgroundremover.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/annotation/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/annotation/_pillow.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/annotation/circle.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/annotation/crosshair.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/annotation/text.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/astrometry/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/astrometry/_dotnet_request.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/astrometry/_dotnet_request_builder.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/astrometry/_dotnet_request_logger.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/astrometry/astrometry.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/astrometry/dotnet.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/calibration/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/calibration/_calibration_cache.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/calibration/_ccddata_calibrator.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/calibration/calibration.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/detection/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/detection/_pysep_stats_calculator.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/detection/daophot.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/detection/pysep.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/detection/simpledisk.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/detection/sourcedetection.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/exptime/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/exptime/exptime.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/exptime/star.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/image/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/image/addfitsheaders.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/image/download.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/image/flip.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/image/grayscale.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/image/httpserver.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/image/normalize.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/image/save.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/image/saveimage.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/image/smooth.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/image/softbin.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/misc/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/misc/addmask.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/misc/catalogcircularmask.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/misc/circularmask.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/misc/createfilename.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/misc/imagesourcefilter.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/misc/removebackground.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/modules/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/modules/getfitsheaders.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/offsets/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/offsets/astrometry.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/offsets/brighteststar.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/offsets/brighteststar_guiding.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/offsets/dummyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/offsets/dummyskyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/offsets/fitsheader.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/offsets/offsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/offsets/pixeloffsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/offsets/projected.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/offsets/spilled_light.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/photometry/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/photometry/_photometry_calculator.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/photometry/_photutil_aperture_photometry.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/photometry/aperture_photometry.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/photometry/photometry.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/photometry/photutil.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/photometry/pysep.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/wcs/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/images/processors/wcs/solarhelioprojective.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IAbortable.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IAutoFocus.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IAutoGuiding.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IAutonomous.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/ICalibrate.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/ICamera.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/ICooling.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IData.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IDome.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IExposure.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IExposureTime.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IFilters.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IFitsHeaderAfter.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IFitsHeaderBefore.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IGain.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IImageFormat.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IImageType.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IMode.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IMotion.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IMultiFiber.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IOffsetsAltAz.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IOffsetsRaDec.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IPointingAltAz.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IPointingHGS.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IPointingHelioprojective.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IPointingRaDec.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IPointingSeries.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IReady.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IRoof.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IRotation.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IRunnable.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IRunning.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IScriptRunner.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/ISpectrograph.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IStartStop.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/ISyncTarget.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/ITelescope.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/ITemperatures.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IVideo.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IWeather.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/interfaces/IWindow.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/mixins/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/mixins/camerasettings.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/mixins/fitsheader.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/mixins/fitsnamespace.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/mixins/follow.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/mixins/motionstatus.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/mixins/pipeline.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/mixins/waitformotion.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/mixins/weatheraware.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/camera/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/camera/adaptive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/camera/basecamera.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/camera/basespectrograph.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/camera/dummyspectrograph.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/camera/dummyvideo.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/camera/pipelinecamera.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/flatfield/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/flatfield/pointing.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/flatfield/scheduler.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/focus/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/focus/focusmodel.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/focus/focusseries.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/image/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/image/imagewriter.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/image/pipeline.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/image/seeing.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/_base.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/_baseguiding.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/autoguiding.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/dummyguiding.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/guidingstatistics/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/guidingstatistics/guidingstatistics.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/guidingstatistics/pixeloffset.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/guidingstatistics/skyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/guidingstatistics/uptime.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/pointing/scienceframeguiding.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/robotic/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/robotic/mastermind.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/robotic/scheduler.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/robotic/scriptrunner.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/roof/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/roof/basedome.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/roof/baseroof.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/roof/dummyroof.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/telescope/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/telescope/basetelescope.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/test/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/test/standalone.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/utils/autonomouswarning.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/utils/dummymode.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/utils/fluentlogger.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/utils/httpfilecache.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/utils/kiosk.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/utils/matrix.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/utils/stellarium.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/utils/telegram.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/utils/trigger.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/weather/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/weather/weather_api.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/modules/weather/weather_state.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/object.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/py.typed +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/observation.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/astroplanscheduler.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/constraints/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/constraints/airmassconstraint.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/constraints/constraint.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/constraints/moonilluminationconstraint.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/constraints/moonseparationconstraint.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/constraints/solarelevationconstraint.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/constraints/timeconstraint.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/dataprovider.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/merits/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/merits/aftertime.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/merits/beforetime.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/merits/constant.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/merits/follow.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/merits/interval.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/merits/merit.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/merits/pernight.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/merits/random.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/merits/timewindow.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/merits/transit.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/observationarchiveevolution.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/ondemandscheduler.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/targets/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/targets/dynamictarget.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/targets/helioprojectiveradialarget.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/targets/picker/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/targets/picker/csvpicker.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/targets/picker/picker.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/targets/siderealtarget.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/targets/target.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scheduler/taskscheduler.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/calibration/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/calibration/darkbias.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/calibration/pointing.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/control/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/control/cases.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/control/conditional.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/control/parallel.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/control/selector.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/control/sequential.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/imaging/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/imaging/autofocus.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/imaging/imaging.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/imaging/transitimaging.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/script.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/utils/callmodule.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/utils/debugtrigger.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/scripts/utils/log.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/backend/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/backend/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/backend/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/filesystem/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/filesystem/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/filesystem/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/_portal.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/_schedulereader.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/_schedulewriter.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/configdb.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/mockobservationarchive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/scripts/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/scripts/autofocus.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/scripts/default.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/scripts/script.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/task.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/lco/taskrunner.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/memory/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/memory/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/memory/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/observationarchive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/storage/taskarchive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/task.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/taskrunner.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/archive/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/archive/archive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/archive/local_archive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/archive/pyobs_archive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/exptime/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/exptime/exptime.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/exptime/stellarexptime.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/skyflats/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/skyflats/exptimeeval.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/skyflats/flatfielder.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/skyflats/pointing/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/skyflats/pointing/base.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/skyflats/pointing/static.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/skyflats/priorities/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/skyflats/priorities/archive.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/skyflats/priorities/base.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/skyflats/priorities/const.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/robotic/utils/skyflats/scheduler.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/average.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/cache.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/config.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/coordinates.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/curvefit.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/fits.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/focusseries/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/focusseries/base.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/focusseries/photometry.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/focusseries/projection.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/grids/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/grids/filters.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/grids/grid.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/grids/gridnode.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/grids/pipeline.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/gui/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/gui/camera/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/gui/camera/binningwidget.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/gui/camera/datadisplaywidget.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/gui/camera/exposewidget.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/gui/camera/exposuretimewidget.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/gui/camera/imageformatwidget.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/gui/camera/listpickerdialog.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/gui/camera/windowingwidget.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/http.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/influxdb.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/logger.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/logging/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/logging/context.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/logging/resolvableerror.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/modulegui.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/offsets/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/offsets/applyaltazoffsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/offsets/applyoffsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/offsets/applyradecoffsets.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/parallel.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/pipeline/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/pipeline/night.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/pipeline/pipeline.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/publisher/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/publisher/csv.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/publisher/http.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/publisher/log.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/publisher/multi.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/publisher/publisher.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/serialization.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/shellcommand.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/threads/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/threads/lockwithabort.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/utils/time.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/version.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/archivefile.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/bufferedfile.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/file.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/filelists/__init__.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/filelists/filelist.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/filelists/testing.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/httpfile.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/localfile.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/memfile.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/sftpfile.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/smbfile.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/sshfile.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/tempfile.py +0 -0
- {pyobs_core-2.0.0.dev10 → pyobs_core-2.0.0.dev11}/pyobs/vfs/vfs.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyobs-core
|
|
3
|
-
Version: 2.0.0.
|
|
3
|
+
Version: 2.0.0.dev11
|
|
4
4
|
Summary: robotic telescope software
|
|
5
5
|
Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -9,7 +9,7 @@ Requires-Python: >=3.11
|
|
|
9
9
|
Requires-Dist: aiohttp<4,>=3.11.18
|
|
10
10
|
Requires-Dist: astroplan<0.11,>=0.10.1
|
|
11
11
|
Requires-Dist: astropy-iers-data>=0.2026.6.22.1.23.34
|
|
12
|
-
Requires-Dist: astropy<
|
|
12
|
+
Requires-Dist: astropy<9,>=7.0.1
|
|
13
13
|
Requires-Dist: astropydantic>=0.0.5
|
|
14
14
|
Requires-Dist: astroquery<0.5,>=0.4.10
|
|
15
15
|
Requires-Dist: colour<0.2,>=0.1.5
|
|
@@ -24,7 +24,7 @@ Requires-Dist: pillow>=11.3.0
|
|
|
24
24
|
Requires-Dist: psutil>=7.2.2
|
|
25
25
|
Requires-Dist: py-expression-eval<0.4,>=0.3.14
|
|
26
26
|
Requires-Dist: pydantic>=2.12.5
|
|
27
|
-
Requires-Dist: pytz
|
|
27
|
+
Requires-Dist: pytz<2027.0,>=2025.2
|
|
28
28
|
Requires-Dist: pyyaml<7,>=6.0.2
|
|
29
29
|
Requires-Dist: requests<3,>=2.32.3
|
|
30
30
|
Requires-Dist: scipy<2,>=1.15.2
|
|
@@ -39,7 +39,7 @@ Requires-Dist: filelock>=3.28.0; extra == 'full'
|
|
|
39
39
|
Requires-Dist: lmfit<2,>=1.3.3; extra == 'full'
|
|
40
40
|
Requires-Dist: matrix-nio>=0.25.2; extra == 'full'
|
|
41
41
|
Requires-Dist: opencv-python-headless>=4.10.0.84; extra == 'full'
|
|
42
|
-
Requires-Dist: photutils<3
|
|
42
|
+
Requires-Dist: photutils<4,>=3.0.0; extra == 'full'
|
|
43
43
|
Requires-Dist: python-daemon<4,>=3.1.2; extra == 'full'
|
|
44
44
|
Requires-Dist: python-telegram-bot~=22.0; extra == 'full'
|
|
45
45
|
Requires-Dist: sep<2,>=1.4.1; (sys_platform == 'linux') and extra == 'full'
|
|
@@ -114,6 +114,11 @@ class Application:
|
|
|
114
114
|
class PyobsJournaldLogHandler(JournaldLogHandler):
|
|
115
115
|
"""JournaldLogHandler that adds SYSLOG_IDENTIFIER=pyobs and PYOBS_MODULE per record."""
|
|
116
116
|
|
|
117
|
+
# logging.CRITICAL and logging.FATAL are both 50, so the upstream LEVELS dict
|
|
118
|
+
# literal collides and silently maps level 50 to FATAL's priority (0, "emerg")
|
|
119
|
+
# instead of CRITICAL's (2, "crit"). Override explicitly to restore priority 2.
|
|
120
|
+
LEVELS = {**JournaldLogHandler.LEVELS, logging.CRITICAL: 2}
|
|
121
|
+
|
|
117
122
|
def __init__(self, **kw: Any) -> None:
|
|
118
123
|
super().__init__(identifier="pyobs", **kw)
|
|
119
124
|
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import argparse
|
|
2
|
+
import logging
|
|
2
3
|
import os
|
|
3
4
|
from typing import Any
|
|
4
5
|
|
|
5
6
|
import yaml
|
|
6
7
|
|
|
8
|
+
log = logging.getLogger("pyobs")
|
|
9
|
+
|
|
7
10
|
|
|
8
11
|
class CLI:
|
|
9
12
|
# name of section in configuration file
|
|
@@ -42,11 +45,17 @@ class CLI:
|
|
|
42
45
|
|
|
43
46
|
def _load_config(self) -> None:
|
|
44
47
|
"""Load config from config file"""
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
candidates = [
|
|
49
|
+
os.path.expanduser(os.path.join("~", ".config", "pyobs.yaml")),
|
|
50
|
+
os.path.join("/", "etc", "pyobs.yaml"),
|
|
51
|
+
os.path.join("/", "opt", "pyobs", "storage", "pyobs.yaml"),
|
|
52
|
+
]
|
|
53
|
+
for config_file in candidates:
|
|
54
|
+
if os.path.exists(config_file):
|
|
55
|
+
break
|
|
56
|
+
else:
|
|
57
|
+
return
|
|
58
|
+
log.info("Using config file %s.", config_file)
|
|
50
59
|
with open(config_file) as f:
|
|
51
60
|
cfg = yaml.safe_load(f)
|
|
52
61
|
if cfg is None or self.CONFIG_SECTION not in cfg:
|
|
@@ -31,6 +31,7 @@ class PyobsDaemonCLI(CLI):
|
|
|
31
31
|
"run_path",
|
|
32
32
|
"log_path",
|
|
33
33
|
"log_level",
|
|
34
|
+
"syslog",
|
|
34
35
|
"chuid",
|
|
35
36
|
]
|
|
36
37
|
|
|
@@ -46,6 +47,12 @@ class PyobsDaemonCLI(CLI):
|
|
|
46
47
|
choices=["critical", "error", "warning", "info", "debug"],
|
|
47
48
|
default=self._config.get("log-level", "info"),
|
|
48
49
|
)
|
|
50
|
+
self._parser.add_argument(
|
|
51
|
+
"--syslog",
|
|
52
|
+
action="store_true",
|
|
53
|
+
help="send module logs to systemd journal",
|
|
54
|
+
default=self._config.get("syslog", False),
|
|
55
|
+
)
|
|
49
56
|
self._parser.add_argument("--chuid", type=str, default=self._config.get("chuid", "pyobs:pyobs"))
|
|
50
57
|
self._parser.add_argument("-v", "--verbose", action="store_true")
|
|
51
58
|
|
|
@@ -64,6 +71,7 @@ class PyobsDaemonCLI(CLI):
|
|
|
64
71
|
str(os.path.join(self._config["path"], self._config["run_path"])),
|
|
65
72
|
str(os.path.join(self._config["path"], self._config["log_path"])),
|
|
66
73
|
log_level=self._config["log_level"],
|
|
74
|
+
syslog=self._config["syslog"],
|
|
67
75
|
chuid=self._config["chuid"],
|
|
68
76
|
verbose=self._config["verbose"],
|
|
69
77
|
)
|
|
@@ -89,6 +97,7 @@ class PyobsDaemon:
|
|
|
89
97
|
run_path: str,
|
|
90
98
|
log_path: str,
|
|
91
99
|
log_level: str = "info",
|
|
100
|
+
syslog: bool = False,
|
|
92
101
|
chuid: str | None = None,
|
|
93
102
|
verbose: bool = False,
|
|
94
103
|
**kwargs: Any,
|
|
@@ -97,6 +106,7 @@ class PyobsDaemon:
|
|
|
97
106
|
self._run_path = run_path
|
|
98
107
|
self._log_path = log_path
|
|
99
108
|
self._log_level = log_level
|
|
109
|
+
self._syslog = syslog
|
|
100
110
|
self._verbose = verbose
|
|
101
111
|
|
|
102
112
|
# parse optional user/group from chuid (format: "user:group" or "user")
|
|
@@ -298,6 +308,8 @@ class PyobsDaemon:
|
|
|
298
308
|
self._log_level,
|
|
299
309
|
self._config_file(module),
|
|
300
310
|
]
|
|
311
|
+
if self._syslog:
|
|
312
|
+
cmd.append("--syslog")
|
|
301
313
|
|
|
302
314
|
if self._verbose:
|
|
303
315
|
print(f"[DEBUG] Executing: {' '.join(cmd)}")
|
|
@@ -34,10 +34,12 @@ class Comm:
|
|
|
34
34
|
|
|
35
35
|
self._proxies: dict[str, Proxy] = {}
|
|
36
36
|
self._state_subscriptions: dict[str, list[tuple[type[Interface], StateCallback]]] = {}
|
|
37
|
+
self._presence_subscriptions: dict[str, list[PresenceCallback]] = {}
|
|
37
38
|
self._module: Module | None = None
|
|
38
39
|
self._log_queue: asyncio.Queue[LogEvent] = asyncio.Queue()
|
|
39
40
|
self._logging_task: asyncio.Task[Any] | None = None
|
|
40
41
|
self._event_handlers: dict[type[Event], list[Callable[[Event, str], Coroutine[Any, Any, bool]]]] = {}
|
|
42
|
+
self._registered_events: set[type[Event]] = set()
|
|
41
43
|
self._closing = asyncio.Event()
|
|
42
44
|
|
|
43
45
|
@property
|
|
@@ -144,7 +146,7 @@ class Comm:
|
|
|
144
146
|
|
|
145
147
|
# subscribe to state
|
|
146
148
|
for interface in interfaces:
|
|
147
|
-
if interface.
|
|
149
|
+
if interface.has_own_state():
|
|
148
150
|
await self.subscribe_state(client, interface, functools.partial(proxy.update_state, interface))
|
|
149
151
|
|
|
150
152
|
self._proxies[client] = proxy
|
|
@@ -265,6 +267,12 @@ class Comm:
|
|
|
265
267
|
for interface, callback in self._state_subscriptions.pop(sender, []):
|
|
266
268
|
await self.unsubscribe_state(sender, interface, callback)
|
|
267
269
|
|
|
270
|
+
# tear down any presence subscriptions held for that client -- otherwise a stale
|
|
271
|
+
# callback (e.g. bound to a since-destroyed GUI widget) lingers and can blow up
|
|
272
|
+
# the next presence update for this client, silently swallowing its reconnect
|
|
273
|
+
for callback in self._presence_subscriptions.pop(sender, []):
|
|
274
|
+
await self.unsubscribe_presence(sender, callback)
|
|
275
|
+
|
|
268
276
|
return True
|
|
269
277
|
|
|
270
278
|
@property
|
|
@@ -434,6 +442,7 @@ class Comm:
|
|
|
434
442
|
|
|
435
443
|
# we also want to register all events derived from the given one
|
|
436
444
|
event_classes = self._get_derived_events(event_class)
|
|
445
|
+
self._registered_events.update(event_classes)
|
|
437
446
|
|
|
438
447
|
# do we have a handler?
|
|
439
448
|
if handler:
|
|
@@ -590,11 +599,27 @@ class Comm:
|
|
|
590
599
|
module: Name of remote module.
|
|
591
600
|
callback: Called with (ModuleState, error_string) on each update.
|
|
592
601
|
"""
|
|
602
|
+
self._presence_subscriptions.setdefault(module, []).append(callback)
|
|
593
603
|
await self._subscribe_presence(module, callback)
|
|
594
604
|
|
|
595
605
|
async def _subscribe_presence(self, module: str, callback: PresenceCallback) -> None:
|
|
596
606
|
pass
|
|
597
607
|
|
|
608
|
+
async def unsubscribe_presence(self, module: str, callback: PresenceCallback) -> None:
|
|
609
|
+
"""Unsubscribe from presence updates.
|
|
610
|
+
|
|
611
|
+
Args:
|
|
612
|
+
module: Name of remote module.
|
|
613
|
+
callback: Callback that was registered.
|
|
614
|
+
"""
|
|
615
|
+
subs = self._presence_subscriptions.get(module)
|
|
616
|
+
if subs is not None and callback in subs:
|
|
617
|
+
subs.remove(callback)
|
|
618
|
+
await self._unsubscribe_presence(module, callback)
|
|
619
|
+
|
|
620
|
+
async def _unsubscribe_presence(self, module: str, callback: PresenceCallback) -> None:
|
|
621
|
+
pass
|
|
622
|
+
|
|
598
623
|
def _send_event_to_module(self, event: Event, from_client: str) -> None:
|
|
599
624
|
"""Send an event to all connected modules.
|
|
600
625
|
|
|
@@ -48,12 +48,13 @@ def xml_to_params(params_elem: ET.Element, names: list[str], types: dict[str, An
|
|
|
48
48
|
type_hint = types.get(name, Any)
|
|
49
49
|
value_elem = param_elem.find(f"{{{_NS}}}value")
|
|
50
50
|
if value_elem is None:
|
|
51
|
-
|
|
52
|
-
continue
|
|
51
|
+
raise ValueError(f"Malformed RPC param '{name}': missing <value> element.")
|
|
53
52
|
pyobs_value = value_elem.find(f"{{{_PYOBS_NS}}}value")
|
|
54
53
|
if pyobs_value is None:
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
raise ValueError(
|
|
55
|
+
f"Malformed RPC param '{name}': missing <value> element in namespace '{_PYOBS_NS}' "
|
|
56
|
+
f"(sender may have serialized it without the required xmlns)."
|
|
57
|
+
)
|
|
57
58
|
children = list(pyobs_value)
|
|
58
59
|
result.append(xml_to_value(children[0], type_hint) if children else None)
|
|
59
60
|
return result
|
|
@@ -214,6 +215,10 @@ class RPC:
|
|
|
214
215
|
response_params = return_to_xml(return_value, return_type)
|
|
215
216
|
self._client.plugin["xep_0009"].make_iq_method_response(iq["id"], iq["from"], response_params).send()
|
|
216
217
|
|
|
218
|
+
except exc.ForbiddenError as e:
|
|
219
|
+
e.log(log, "WARNING", f"Forbidden call to {pmethod}: {e}")
|
|
220
|
+
self._client.plugin["xep_0009"].forbidden(iq).send()
|
|
221
|
+
|
|
217
222
|
except Exception as e:
|
|
218
223
|
if isinstance(e, exc.PyObsError):
|
|
219
224
|
e.log(log, "ERROR", f"Exception in call to {pmethod}: {e}", exc_info=True)
|
|
@@ -27,11 +27,17 @@ strip the namespace from the tag before matching (tag.split('}')[-1]).
|
|
|
27
27
|
from __future__ import annotations
|
|
28
28
|
|
|
29
29
|
import dataclasses
|
|
30
|
+
import inspect
|
|
31
|
+
import types as _builtin_types
|
|
30
32
|
from enum import StrEnum
|
|
31
|
-
from typing import Annotated, Any, get_args, get_origin, get_type_hints
|
|
33
|
+
from typing import Annotated, Any, Union, get_args, get_origin, get_type_hints
|
|
32
34
|
|
|
33
35
|
from slixmpp.xmlstream import ET
|
|
34
36
|
|
|
37
|
+
from ...interfaces.interface import Interface as _Interface
|
|
38
|
+
from ...utils.enums import Unit
|
|
39
|
+
from ...utils.time import Time as _Time
|
|
40
|
+
|
|
35
41
|
# Namespace used for the <pyobs:value> wrapper in RPC
|
|
36
42
|
PYOBS_NS = "urn:pyobs:rpc:1"
|
|
37
43
|
|
|
@@ -329,10 +335,184 @@ def _parse_scalar(text: str, type_hint: Any) -> Any:
|
|
|
329
335
|
return text
|
|
330
336
|
|
|
331
337
|
|
|
338
|
+
# ---------------------------------------------------------------------------
|
|
339
|
+
# Interface schema (disco#info <pyobs:interface> blocks)
|
|
340
|
+
# ---------------------------------------------------------------------------
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def _wire_type(hint: Any, enums: dict[str, type]) -> tuple[str, str | None]:
|
|
344
|
+
"""Map a Python type hint to a (wire_type_string, unit_string|None) pair."""
|
|
345
|
+
origin = get_origin(hint)
|
|
346
|
+
args = get_args(hint)
|
|
347
|
+
|
|
348
|
+
# Annotated[T, ...] — extract optional Unit annotation
|
|
349
|
+
if origin is Annotated:
|
|
350
|
+
inner = args[0]
|
|
351
|
+
unit = next((a for a in args[1:] if isinstance(a, Unit)), None)
|
|
352
|
+
type_str, _ = _wire_type(inner, enums)
|
|
353
|
+
return type_str, unit.value if unit else None
|
|
354
|
+
|
|
355
|
+
# T | None → optional<T> (handles typing.Union and builtin types.UnionType)
|
|
356
|
+
if origin is Union or origin is _builtin_types.UnionType:
|
|
357
|
+
non_none = [a for a in args if a is not type(None)]
|
|
358
|
+
if len(non_none) == 1:
|
|
359
|
+
inner_str, _ = _wire_type(non_none[0], enums)
|
|
360
|
+
return f"optional<{inner_str}>", None
|
|
361
|
+
return "any", None
|
|
362
|
+
|
|
363
|
+
# list[T] → array<T>
|
|
364
|
+
if origin is list:
|
|
365
|
+
inner_str, _ = _wire_type(args[0] if args else Any, enums)
|
|
366
|
+
return f"array<{inner_str}>", None
|
|
367
|
+
|
|
368
|
+
# Primitives — bool before int (bool is a subclass of int)
|
|
369
|
+
if hint is bool:
|
|
370
|
+
return "bool", None
|
|
371
|
+
if hint is int:
|
|
372
|
+
return "int32", None
|
|
373
|
+
if hint is float:
|
|
374
|
+
return "float64", None
|
|
375
|
+
if hint is str:
|
|
376
|
+
return "string", None
|
|
377
|
+
if hint is type(None):
|
|
378
|
+
return "void", None
|
|
379
|
+
|
|
380
|
+
# Time (pyobs's astropy.time.Time subclass)
|
|
381
|
+
if isinstance(hint, type) and issubclass(hint, _Time):
|
|
382
|
+
return "datetime", None
|
|
383
|
+
|
|
384
|
+
# StrEnum subclass → enum(Name) + record for <types> block
|
|
385
|
+
if isinstance(hint, type) and issubclass(hint, StrEnum) and hint is not StrEnum:
|
|
386
|
+
enums[hint.__name__] = hint
|
|
387
|
+
return f"enum({hint.__name__})", None
|
|
388
|
+
|
|
389
|
+
# dataclass → struct<Name>
|
|
390
|
+
if dataclasses.is_dataclass(hint) and isinstance(hint, type):
|
|
391
|
+
return f"struct<{hint.__name__}>", None
|
|
392
|
+
|
|
393
|
+
return "any", None
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _interface_schema_to_xml(interface: type) -> ET.Element:
|
|
397
|
+
"""Build the <{ns}interface> disco#info schema element for one Interface subclass."""
|
|
398
|
+
ns = f"urn:pyobs:interface:{interface.__name__}:{interface.version}"
|
|
399
|
+
root = ET.Element(f"{{{ns}}}interface", attrib={"name": interface.__name__})
|
|
400
|
+
|
|
401
|
+
enums: dict[str, type] = {}
|
|
402
|
+
|
|
403
|
+
# Collect <command> elements from abstract methods, MRO base-first
|
|
404
|
+
seen: set[str] = set()
|
|
405
|
+
cmd_elems: list[ET.Element] = []
|
|
406
|
+
|
|
407
|
+
for base in reversed(interface.__mro__):
|
|
408
|
+
if base in (object, _Interface):
|
|
409
|
+
continue
|
|
410
|
+
for name, member in sorted(base.__dict__.items()):
|
|
411
|
+
if name.startswith("_") or name in seen:
|
|
412
|
+
continue
|
|
413
|
+
if not getattr(member, "__isabstractmethod__", False):
|
|
414
|
+
continue
|
|
415
|
+
seen.add(name)
|
|
416
|
+
|
|
417
|
+
try:
|
|
418
|
+
hints = get_type_hints(member, include_extras=True)
|
|
419
|
+
sig = inspect.signature(member)
|
|
420
|
+
except Exception:
|
|
421
|
+
continue
|
|
422
|
+
|
|
423
|
+
cmd = ET.Element("command", attrib={"name": name})
|
|
424
|
+
for param_name, param in sig.parameters.items():
|
|
425
|
+
if param_name == "self" or param.kind in (param.VAR_KEYWORD, param.VAR_POSITIONAL):
|
|
426
|
+
continue
|
|
427
|
+
if param_name not in hints:
|
|
428
|
+
continue
|
|
429
|
+
type_str, unit_str = _wire_type(hints[param_name], enums)
|
|
430
|
+
attrib: dict[str, str] = {"name": param_name, "type": type_str}
|
|
431
|
+
if unit_str:
|
|
432
|
+
attrib["unit"] = unit_str
|
|
433
|
+
ET.SubElement(cmd, "parameter", attrib=attrib)
|
|
434
|
+
|
|
435
|
+
cmd_elems.append(cmd)
|
|
436
|
+
|
|
437
|
+
# Build <state> element (after commands, so enum collection covers both)
|
|
438
|
+
state_elem: ET.Element | None = None
|
|
439
|
+
if getattr(interface, "state", None) is not None and dataclasses.is_dataclass(interface.state):
|
|
440
|
+
state_node = f"state/{interface.__name__}/{interface.version}"
|
|
441
|
+
state_elem = ET.Element("state", attrib={"node": state_node})
|
|
442
|
+
try:
|
|
443
|
+
state_hints = get_type_hints(interface.state, include_extras=True)
|
|
444
|
+
except Exception:
|
|
445
|
+
state_hints = {}
|
|
446
|
+
for f in dataclasses.fields(interface.state):
|
|
447
|
+
type_str, unit_str = _wire_type(state_hints.get(f.name, Any), enums)
|
|
448
|
+
fattrib: dict[str, str] = {"name": f.name, "type": type_str}
|
|
449
|
+
if unit_str:
|
|
450
|
+
fattrib["unit"] = unit_str
|
|
451
|
+
ET.SubElement(state_elem, "field", attrib=fattrib)
|
|
452
|
+
|
|
453
|
+
# Emit in order: <types> → <command>... → <state>
|
|
454
|
+
if enums:
|
|
455
|
+
types_elem = ET.SubElement(root, "types")
|
|
456
|
+
for enum_name, enum_cls in sorted(enums.items()):
|
|
457
|
+
enum_elem = ET.SubElement(types_elem, "enum", attrib={"name": enum_name})
|
|
458
|
+
for member in enum_cls:
|
|
459
|
+
val_elem = ET.SubElement(enum_elem, "value")
|
|
460
|
+
val_elem.text = member.value
|
|
461
|
+
|
|
462
|
+
for cmd in cmd_elems:
|
|
463
|
+
root.append(cmd)
|
|
464
|
+
|
|
465
|
+
if state_elem is not None:
|
|
466
|
+
root.append(state_elem)
|
|
467
|
+
|
|
468
|
+
return root
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def _event_schema_to_xml(event_cls: type) -> ET.Element:
|
|
472
|
+
"""Build the <{ns}event> disco#info schema element for one Event subclass."""
|
|
473
|
+
ns = f"urn:pyobs:event:{event_cls.__name__}:{event_cls.version}"
|
|
474
|
+
root = ET.Element(f"{{{ns}}}event", attrib={"name": event_cls.__name__})
|
|
475
|
+
|
|
476
|
+
enums: dict[str, type] = {}
|
|
477
|
+
field_elems: list[ET.Element] = []
|
|
478
|
+
|
|
479
|
+
try:
|
|
480
|
+
hints = get_type_hints(event_cls.__init__, include_extras=True)
|
|
481
|
+
sig = inspect.signature(event_cls.__init__)
|
|
482
|
+
except Exception:
|
|
483
|
+
return root
|
|
484
|
+
|
|
485
|
+
for param_name, param in sig.parameters.items():
|
|
486
|
+
if param_name == "self" or param.kind in (param.VAR_KEYWORD, param.VAR_POSITIONAL):
|
|
487
|
+
continue
|
|
488
|
+
if param_name not in hints:
|
|
489
|
+
continue
|
|
490
|
+
type_str, unit_str = _wire_type(hints[param_name], enums)
|
|
491
|
+
attrib: dict[str, str] = {"name": param_name, "type": type_str}
|
|
492
|
+
if unit_str:
|
|
493
|
+
attrib["unit"] = unit_str
|
|
494
|
+
field_elems.append(ET.Element("field", attrib=attrib))
|
|
495
|
+
|
|
496
|
+
if enums:
|
|
497
|
+
types_elem = ET.SubElement(root, "types")
|
|
498
|
+
for enum_name, enum_cls in sorted(enums.items()):
|
|
499
|
+
enum_elem = ET.SubElement(types_elem, "enum", attrib={"name": enum_name})
|
|
500
|
+
for member in enum_cls:
|
|
501
|
+
val_elem = ET.SubElement(enum_elem, "value")
|
|
502
|
+
val_elem.text = member.value
|
|
503
|
+
|
|
504
|
+
for f in field_elems:
|
|
505
|
+
root.append(f)
|
|
506
|
+
|
|
507
|
+
return root
|
|
508
|
+
|
|
509
|
+
|
|
332
510
|
__all__ = [
|
|
333
511
|
"PYOBS_NS",
|
|
334
512
|
"value_to_xml",
|
|
335
513
|
"xml_to_value",
|
|
336
514
|
"_dataclass_to_xml",
|
|
337
515
|
"_xml_to_dataclass",
|
|
516
|
+
"_interface_schema_to_xml",
|
|
517
|
+
"_event_schema_to_xml",
|
|
338
518
|
]
|
|
@@ -5,8 +5,12 @@ from slixmpp.xmlstream import ET
|
|
|
5
5
|
class XEP_0009(XEP_0009_original):
|
|
6
6
|
"""Small fix for the original XEP_0009 plugin."""
|
|
7
7
|
|
|
8
|
-
def
|
|
9
|
-
|
|
8
|
+
def handle_error(self, iq):
|
|
9
|
+
"""Route RPC-level errors (e.g. forbidden, item-not-found) through the same
|
|
10
|
+
jabber_rpc_error event as transport-level errors, instead of being silently
|
|
11
|
+
dropped -- the base class's own name for this hook, previously shadowed by a
|
|
12
|
+
same-but-underscored no-op that never actually overrode it."""
|
|
13
|
+
self.xmpp.event("jabber_rpc_error", iq)
|
|
10
14
|
|
|
11
15
|
def extract_method(self, stanza):
|
|
12
16
|
xml = ET.fromstring(f"{stanza}")
|
|
@@ -16,6 +20,10 @@ class XEP_0009(XEP_0009_original):
|
|
|
16
20
|
"""Expose method to public."""
|
|
17
21
|
return self._item_not_found(iq)
|
|
18
22
|
|
|
23
|
+
def forbidden(self, iq):
|
|
24
|
+
"""Expose method to public."""
|
|
25
|
+
return self._forbidden(iq)
|
|
26
|
+
|
|
19
27
|
def send_fault(self, iq, fault_xml):
|
|
20
28
|
"""Expose method to public."""
|
|
21
29
|
return self._send_fault(iq, fault_xml)
|
|
@@ -32,6 +32,7 @@ class XmppClient(slixmpp.ClientXMPP):
|
|
|
32
32
|
self._auth_event = asyncio.Event()
|
|
33
33
|
self._auth_success = False
|
|
34
34
|
self._jid_conflict = False
|
|
35
|
+
self._conflict_reason: str | None = None
|
|
35
36
|
|
|
36
37
|
# auto-accept invitations
|
|
37
38
|
self.auto_authorize = True
|
|
@@ -54,8 +55,21 @@ class XmppClient(slixmpp.ClientXMPP):
|
|
|
54
55
|
self.add_event_handler("auth_success", lambda ev: self._auth(True))
|
|
55
56
|
self.add_event_handler("failed_auth", lambda ev: self._auth(False))
|
|
56
57
|
self.add_event_handler("failed_all_auth", self.failed_all_auth)
|
|
58
|
+
self.add_event_handler("stream_error", self._stream_error)
|
|
57
59
|
self.add_filter("in", self._filter_messages)
|
|
58
60
|
|
|
61
|
+
def reconnect(self, wait: int | float = 2.0, reason: str = "Reconnecting") -> Any:
|
|
62
|
+
"""Disconnect only, instead of slixmpp's default reconnect-in-place.
|
|
63
|
+
|
|
64
|
+
xep_0199's keepalive calls this on ping timeout. slixmpp's own
|
|
65
|
+
implementation would reconnect this same client object, while
|
|
66
|
+
XmppComm's "disconnected" handler independently spins up a brand-new
|
|
67
|
+
XmppClient. The two then fight over the same JID resource, each
|
|
68
|
+
kicking the other off the server ("replaced by new connection"),
|
|
69
|
+
forever. Leaving reconnection solely to XmppComm avoids that.
|
|
70
|
+
"""
|
|
71
|
+
return self.disconnect(0.0, reason=reason)
|
|
72
|
+
|
|
59
73
|
def _filter_messages(self, stanza: StanzaBase) -> StanzaBase | None:
|
|
60
74
|
# if a user with same JID is already connected, we get a conflict
|
|
61
75
|
if '<conflict xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />' in str(stanza):
|
|
@@ -63,6 +77,28 @@ class XmppClient(slixmpp.ClientXMPP):
|
|
|
63
77
|
return None
|
|
64
78
|
return stanza
|
|
65
79
|
|
|
80
|
+
def _stream_error(self, error: Any) -> None:
|
|
81
|
+
"""Called when the server sends a <stream:error/>, e.g. when this connection gets
|
|
82
|
+
kicked because another session took over the same JID/resource.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
error: The stream error stanza.
|
|
86
|
+
"""
|
|
87
|
+
if error["condition"] == "conflict":
|
|
88
|
+
self._jid_conflict = True
|
|
89
|
+
self._conflict_reason = error["text"] or None
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def kicked_by_conflict(self) -> bool:
|
|
93
|
+
"""Whether this client was (or is being) kicked because another session connected
|
|
94
|
+
with the same JID, rather than disconnecting for some other reason."""
|
|
95
|
+
return self._jid_conflict
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def conflict_reason(self) -> str | None:
|
|
99
|
+
"""Human-readable reason text sent alongside the conflict stream error, if any."""
|
|
100
|
+
return self._conflict_reason
|
|
101
|
+
|
|
66
102
|
async def wait_connect(self) -> bool:
|
|
67
103
|
"""Wait for client to connect.
|
|
68
104
|
|