Skip to content

Commit 43ca218

Browse files
authored
Merge pull request #191 from Guzz-T/issue/168/obsolete
Throw a KeyError exception if obsolete names are used
2 parents e307db8 + fb6aa22 commit 43ca218

File tree

8 files changed

+1822
-1696
lines changed

8 files changed

+1822
-1696
lines changed

luxtronik/calculations.py

Lines changed: 239 additions & 235 deletions
Large diffs are not rendered by default.

luxtronik/constants.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,7 @@
2424

2525
# Content of response that is contained in responses to discovery broadcast
2626
LUXTRONIK_DISCOVERY_RESPONSE_PREFIX = "2500;111;"
27+
28+
LUXTRONIK_NAME_CHECK_NONE = "none"
29+
LUXTRONIK_NAME_CHECK_PREFERRED = "preferred"
30+
LUXTRONIK_NAME_CHECK_OBSOLETE = "obsolete"

luxtronik/data_vector.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
import logging
44

5+
from luxtronik.constants import (
6+
LUXTRONIK_NAME_CHECK_PREFERRED,
7+
LUXTRONIK_NAME_CHECK_OBSOLETE,
8+
)
9+
510
from luxtronik.datatypes import Unknown
611

712

@@ -11,6 +16,8 @@ class DataVector:
1116
logger = logging.getLogger("Luxtronik.DataVector")
1217
name = "DataVector"
1318

19+
_obsolete = {}
20+
1421
def __init__(self):
1522
"""Initialize DataVector class."""
1623
self._data = {}
@@ -46,9 +53,15 @@ def _lookup(self, target, with_index=False):
4653
except ValueError:
4754
# Get entry by name
4855
target_index = None
56+
obsolete_entry = self._obsolete.get(target, None)
57+
if obsolete_entry:
58+
raise KeyError(f"The name '{target}' is obsolete! Use '{obsolete_entry}' instead.")
4959
for index, entry in self._data.items():
50-
if entry.name == target:
60+
check_result = entry.check_name(target)
61+
if check_result == LUXTRONIK_NAME_CHECK_PREFERRED:
5162
target_index = index
63+
elif check_result == LUXTRONIK_NAME_CHECK_OBSOLETE:
64+
raise KeyError(f"The name '{target}' is obsolete! Use '{entry.name}' instead.")
5265
elif isinstance(target, int):
5366
# Get entry by id
5467
target_index = target

luxtronik/datatypes.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
import socket
55
import struct
66

7+
from luxtronik.constants import (
8+
LUXTRONIK_NAME_CHECK_NONE,
9+
LUXTRONIK_NAME_CHECK_PREFERRED,
10+
LUXTRONIK_NAME_CHECK_OBSOLETE,
11+
)
12+
713
from functools import total_ordering
814

915

@@ -14,12 +20,17 @@ class Base:
1420
datatype_class = None
1521
datatype_unit = None
1622

17-
def __init__(self, name, writeable=False):
23+
def __init__(self, names, writeable=False):
1824
"""Initialize the base data field class. Set the initial raw value to None"""
1925
# save the raw value only since the user value
2026
# could be build at any time
2127
self._raw = None
22-
self.name = name
28+
if isinstance(names, list):
29+
self._names = names
30+
else:
31+
self._names = [names]
32+
assert len(self._names) > 0, "At least one name is required"
33+
assert all(isinstance(name, str) for name in self._names), "Names must be strings"
2334
self.writeable = writeable
2435

2536
@classmethod
@@ -32,6 +43,23 @@ def from_heatpump(cls, value):
3243
"""Converts value from heatpump units."""
3344
return value
3445

46+
@property
47+
def name(self):
48+
"""Return the (most common) name of the entry."""
49+
return self._names[0]
50+
51+
def check_name(self, name):
52+
"""
53+
Check whether a name matches one of the supported entry names.
54+
The result string can be used to trigger a exception for obsolete names.
55+
"""
56+
if name == self.name:
57+
return LUXTRONIK_NAME_CHECK_PREFERRED
58+
elif name in self._names:
59+
return LUXTRONIK_NAME_CHECK_OBSOLETE
60+
else:
61+
return LUXTRONIK_NAME_CHECK_NONE
62+
3563
@property
3664
def value(self):
3765
"""Return the stored value converted from heatpump units."""

luxtronik/parameters.py

Lines changed: 1108 additions & 1108 deletions
Large diffs are not rendered by default.

luxtronik/visibilities.py

Lines changed: 350 additions & 350 deletions
Large diffs are not rendered by default.

tests/test_data_vector.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""Test suite for data_vector module"""
2+
3+
# pylint: disable=too-few-public-methods,invalid-name,too-many-lines
4+
5+
import pytest
6+
from luxtronik.data_vector import DataVector
7+
8+
from luxtronik.datatypes import (
9+
Base,
10+
)
11+
12+
13+
class ObsoleteDataVector(DataVector):
14+
15+
name = "Obsolete"
16+
17+
_obsolete = {
18+
"baz": "foo"
19+
}
20+
21+
def __init__(self):
22+
super().__init__()
23+
self._data = {
24+
0: Base(["foo", "bar"]),
25+
}
26+
27+
28+
class TestDataVector:
29+
"""Test suite for DataVector"""
30+
31+
@pytest.mark.parametrize("name, exception_expected", [
32+
("foo", False),
33+
("bar", True),
34+
("baz", True),
35+
("qux", False),
36+
])
37+
def test_obsolete(self, name, exception_expected):
38+
"""Test cases for initialization"""
39+
obsolete = ObsoleteDataVector()
40+
try:
41+
obsolete.get(name)
42+
assert not exception_expected
43+
except KeyError:
44+
assert exception_expected

tests/test_datatypes.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
import datetime
66

7+
from luxtronik.constants import (
8+
LUXTRONIK_NAME_CHECK_NONE,
9+
LUXTRONIK_NAME_CHECK_PREFERRED,
10+
LUXTRONIK_NAME_CHECK_OBSOLETE,
11+
)
12+
713
from luxtronik.datatypes import (
814
Base,
915
SelectionBase,
@@ -95,6 +101,33 @@ def test_to_heatpump(self):
95101

96102
assert Base.to_heatpump(42) == 42
97103

104+
def test_name(self):
105+
"""Test cases for name property"""
106+
base = Base(["foo", "bar"])
107+
108+
assert base.name == "foo"
109+
110+
def test_empty_name(self):
111+
"""Test cases for name property"""
112+
try:
113+
Base([])
114+
assert False
115+
except Exception:
116+
pass
117+
try:
118+
Base(None)
119+
assert False
120+
except Exception:
121+
pass
122+
123+
def test_check_name(self):
124+
"""Test cases for check_name() function"""
125+
base = Base(["foo", "bar"])
126+
127+
assert base.check_name("foo") == LUXTRONIK_NAME_CHECK_PREFERRED
128+
assert base.check_name("bar") == LUXTRONIK_NAME_CHECK_OBSOLETE
129+
assert base.check_name("baz") == LUXTRONIK_NAME_CHECK_NONE
130+
98131
def test_value_property(self):
99132
"""Test case for value property"""
100133

0 commit comments

Comments
 (0)