Fixing dismantle callsign

This commit is contained in:
Miroslaw Mowinski 2026-02-17 17:11:14 +01:00
parent 8c15ab8c2c
commit 2495d5e237
3 changed files with 47 additions and 7 deletions

View file

@ -56,12 +56,24 @@ class Callinfo(object):
"""
callsign = callsign.upper()
homecall = re.search('[\\d]{0,1}[A-Z]{1,2}\\d([A-Z]{1,4}|\\d{3,3}|\\d{1,3}[A-Z])[A-Z]{0,5}', callsign)
# Prefer splitting on '/', as portable calls often appear as chains like DL/SQ5FOX/M/DL.
# Pick the first token that looks like a real callsign and let higher-level logic validate it.
token_candidates = [token.strip() for token in callsign.split('/') if token.strip()]
token_candidates = [re.sub(r'-\d{1,3}$', '', token) for token in token_candidates]
# Accept typical callsigns and special patterns with digits in the suffix (e.g. 3Z3Z3Z).
token_pattern = re.compile(r'^[\d]{0,1}[A-Z]{1,2}\d{1,4}[A-Z0-9]{1,8}$')
for token in token_candidates:
if token_pattern.match(token):
return token
# Fallback: search inside the string for a callsign-like pattern.
homecall = re.search(r'[\d]{0,1}[A-Z]{1,2}\d{1,4}[A-Z0-9]{1,8}', callsign)
if homecall:
homecall = homecall.group(0)
return homecall
else:
raise ValueError
return homecall.group(0)
raise ValueError
def _iterate_prefix(self, callsign, timestamp=None):
"""truncate call until it corresponds to a Prefix in the database"""
@ -195,6 +207,11 @@ class Callinfo(object):
elif re.match('^[\\d]{0,1}[A-Z]{1,2}\\d{1,4}([A-Z]{1,4}|[A-Z]{1,2}\\d{0,3})[A-Z]{0,5}$', callsign):
return self._iterate_prefix(callsign, timestamp)
# Some special callsigns contain digits in the suffix (e.g. 3Z3Z3Z).
# Fall back to a more permissive pattern and let the prefix database decide.
elif re.match('^[\\d]{0,1}[A-Z]{1,2}\\d{1,4}[A-Z0-9]{1,8}$', callsign):
return self._iterate_prefix(callsign, timestamp)
# callsigns with prefixes (xxx/callsign)
elif re.search('^[A-Z0-9]{1,4}/', entire_callsign):
pfx = re.search('^[A-Z0-9]{1,4}/', entire_callsign)

View file

@ -57,17 +57,23 @@ def fixApiKey(request):
@pytest.fixture(scope="module", params=["clublogapi", "clublogxml", "countryfile"])
def fixGeneralApi(request, fixApiKey):
"""Fixture returning all possible instances of LookupLib"""
if request.param in ("clublogapi", "clublogxml") and not fixApiKey:
pytest.skip("CLUBLOG_APIKEY not set; skipping Clublog-backed tests")
Lib = LookupLib(request.param, fixApiKey)
# pytest.skip("better later")
return(Lib)
@pytest.fixture(scope="module")
def fixClublogApi(request, fixApiKey):
if not fixApiKey:
pytest.skip("CLUBLOG_APIKEY not set; skipping clublogapi tests")
Lib = LookupLib("clublogapi", fixApiKey)
return(Lib)
@pytest.fixture(scope="module")
def fixClublogXML(request, fixApiKey):
if not fixApiKey:
pytest.skip("CLUBLOG_APIKEY not set; skipping clublogxml tests")
Lib = LookupLib("clublogxml", fixApiKey)
return(Lib)
@ -78,6 +84,8 @@ def fixCountryFile(request):
@pytest.fixture(scope="module", params=["clublogxml", "countryfile"])
def fix_callinfo(request, fixApiKey):
if request.param == "clublogxml" and not fixApiKey:
pytest.skip("CLUBLOG_APIKEY not set; skipping clublogxml-based callinfo tests")
lib = LookupLib(request.param, fixApiKey)
callinfo = Callinfo(lib)
return(callinfo)

View file

@ -272,8 +272,22 @@ class Test_callinfo_methods:
assert not fix_callinfo.check_if_beacon("DH1TW")
def test_get_homecall(self, fix_callinfo):
assert fix_callinfo.get_homecall("HB9/DH1TW") == "DH1TW"
assert fix_callinfo.get_homecall("SM3/DH1TW/P") == "DH1TW"
cases = [
("HB9/DH1TW", "DH1TW"),
("SM3/DH1TW/P", "DH1TW"),
("SP5ABC", "SP5ABC"),
("SP/SP5ABC", "SP5ABC"),
("SP5ABC/W5", "SP5ABC"),
("DL/SQ5FOX/M/DL", "SQ5FOX"),
("3z3z3z", "3Z3Z3Z"),
("DL/3z3z3z", "3Z3Z3Z"),
("DL/3z3z3z/am/m/ok", "3Z3Z3Z"),
("N0CALL/P", "N0CALL"),
("W5/N0CALL", "N0CALL"),
]
for input_call, expected in cases:
assert fix_callinfo.get_homecall(input_call) == expected
with pytest.raises(ValueError):
fix_callinfo.get_homecall("QRM")
@ -395,6 +409,7 @@ class Test_callinfo_methods:
def test_is_valid_callsign(self, fix_callinfo):
assert fix_callinfo.is_valid_callsign("DH1TW")
assert fix_callinfo.is_valid_callsign("3Z3Z3Z")
assert not fix_callinfo.is_valid_callsign("QRM")
def test_get_lat_long(self, fix_callinfo):