Loading .gitlab-ci.yml +12 −20 Changes for .gitlab-ci.yml: 12 added lines, 20 removed lines. Original line number Diff line number Diff line Loading @@ -2,33 +2,23 @@ image: python:3.13 variables: PROJECT: "noctua" PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" # The runner is short on disk: no pip cache (downloaded wheels would be # kept twice, and GitLab would also store the cache between jobs). PIP_NO_CACHE_DIR: "1" FORMAT_TARGETS: "${PROJECT}" PYLINT_TARGETS: "${PROJECT}" GIT_USER_EMAIL: "davide.ricci@inaf.it" GIT_USER_NAME: "Davide GitLab CI" FORMATTED_BRANCH_NAME: "validated" cache: key: "$CI_COMMIT_REF_SLUG" paths: - .cache/pip stages: - deploy_docs - setup_and_format - lint - auto_commit # Job 1: We don't actually need to pass artifacts here if we just want to test install install_project: stage: setup_and_format tags: - git-run-ia2 script: - pip install --upgrade pip - pip install -e . # No artifacts needed here unless you are generating files needed by others # The install is tested by run_pylint and pages, which both run # `pip install -e .`: no separate install job (saves runner disk). # Job 2: Remove Trailing Whitespaces fix_trailing_whitespaces: Loading Loading @@ -83,8 +73,9 @@ run_pylint: artifacts: true before_script: - pip install pylint # Install dependencies so pylint can resolve imports - pip install -e . # No dependencies (the runner is short on disk): pylint reports the # unresolved imports, but this job never fails anyway (see `|| echo`). - pip install -e . --no-deps script: - pylint --rcfile=.pylintrc --fail-on=E,F ${PYLINT_TARGETS}/sequencer.py || echo "Pylint finished with issues" Loading @@ -94,11 +85,12 @@ pages: tags: - git-run-ia2 before_script: # - apt-get update -y && apt install -y gnuplot - pip install --upgrade pip # - pip install gnuplotlib - pip install setuptools sphinx - pip install -e . # Only the dependencies needed at import time: the others are mocked # by autodoc_mock_imports in docs/source/conf.py (runner short on disk). - pip install numpy==2.3.5 astropy quart - pip install -e . --no-deps - pip install -r docs/requirements.txt script: - cp noctua/config/nodes.ini.template noctua/config/nodes.ini Loading docs/source/conf.py +9 −0 Changes for docs/source/conf.py: 9 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -25,6 +25,15 @@ extensions = [ 'sphinx.ext.viewcode', # Add links to highlighted source code ] # The CI installs noctua without its dependencies (the runner is short on # disk), only numpy, astropy and quart, which are used at import time # (np.pi arithmetic, astropy models, quart MethodView subclasses): autodoc # imports the modules with the other packages mocked. autodoc_mock_imports = [ 'AtikSDK', 'httpx', 'loguru', 'pipython', 'quart_cors', 'requests', 'telnetlib3', 'uvicorn', 'vmbpy', ] templates_path = ['_templates'] exclude_patterns = [] Loading noctua/api/__init__.py +7 −7 Changes for noctua/api/__init__.py: 7 added lines, 7 removed lines. Original line number Diff line number Diff line Loading @@ -55,13 +55,13 @@ def dynamic_import(url_path): This means a device's API module is shared by every device instance whose class has that same name — e.g. ``tec1``/``tec2``/ ``tec3`` are all instances of ``guider.py``'s ``Guider`` class, so every teccam route resolves to ``noctua.api.guider``, not a per-teccam module. Where that module needs resource classes that live elsewhere (the teccam routes reuse ``camera.py``'s ``FrameBinning``/``Gain``/``Loop``/``SnapshotRaw``/ ``SnapshotState``), it re-exports them with a plain import at the top of the file — see ``guider.py``'s import of those five names. ``tec3`` are all instances of a ``Probe`` class (``stx.Probe``, ``mako.Probe``), so every teccam route resolves to ``noctua.api.probe``, not a per-teccam module. Where that module needs resource classes that live elsewhere (the teccam routes reuse ``camera.py``'s ``FrameBinning``/``Gain``/``Loop``/``SnapshotRaw``/ ``SnapshotState``), it re-exports them with a plain import — see ``probe.py``. """ try: Loading noctua/api/camera.py +16 −3 Changes for noctua/api/camera.py: 16 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -239,6 +239,10 @@ class Loop(BaseResource): """Start the acquisition loop. Body: {"exptime": <float>, "binning": <int>, "gain": <float>} A camera left in error is re-armed first (devices that have ``recover()``, i.e. Mako), so turning the loop switch off and on is how the operator revives it. """ body = await self.get_payload() Loading @@ -246,9 +250,16 @@ class Loop(BaseResource): binning = body.get('binning') gain = body.get('gain') # Everything below talks to the camera (seconds, up to ~10 s for a # recovery): run it off the event loop. def action(): stop_looping = getattr(self.dev, "stop_looping", None) if stop_looping and getattr(self.dev, "looping", False): await self.run_blocking(stop_looping) stop_looping() recover = getattr(self.dev, "recover", None) if recover: recover() if binning is not None: try: Loading @@ -265,11 +276,13 @@ class Loop(BaseResource): self.dev.loop_exposure = exposure self.dev.looping = True return self.make_response({'running': True, 'exposure': exposure}) await self.run_blocking(action) return self.make_response({'running': self.dev.looping, 'exposure': exposure}) async def delete(self): """Stop the acquisition loop.""" self.dev.looping = False return self.make_response({'running': False}) return self.make_response({'running': self.dev.looping}) noctua/api/guider.py +0 −1 Changes for noctua/api/guider.py: 0 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -9,7 +9,6 @@ from noctua.api.guider_instance import guider from noctua.utils.logger import log from .baseresource import BaseResource, expects from .camera import FrameBinning, Gain, Loop, SnapshotRaw, SnapshotState # noqa: F401 — re-exported for dynamic_import (tec1/2/3 class=Guider → module noctua.api.guider) guider_api = Blueprint("guider", __name__) Loading Loading
.gitlab-ci.yml +12 −20 Changes for .gitlab-ci.yml: 12 added lines, 20 removed lines. Original line number Diff line number Diff line Loading @@ -2,33 +2,23 @@ image: python:3.13 variables: PROJECT: "noctua" PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" # The runner is short on disk: no pip cache (downloaded wheels would be # kept twice, and GitLab would also store the cache between jobs). PIP_NO_CACHE_DIR: "1" FORMAT_TARGETS: "${PROJECT}" PYLINT_TARGETS: "${PROJECT}" GIT_USER_EMAIL: "davide.ricci@inaf.it" GIT_USER_NAME: "Davide GitLab CI" FORMATTED_BRANCH_NAME: "validated" cache: key: "$CI_COMMIT_REF_SLUG" paths: - .cache/pip stages: - deploy_docs - setup_and_format - lint - auto_commit # Job 1: We don't actually need to pass artifacts here if we just want to test install install_project: stage: setup_and_format tags: - git-run-ia2 script: - pip install --upgrade pip - pip install -e . # No artifacts needed here unless you are generating files needed by others # The install is tested by run_pylint and pages, which both run # `pip install -e .`: no separate install job (saves runner disk). # Job 2: Remove Trailing Whitespaces fix_trailing_whitespaces: Loading Loading @@ -83,8 +73,9 @@ run_pylint: artifacts: true before_script: - pip install pylint # Install dependencies so pylint can resolve imports - pip install -e . # No dependencies (the runner is short on disk): pylint reports the # unresolved imports, but this job never fails anyway (see `|| echo`). - pip install -e . --no-deps script: - pylint --rcfile=.pylintrc --fail-on=E,F ${PYLINT_TARGETS}/sequencer.py || echo "Pylint finished with issues" Loading @@ -94,11 +85,12 @@ pages: tags: - git-run-ia2 before_script: # - apt-get update -y && apt install -y gnuplot - pip install --upgrade pip # - pip install gnuplotlib - pip install setuptools sphinx - pip install -e . # Only the dependencies needed at import time: the others are mocked # by autodoc_mock_imports in docs/source/conf.py (runner short on disk). - pip install numpy==2.3.5 astropy quart - pip install -e . --no-deps - pip install -r docs/requirements.txt script: - cp noctua/config/nodes.ini.template noctua/config/nodes.ini Loading
docs/source/conf.py +9 −0 Changes for docs/source/conf.py: 9 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -25,6 +25,15 @@ extensions = [ 'sphinx.ext.viewcode', # Add links to highlighted source code ] # The CI installs noctua without its dependencies (the runner is short on # disk), only numpy, astropy and quart, which are used at import time # (np.pi arithmetic, astropy models, quart MethodView subclasses): autodoc # imports the modules with the other packages mocked. autodoc_mock_imports = [ 'AtikSDK', 'httpx', 'loguru', 'pipython', 'quart_cors', 'requests', 'telnetlib3', 'uvicorn', 'vmbpy', ] templates_path = ['_templates'] exclude_patterns = [] Loading
noctua/api/__init__.py +7 −7 Changes for noctua/api/__init__.py: 7 added lines, 7 removed lines. Original line number Diff line number Diff line Loading @@ -55,13 +55,13 @@ def dynamic_import(url_path): This means a device's API module is shared by every device instance whose class has that same name — e.g. ``tec1``/``tec2``/ ``tec3`` are all instances of ``guider.py``'s ``Guider`` class, so every teccam route resolves to ``noctua.api.guider``, not a per-teccam module. Where that module needs resource classes that live elsewhere (the teccam routes reuse ``camera.py``'s ``FrameBinning``/``Gain``/``Loop``/``SnapshotRaw``/ ``SnapshotState``), it re-exports them with a plain import at the top of the file — see ``guider.py``'s import of those five names. ``tec3`` are all instances of a ``Probe`` class (``stx.Probe``, ``mako.Probe``), so every teccam route resolves to ``noctua.api.probe``, not a per-teccam module. Where that module needs resource classes that live elsewhere (the teccam routes reuse ``camera.py``'s ``FrameBinning``/``Gain``/``Loop``/``SnapshotRaw``/ ``SnapshotState``), it re-exports them with a plain import — see ``probe.py``. """ try: Loading
noctua/api/camera.py +16 −3 Changes for noctua/api/camera.py: 16 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -239,6 +239,10 @@ class Loop(BaseResource): """Start the acquisition loop. Body: {"exptime": <float>, "binning": <int>, "gain": <float>} A camera left in error is re-armed first (devices that have ``recover()``, i.e. Mako), so turning the loop switch off and on is how the operator revives it. """ body = await self.get_payload() Loading @@ -246,9 +250,16 @@ class Loop(BaseResource): binning = body.get('binning') gain = body.get('gain') # Everything below talks to the camera (seconds, up to ~10 s for a # recovery): run it off the event loop. def action(): stop_looping = getattr(self.dev, "stop_looping", None) if stop_looping and getattr(self.dev, "looping", False): await self.run_blocking(stop_looping) stop_looping() recover = getattr(self.dev, "recover", None) if recover: recover() if binning is not None: try: Loading @@ -265,11 +276,13 @@ class Loop(BaseResource): self.dev.loop_exposure = exposure self.dev.looping = True return self.make_response({'running': True, 'exposure': exposure}) await self.run_blocking(action) return self.make_response({'running': self.dev.looping, 'exposure': exposure}) async def delete(self): """Stop the acquisition loop.""" self.dev.looping = False return self.make_response({'running': False}) return self.make_response({'running': self.dev.looping})
noctua/api/guider.py +0 −1 Changes for noctua/api/guider.py: 0 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -9,7 +9,6 @@ from noctua.api.guider_instance import guider from noctua.utils.logger import log from .baseresource import BaseResource, expects from .camera import FrameBinning, Gain, Loop, SnapshotRaw, SnapshotState # noqa: F401 — re-exported for dynamic_import (tec1/2/3 class=Guider → module noctua.api.guider) guider_api = Blueprint("guider", __name__) Loading