pyobs-brot 2.0.0.dev12__tar.gz → 2.0.0.dev14__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_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/.github/dependabot.yml +5 -0
- pyobs_brot-2.0.0.dev14/.github/workflows/pyrefly.yml +23 -0
- pyobs_brot-2.0.0.dev14/.github/workflows/pytest.yml +25 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/PKG-INFO +3 -3
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/pyobs_brot/brotdome.py +4 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/pyobs_brot/brotroof.py +4 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/pyobs_brot/brottelescope.py +10 -2
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/pyproject.toml +8 -3
- pyobs_brot-2.0.0.dev14/specs/index.md +17 -0
- pyobs_brot-2.0.0.dev14/tests/test_brotroof.py +34 -0
- pyobs_brot-2.0.0.dev14/tests/test_brottelescope.py +109 -0
- pyobs_brot-2.0.0.dev14/tests/test_import.py +49 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/uv.lock +1048 -787
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/.github/workflows/pypi.yml +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/.github/workflows/ruff.yml +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/.gitignore +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/.pre-commit-config.yaml +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/.readthedocs.yml +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/LICENSE +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/README.md +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/docs/Makefile +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/docs/make.bat +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/docs/requirements.txt +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/docs/source/_static/pyobs.gif +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/docs/source/conf.py +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/docs/source/index.rst +0 -0
- {pyobs_brot-2.0.0.dev12 → pyobs_brot-2.0.0.dev14}/pyobs_brot/__init__.py +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: pyrefly
|
|
2
|
+
on: push
|
|
3
|
+
|
|
4
|
+
jobs:
|
|
5
|
+
pyrefly:
|
|
6
|
+
runs-on: ubuntu-latest
|
|
7
|
+
timeout-minutes: 10
|
|
8
|
+
|
|
9
|
+
steps:
|
|
10
|
+
- name: Check out repository code
|
|
11
|
+
uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- name: Set up Python
|
|
14
|
+
uses: astral-sh/setup-uv@v5
|
|
15
|
+
with:
|
|
16
|
+
enable-cache: true
|
|
17
|
+
python-version: "3.13"
|
|
18
|
+
|
|
19
|
+
- name: Install packages
|
|
20
|
+
run: uv sync --all-extras --dev
|
|
21
|
+
|
|
22
|
+
- name: Run pyrefly
|
|
23
|
+
run: uv run pyrefly check
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: PyTest
|
|
2
|
+
on: push
|
|
3
|
+
|
|
4
|
+
jobs:
|
|
5
|
+
test:
|
|
6
|
+
runs-on: ubuntu-latest
|
|
7
|
+
timeout-minutes: 10
|
|
8
|
+
|
|
9
|
+
steps:
|
|
10
|
+
- name: Check out repository code
|
|
11
|
+
uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- name: Set up Python
|
|
14
|
+
uses: astral-sh/setup-uv@v5
|
|
15
|
+
with:
|
|
16
|
+
enable-cache: true
|
|
17
|
+
python-version: "3.13"
|
|
18
|
+
|
|
19
|
+
- name: Install packages
|
|
20
|
+
run: uv sync --all-extras --dev
|
|
21
|
+
|
|
22
|
+
- name: Run tests
|
|
23
|
+
run: uv run pytest tests
|
|
24
|
+
env:
|
|
25
|
+
CI: true
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: pyobs-brot
|
|
3
|
-
Version: 2.0.0.
|
|
3
|
+
Version: 2.0.0.dev14
|
|
4
4
|
Summary: pyobs module for BROTlib telescopes
|
|
5
5
|
Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>, Lukas Melzig <lukas.melzig@stud.uni-goettingen.de>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -9,4 +9,4 @@ Requires-Python: >=3.11
|
|
|
9
9
|
Requires-Dist: astropy<8,>=7.0.1
|
|
10
10
|
Requires-Dist: paho-mqtt>=2.1.0
|
|
11
11
|
Requires-Dist: pybrotlib>=1.1.5
|
|
12
|
-
Requires-Dist: pyobs-core<3,>=2.0.0.
|
|
12
|
+
Requires-Dist: pyobs-core<3,>=2.0.0.dev48
|
|
@@ -76,6 +76,10 @@ class BrotDome(BaseDome, IDome):
|
|
|
76
76
|
|
|
77
77
|
@timeout(300)
|
|
78
78
|
async def init(self, **kwargs: Any) -> None:
|
|
79
|
+
# weather?
|
|
80
|
+
if not self.is_weather_good():
|
|
81
|
+
raise exc.InitError("Weather seems to be bad.")
|
|
82
|
+
|
|
79
83
|
log.info("Opening roof")
|
|
80
84
|
if self.brot.dome.shutter == DomeShutterStatus.OPEN:
|
|
81
85
|
return
|
|
@@ -60,6 +60,10 @@ class BrotRoof(BaseRoof):
|
|
|
60
60
|
|
|
61
61
|
@timeout(300)
|
|
62
62
|
async def init(self, **kwargs: Any) -> None:
|
|
63
|
+
# weather?
|
|
64
|
+
if not self.is_weather_good():
|
|
65
|
+
raise exc.InitError("Weather seems to be bad.")
|
|
66
|
+
|
|
63
67
|
log.info("Opening roof")
|
|
64
68
|
if self.brot.roof.status == RoofStatus.OPEN:
|
|
65
69
|
return
|
|
@@ -95,6 +95,10 @@ class BrotBaseTelescope(
|
|
|
95
95
|
await self.comm.set_state(IOffsetsRaDec, RaDecOffsetState(ra=0.0, dec=0.0))
|
|
96
96
|
await self.comm.set_state(IOffsetsAltAz, AltAzOffsetState(alt=0.0, az=0.0))
|
|
97
97
|
|
|
98
|
+
# placeholder -- real readings only exist once the MQTT client has had a chance to
|
|
99
|
+
# receive telemetry, which _update_task() (started above) hasn't had time to do yet
|
|
100
|
+
await self.comm.set_state(ITemperatures, TemperaturesState(readings=[]))
|
|
101
|
+
|
|
98
102
|
async def close(self) -> None:
|
|
99
103
|
await BaseTelescope.close(self)
|
|
100
104
|
await self.mqtt.close()
|
|
@@ -238,6 +242,10 @@ class BrotBaseTelescope(
|
|
|
238
242
|
|
|
239
243
|
@timeout(120)
|
|
240
244
|
async def init(self, **kwargs: Any) -> None:
|
|
245
|
+
# weather?
|
|
246
|
+
if not self.is_weather_good():
|
|
247
|
+
raise exc.InitError("Weather seems to be bad.")
|
|
248
|
+
|
|
241
249
|
match self.brot.telescope.status:
|
|
242
250
|
case TelescopeStatus.PARKED:
|
|
243
251
|
pass
|
|
@@ -324,8 +332,8 @@ class BrotRaDecTelescope(BrotBaseTelescope, IOffsetsRaDec):
|
|
|
324
332
|
await self.brot.telescope.set_offset_dec(ddec * 3600)
|
|
325
333
|
MAX_TARGET_DISTANCE = 2.0 / 3600.0
|
|
326
334
|
while (
|
|
327
|
-
self.brot.telescope._telemetry.POSITION.INSTRUMENTAL.HA.TARGETDISTANCE
|
|
328
|
-
|
|
335
|
+
self.brot.telescope._telemetry.POSITION.INSTRUMENTAL.HA.TARGETDISTANCE > MAX_TARGET_DISTANCE
|
|
336
|
+
or self.brot.telescope._telemetry.POSITION.INSTRUMENTAL.DEC.TARGETDISTANCE > MAX_TARGET_DISTANCE
|
|
329
337
|
):
|
|
330
338
|
await asyncio.sleep(0.1)
|
|
331
339
|
await self.comm.set_state(IOffsetsRaDec, RaDecOffsetState(ra=dra, dec=ddec))
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pyobs-brot"
|
|
3
|
-
version = "2.0.0.
|
|
3
|
+
version = "2.0.0.dev14"
|
|
4
4
|
description = "pyobs module for BROTlib telescopes"
|
|
5
5
|
authors = [{ name = "Tim-Oliver Husser", email = "thusser@uni-goettingen.de" }, { name = "Lukas Melzig", email = "lukas.melzig@stud.uni-goettingen.de" }]
|
|
6
6
|
requires-python = ">=3.11"
|
|
7
7
|
license = "MIT"
|
|
8
8
|
dependencies = [
|
|
9
9
|
"astropy>=7.0.1,<8",
|
|
10
|
-
"pyobs-core>=2.0.0.
|
|
10
|
+
"pyobs-core>=2.0.0.dev48,<3",
|
|
11
11
|
"paho-mqtt>=2.1.0",
|
|
12
12
|
"pybrotlib>=1.1.5",
|
|
13
13
|
]
|
|
14
14
|
|
|
15
15
|
[dependency-groups]
|
|
16
16
|
dev = [
|
|
17
|
-
"black>=23.7.0,<
|
|
17
|
+
"black>=23.7.0,<27",
|
|
18
18
|
"ruff>=0.9.0",
|
|
19
19
|
"pyrefly>=1.1.1",
|
|
20
20
|
"pre-commit>=3.3.3,<5",
|
|
21
|
+
"pytest>=8.0.0",
|
|
22
|
+
"pytest-asyncio>=0.24.0",
|
|
21
23
|
]
|
|
22
24
|
|
|
23
25
|
[build-system]
|
|
@@ -37,3 +39,6 @@ select = ["E", "F", "W", "I", "UP", "G"]
|
|
|
37
39
|
|
|
38
40
|
[tool.pyrefly]
|
|
39
41
|
python-version = "3.11"
|
|
42
|
+
|
|
43
|
+
[tool.pytest.ini_options]
|
|
44
|
+
asyncio_mode = "strict"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Design/planning docs
|
|
2
|
+
|
|
3
|
+
This repo has no `specs/` structure of its own. Design docs, implementation plans, and ADRs that
|
|
4
|
+
concern `pyobs-brot` — including ones actually implemented here — live in `pyobs-core`'s `specs/`
|
|
5
|
+
tree instead (`specs/design/`, `specs/plans/`, `specs/adrs/`), each tagged with a `Repos:` line
|
|
6
|
+
naming every repo it concerns. See `pyobs-core/CLAUDE.md`'s "Cross-repo docs" section.
|
|
7
|
+
|
|
8
|
+
Relevant so far:
|
|
9
|
+
|
|
10
|
+
- `pyobs-core/specs/plans/ejabberd-throughput-benchmarking.md` — XMPP/ejabberd throughput
|
|
11
|
+
benchmarking, including a production incident investigation involving `BrotDome`/
|
|
12
|
+
`BrotRaDecTelescope` on `pyobs-iag50` (disco#info capability fetches silently timing out after a
|
|
13
|
+
few modules restart together) and the `pybrotlib` `MQTTTransport.run()` event-loop-starvation fix
|
|
14
|
+
found along the way.
|
|
15
|
+
- `pyobs-core/specs/plans/enforce-state-publishing.md` — the state-publishing convention every
|
|
16
|
+
`Module` follows; `BrotRaDecTelescope`'s `ITemperatures` state had the same gap this doc's
|
|
17
|
+
convention exists to catch (2026-07-27 addendum).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Unit tests for the roof-status -> motion-status mapping in BrotRoof.
|
|
2
|
+
|
|
3
|
+
The BROT/MQTT backend is mocked out; only the state mapping is exercised.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from unittest.mock import MagicMock
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
from pybrotlib.components.roof import RoofStatus
|
|
10
|
+
from pyobs.utils.enums import MotionStatus
|
|
11
|
+
|
|
12
|
+
from pyobs_brot import BrotRoof
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.mark.parametrize(
|
|
16
|
+
("status", "expected"),
|
|
17
|
+
[
|
|
18
|
+
(RoofStatus.ERROR, MotionStatus.ERROR),
|
|
19
|
+
(RoofStatus.CLOSED, MotionStatus.PARKED),
|
|
20
|
+
(RoofStatus.OPENING, MotionStatus.INITIALIZING),
|
|
21
|
+
(RoofStatus.CLOSING, MotionStatus.PARKING),
|
|
22
|
+
(RoofStatus.OPEN, MotionStatus.POSITIONED),
|
|
23
|
+
(RoofStatus.STOPPED, MotionStatus.IDLE),
|
|
24
|
+
],
|
|
25
|
+
)
|
|
26
|
+
@pytest.mark.asyncio
|
|
27
|
+
async def test_update_status_mapping(status: RoofStatus, expected: MotionStatus) -> None:
|
|
28
|
+
roof = BrotRoof(host="localhost", name="roof")
|
|
29
|
+
roof.brot.roof = MagicMock()
|
|
30
|
+
roof.brot.roof.status = status
|
|
31
|
+
|
|
32
|
+
await roof._update_status()
|
|
33
|
+
|
|
34
|
+
assert roof.motion_status() == expected
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Unit tests for the non-hardware logic in the BROT telescope drivers: constructor
|
|
2
|
+
state, focus-offset composition, and the RA/Dec offset scaling + convergence wait.
|
|
3
|
+
|
|
4
|
+
The BROT/MQTT backend (self.brot) is mocked out; hardware I/O itself is out of scope.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from types import SimpleNamespace
|
|
8
|
+
from typing import Any
|
|
9
|
+
from unittest.mock import AsyncMock, MagicMock
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
from pyobs.interfaces import IFocuser, IOffsetsRaDec
|
|
13
|
+
|
|
14
|
+
from pyobs_brot import BrotRaDecTelescope
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_constructor_defaults() -> None:
|
|
18
|
+
telescope = BrotRaDecTelescope(host="localhost", name="telescope")
|
|
19
|
+
assert telescope.temperatures == {}
|
|
20
|
+
assert telescope.focus_offset == 0.0
|
|
21
|
+
assert telescope._roof == "None"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_constructor_temperatures_and_roof() -> None:
|
|
25
|
+
telescope = BrotRaDecTelescope(
|
|
26
|
+
host="localhost",
|
|
27
|
+
name="telescope",
|
|
28
|
+
temperatures={"ccd": "T1"},
|
|
29
|
+
roof="some-roof",
|
|
30
|
+
)
|
|
31
|
+
assert telescope.temperatures == {"ccd": "T1"}
|
|
32
|
+
assert telescope._roof == "some-roof"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.mark.asyncio
|
|
36
|
+
async def test_set_focus_offset_composes_and_publishes() -> None:
|
|
37
|
+
telescope = BrotRaDecTelescope(host="localhost", name="telescope")
|
|
38
|
+
telescope.brot.focus = MagicMock()
|
|
39
|
+
telescope.brot.focus.position = 10.0
|
|
40
|
+
telescope.brot.focus.set = AsyncMock()
|
|
41
|
+
telescope._wait_for_focus = AsyncMock() # type: ignore[method-assign]
|
|
42
|
+
telescope.comm.set_state = AsyncMock() # type: ignore[method-assign]
|
|
43
|
+
|
|
44
|
+
await telescope.set_focus_offset(0.25)
|
|
45
|
+
|
|
46
|
+
# the hardware call adds the offset onto the current position...
|
|
47
|
+
telescope.brot.focus.set.assert_awaited_once_with(10.25)
|
|
48
|
+
assert telescope.focus_offset == 0.25
|
|
49
|
+
|
|
50
|
+
# ...and the published focus subtracts the offset back out of the new position
|
|
51
|
+
assert telescope.comm.set_state.await_args is not None
|
|
52
|
+
interface, state = telescope.comm.set_state.await_args.args
|
|
53
|
+
assert interface is IFocuser
|
|
54
|
+
assert (state.focus, state.focus_offset) == (9.75, 0.25)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _telemetry(ha_dist: float, dec_dist: float) -> Any:
|
|
58
|
+
return SimpleNamespace(
|
|
59
|
+
POSITION=SimpleNamespace(
|
|
60
|
+
INSTRUMENTAL=SimpleNamespace(
|
|
61
|
+
HA=SimpleNamespace(TARGETDISTANCE=ha_dist),
|
|
62
|
+
DEC=SimpleNamespace(TARGETDISTANCE=dec_dist),
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@pytest.mark.asyncio
|
|
69
|
+
async def test_set_offsets_radec_sends_scaled_and_sign_flipped_offsets() -> None:
|
|
70
|
+
telescope = BrotRaDecTelescope(host="localhost", name="telescope")
|
|
71
|
+
telescope.brot.telescope.set_offset_ha = AsyncMock() # type: ignore[method-assign]
|
|
72
|
+
telescope.brot.telescope.set_offset_dec = AsyncMock() # type: ignore[method-assign]
|
|
73
|
+
telescope.brot.telescope._telemetry = _telemetry(0.0, 0.0) # already converged
|
|
74
|
+
telescope.comm.set_state = AsyncMock() # type: ignore[method-assign]
|
|
75
|
+
|
|
76
|
+
await telescope.set_offsets_radec(0.001, 0.002)
|
|
77
|
+
|
|
78
|
+
# HA is sign-flipped (RA east is HA west) and both are scaled deg -> arcsec
|
|
79
|
+
telescope.brot.telescope.set_offset_ha.assert_awaited_once_with(-3.6)
|
|
80
|
+
telescope.brot.telescope.set_offset_dec.assert_awaited_once_with(7.2)
|
|
81
|
+
assert telescope.comm.set_state.await_args is not None
|
|
82
|
+
interface, state = telescope.comm.set_state.await_args.args
|
|
83
|
+
assert interface is IOffsetsRaDec
|
|
84
|
+
assert (state.ra, state.dec) == (0.001, 0.002)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@pytest.mark.asyncio
|
|
88
|
+
async def test_set_offsets_radec_waits_until_both_axes_converge(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
89
|
+
telescope = BrotRaDecTelescope(host="localhost", name="telescope")
|
|
90
|
+
telescope.brot.telescope.set_offset_ha = AsyncMock() # type: ignore[method-assign]
|
|
91
|
+
telescope.brot.telescope.set_offset_dec = AsyncMock() # type: ignore[method-assign]
|
|
92
|
+
telescope.comm.set_state = AsyncMock() # type: ignore[method-assign]
|
|
93
|
+
|
|
94
|
+
# still slewing for two polls (HA, then DEC, still off-target), converged on the third
|
|
95
|
+
readings = [(1.0, 1.0), (1.0, 0.0), (0.0, 0.0)]
|
|
96
|
+
telescope.brot.telescope._telemetry = _telemetry(*readings[0])
|
|
97
|
+
|
|
98
|
+
sleep_calls = 0
|
|
99
|
+
|
|
100
|
+
async def fake_sleep(_seconds: float) -> None:
|
|
101
|
+
nonlocal sleep_calls
|
|
102
|
+
sleep_calls += 1
|
|
103
|
+
telescope.brot.telescope._telemetry = _telemetry(*readings[sleep_calls])
|
|
104
|
+
|
|
105
|
+
monkeypatch.setattr("pyobs_brot.brottelescope.asyncio.sleep", fake_sleep)
|
|
106
|
+
|
|
107
|
+
await telescope.set_offsets_radec(0.001, 0.002)
|
|
108
|
+
|
|
109
|
+
assert sleep_calls == 2
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Smoke tests: import every public module and instantiate each driver class without
|
|
2
|
+
hardware, asserting the interfaces they claim.
|
|
3
|
+
|
|
4
|
+
pybrotlib is a pure-Python MQTT client that connects at connect() time, not at
|
|
5
|
+
construction, so instantiation is safe with no broker running.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pyobs.interfaces import (
|
|
9
|
+
IDome,
|
|
10
|
+
IFocuser,
|
|
11
|
+
IOffsetsAltAz,
|
|
12
|
+
IOffsetsRaDec,
|
|
13
|
+
IPointingAltAz,
|
|
14
|
+
IPointingRaDec,
|
|
15
|
+
IRoof,
|
|
16
|
+
ITemperatures,
|
|
17
|
+
)
|
|
18
|
+
from pyobs.modules import Module
|
|
19
|
+
|
|
20
|
+
from pyobs_brot import BrotDome, BrotRaDecTelescope, BrotRoof
|
|
21
|
+
from pyobs_brot.brottelescope import BrotAltAzTelescope
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_instantiate_dome() -> None:
|
|
25
|
+
dome = BrotDome(host="localhost", name="dome")
|
|
26
|
+
assert isinstance(dome, Module)
|
|
27
|
+
assert isinstance(dome, IDome)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_instantiate_roof() -> None:
|
|
31
|
+
roof = BrotRoof(host="localhost", name="roof")
|
|
32
|
+
assert isinstance(roof, Module)
|
|
33
|
+
assert isinstance(roof, IRoof)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_instantiate_radec_telescope() -> None:
|
|
37
|
+
telescope = BrotRaDecTelescope(host="localhost", name="telescope")
|
|
38
|
+
assert isinstance(telescope, Module)
|
|
39
|
+
assert isinstance(telescope, IFocuser)
|
|
40
|
+
assert isinstance(telescope, ITemperatures)
|
|
41
|
+
assert isinstance(telescope, IPointingRaDec)
|
|
42
|
+
assert isinstance(telescope, IPointingAltAz)
|
|
43
|
+
assert isinstance(telescope, IOffsetsRaDec)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_instantiate_altaz_telescope() -> None:
|
|
47
|
+
telescope = BrotAltAzTelescope(host="localhost", name="telescope")
|
|
48
|
+
assert isinstance(telescope, Module)
|
|
49
|
+
assert isinstance(telescope, IOffsetsAltAz)
|