Skip to content

Commit 7807632

Browse files
authored
Merge pull request #77 from masenf/allow-invalid-tone
Allow invalid tone
2 parents bdb3256 + f4a7534 commit 7807632

6 files changed

Lines changed: 116 additions & 5 deletions

File tree

src/dzcb/k7abd.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
Talkgroup,
3838
Zone,
3939
)
40+
import dzcb.tone
4041

4142

4243
logger = logging.getLogger(__name__)
@@ -321,6 +322,10 @@ def Codeplug_from_k7abd(input_dir):
321322
talkgroups = {}
322323
all_talkgroups_by_name = {}
323324
total_files = 0
325+
if not dzcb.tone.REQUIRE_VALID_TONE:
326+
logger.warning(
327+
"REQUIRE_VALID_TONE=0: resulting codeplug files may contain invalid entries"
328+
)
324329
for p in sorted(d.glob("Analog__*.csv")):
325330
update_zones_channels(
326331
zones, Analog_from_csv(p.read_text().splitlines()), log_filename=p

src/dzcb/model.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,14 @@ def flattened(self, allowed_powers):
159159
"No known powers are allowed {!r} from {!r}".format(self, allowed_powers)
160160
)
161161

162+
@classmethod
163+
def from_any(cls, v):
164+
"""Passable as an attr converter."""
165+
if isinstance(v, str):
166+
# use title case string
167+
v = v.title()
168+
return super(Power, cls).from_any(v)
169+
162170

163171
class Bandwidth(ConvertibleEnum):
164172
_125 = "12.5"
@@ -234,9 +242,13 @@ def transmit_frequency(self):
234242

235243
def _tone_validator(instance, attribute, value):
236244
if value is not None and value not in dzcb.tone.VALID_TONES:
237-
raise ValueError(
238-
"field {!r} has unknown tone {!r}".format(attribute.name, value)
245+
message = "field {!r} for {} has unknown tone {!r}".format(
246+
attribute.name, instance.name, value
239247
)
248+
if dzcb.tone.REQUIRE_VALID_TONE:
249+
raise ValueError(message)
250+
else:
251+
logger.warning(message)
240252

241253

242254
def _tone_converter(value):

src/dzcb/tone.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
"""All valid PL / DCS tones"""
22

3+
from .util import getenv_bool
4+
5+
# set REQUIRE_VALID_TONE=0 in the environment to write non-valid tones
6+
# into codeplug output files
7+
REQUIRE_VALID_TONE = getenv_bool("REQUIRE_VALID_TONE", default=True)
8+
39
VALID_TONES = [
410
"67.0",
511
"69.3",

src/dzcb/util.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import os
2+
3+
4+
STR_TO_BOOL = {
5+
"false": False,
6+
"no": False,
7+
"off": False,
8+
"0": False,
9+
0: False,
10+
"true": True,
11+
"yes": True,
12+
"on": True,
13+
"1": True,
14+
1: True,
15+
}
16+
17+
18+
def getenv_bool(var_name, default=False):
19+
"""
20+
Retrieve the given environment variable as a bool.
21+
22+
Will use the text translation table STR_TO_BOOL to facilitate the conversion
23+
so that "yes"/"no" and "on"/"off" can also be used.
24+
"""
25+
val = os.environ.get(var_name, None)
26+
if val is None:
27+
return default
28+
return STR_TO_BOOL[val.lower()]

tests/test_k7abd.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,23 @@ def test_digital_channels_missing_talkgroup():
8585
assert ch0tg.timeslot == Timeslot.ONE
8686

8787

88-
def test_analog_weird_values():
88+
@pytest.fixture(params=[True, False])
89+
def require_valid_tone(request, monkeypatch):
90+
import dzcb.tone
91+
92+
monkeypatch.setattr(dzcb.tone, "REQUIRE_VALID_TONE", request.param)
93+
return request.param
94+
95+
96+
def test_analog_weird_values(require_valid_tone):
8997
"""
9098
test validation of fields in the csv file
9199
"""
92100

93101
cp = codeplug_from_relative_dir("analog-weird-values").filter()
94102

95-
assert len(cp.zones) == 6
96-
assert len(cp.channels) == 6
103+
assert len(cp.zones) == 6 if require_valid_tone else 9
104+
assert len(cp.channels) == 6 if require_valid_tone else 9
97105

98106
for ch in cp.channels:
99107
if ch.name in ("off", "blank"):
@@ -111,6 +119,20 @@ def test_analog_weird_values():
111119
elif ch.name == "split-tone":
112120
assert ch.tone_decode == "74.4"
113121
assert ch.tone_encode == "254.1"
122+
if require_valid_tone:
123+
assert ch.name != "restricted-in"
124+
assert ch.name != "restricted-out"
125+
assert ch.name != "sixty-nine"
126+
else:
127+
if ch.name == "restricted-in":
128+
assert ch.tone_decode == "restricted"
129+
assert ch.tone_encode is None
130+
elif ch.name == "restricted-out":
131+
assert ch.tone_decode is None
132+
assert ch.tone_encode == "restricted"
133+
elif ch.name == "sixty-nine":
134+
assert ch.tone_decode == "69.0"
135+
assert ch.tone_encode == "69.0"
114136

115137

116138
def test_digital_repeaters_private_contacts():

tests/test_util.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import pytest
2+
3+
import dzcb.util
4+
5+
6+
ENV_VAR_NAME = "TEST_UTIL_ENVVAR"
7+
8+
9+
@pytest.fixture(
10+
params=[
11+
("yes", True),
12+
("on", True),
13+
(0, False),
14+
("no", False),
15+
("off", False),
16+
(None, None), # should use default
17+
("foo", KeyError), # should use default
18+
]
19+
)
20+
def exp_env_bool(request, monkeypatch):
21+
env_value, exp_bool_value = request.param
22+
if env_value is not None:
23+
monkeypatch.setenv(ENV_VAR_NAME, env_value)
24+
return exp_bool_value
25+
26+
27+
@pytest.mark.parametrize("default", [True, False])
28+
def test_getenv_bool(exp_env_bool, default):
29+
if isinstance(exp_env_bool, type) and issubclass(exp_env_bool, Exception):
30+
with pytest.raises(exp_env_bool):
31+
_ = dzcb.util.getenv_bool(ENV_VAR_NAME, default=default)
32+
return
33+
34+
val = dzcb.util.getenv_bool(ENV_VAR_NAME, default=default)
35+
if exp_env_bool is None:
36+
assert val is default
37+
else:
38+
assert val is exp_env_bool

0 commit comments

Comments
 (0)