pywmswebcontrolpro 0.1.1__tar.gz → 0.1.2__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.
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/PKG-INFO +1 -1
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/webcontrol.py +24 -3
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/conftest.py +2 -1
- pywmswebcontrolpro-0.1.2/tests/test_configuration.py +59 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/.github/workflows/release.yaml +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/.github/workflows/validate.yaml +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/.gitignore +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/.python-version +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/LICENSE +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/README.md +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/mypy.ini +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pyproject.toml +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pytest.ini +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/__init__.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/action.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/const.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/destination.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/py.typed +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/refresh.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/room.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/scene.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/store.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/travel.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/requirements_lint.txt +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/requirements_test.txt +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/ruff.toml +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/simulator/simulator.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/__init__.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/test_import.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/test_refresh.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/test_settings.py +0 -0
- {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/test_travel.py +0 -0
|
@@ -4,6 +4,7 @@ import asyncio
|
|
|
4
4
|
import pprint
|
|
5
5
|
import time
|
|
6
6
|
from collections.abc import Mapping
|
|
7
|
+
from dataclasses import dataclass
|
|
7
8
|
from datetime import timedelta
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from types import MappingProxyType
|
|
@@ -33,6 +34,14 @@ DEFAULT_RETRY_DELAY = 1.0
|
|
|
33
34
|
DEFAULT_REQUEST_SPACING = 0.5
|
|
34
35
|
|
|
35
36
|
|
|
37
|
+
@dataclass(frozen=True)
|
|
38
|
+
class ConfigChanges:
|
|
39
|
+
"""Destinations that appeared or disappeared with a configuration refresh."""
|
|
40
|
+
|
|
41
|
+
added: frozenset[int] = frozenset()
|
|
42
|
+
removed: frozenset[int] = frozenset()
|
|
43
|
+
|
|
44
|
+
|
|
36
45
|
class WebControlPro:
|
|
37
46
|
"""Client of one WMS WebControl pro gateway."""
|
|
38
47
|
|
|
@@ -143,15 +152,27 @@ class WebControlPro:
|
|
|
143
152
|
ping = await self._ping()
|
|
144
153
|
return ping["status"] == 0
|
|
145
154
|
|
|
146
|
-
async def refresh(self) ->
|
|
147
|
-
"""Read the configuration and create destinations, rooms and scenes.
|
|
155
|
+
async def refresh(self) -> ConfigChanges:
|
|
156
|
+
"""Read the configuration and create destinations, rooms and scenes.
|
|
157
|
+
|
|
158
|
+
A destination that is already known stays the same object, so its
|
|
159
|
+
actions keep their movement model and stored state. Only new
|
|
160
|
+
destinations are created, and the result names the destinations that
|
|
161
|
+
appeared and disappeared. Rooms and scenes are created again.
|
|
162
|
+
"""
|
|
148
163
|
config = await self._getConfiguration()
|
|
149
164
|
self._config = config
|
|
165
|
+
known = self._dests
|
|
150
166
|
self._dests = {
|
|
151
|
-
dest["id"]: Destination(self, **dest)
|
|
167
|
+
dest["id"]: known.get(dest["id"]) or Destination(self, **dest)
|
|
168
|
+
for dest in config["destinations"]
|
|
152
169
|
}
|
|
153
170
|
self._rooms = {room["id"]: Room(self, **room) for room in config["rooms"]}
|
|
154
171
|
self._scenes = {scene["id"]: Scene(self, **scene) for scene in config["scenes"]}
|
|
172
|
+
return ConfigChanges(
|
|
173
|
+
added=frozenset(self._dests) - frozenset(known),
|
|
174
|
+
removed=frozenset(known) - frozenset(self._dests),
|
|
175
|
+
)
|
|
155
176
|
|
|
156
177
|
def dest(self, name: str) -> Destination:
|
|
157
178
|
"""Return the destination with the given name or raise KeyError."""
|
|
@@ -106,12 +106,13 @@ class FakeGateway:
|
|
|
106
106
|
def __init__(self) -> None:
|
|
107
107
|
self.status_answers: list[dict[str, Any] | Exception] = []
|
|
108
108
|
self.requests: list[dict[str, Any]] = []
|
|
109
|
+
self.config = CONFIG
|
|
109
110
|
|
|
110
111
|
def post(self, url: str, json: dict[str, Any], timeout: int) -> FakeRequest:
|
|
111
112
|
"""Answer one request of the library."""
|
|
112
113
|
self.requests.append(json)
|
|
113
114
|
if json["command"] == "getConfiguration":
|
|
114
|
-
return FakeRequest(
|
|
115
|
+
return FakeRequest(self.config)
|
|
115
116
|
return FakeRequest(self.status_answers.pop(0))
|
|
116
117
|
|
|
117
118
|
@property
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Tests for reading the configuration of the gateway again."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from copy import deepcopy
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pywmswebcontrolpro.webcontrol import ConfigChanges, WebControlPro
|
|
8
|
+
|
|
9
|
+
from .conftest import CONFIG, DEST_ID, FakeGateway
|
|
10
|
+
|
|
11
|
+
NEW_DEST_ID = 8
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _config_with(*dest_ids: int) -> dict[str, Any]:
|
|
15
|
+
"""Return a configuration with copies of the test destination."""
|
|
16
|
+
config = deepcopy(CONFIG)
|
|
17
|
+
template = config["destinations"][0]
|
|
18
|
+
config["destinations"] = [{**template, "id": dest_id} for dest_id in dest_ids]
|
|
19
|
+
return config
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
async def test_first_refresh_reports_all_destinations_as_added(
|
|
23
|
+
make_control: Callable[..., WebControlPro],
|
|
24
|
+
) -> None:
|
|
25
|
+
"""The first read of the configuration finds the destinations."""
|
|
26
|
+
changes = await make_control().refresh()
|
|
27
|
+
|
|
28
|
+
assert changes == ConfigChanges(added=frozenset({DEST_ID}))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
async def test_refresh_reports_added_and_removed_destinations(
|
|
32
|
+
make_control: Callable[..., WebControlPro], gateway: FakeGateway
|
|
33
|
+
) -> None:
|
|
34
|
+
"""A destination that appears or disappears is named in the result."""
|
|
35
|
+
control = make_control()
|
|
36
|
+
await control.refresh()
|
|
37
|
+
gateway.config = _config_with(NEW_DEST_ID)
|
|
38
|
+
|
|
39
|
+
changes = await control.refresh()
|
|
40
|
+
|
|
41
|
+
assert changes == ConfigChanges(
|
|
42
|
+
added=frozenset({NEW_DEST_ID}), removed=frozenset({DEST_ID})
|
|
43
|
+
)
|
|
44
|
+
assert set(control.dests) == {NEW_DEST_ID}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
async def test_refresh_keeps_the_known_destinations(
|
|
48
|
+
make_control: Callable[..., WebControlPro], gateway: FakeGateway
|
|
49
|
+
) -> None:
|
|
50
|
+
"""A known destination stays the same object with its state."""
|
|
51
|
+
control = make_control()
|
|
52
|
+
await control.refresh()
|
|
53
|
+
known = control.dests[DEST_ID]
|
|
54
|
+
gateway.config = _config_with(DEST_ID, NEW_DEST_ID)
|
|
55
|
+
|
|
56
|
+
changes = await control.refresh()
|
|
57
|
+
|
|
58
|
+
assert changes == ConfigChanges(added=frozenset({NEW_DEST_ID}))
|
|
59
|
+
assert control.dests[DEST_ID] is known
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|