More ruff linter fixes

This commit is contained in:
Ian Renton
2026-08-15 08:43:19 +01:00
parent dd89ff4af7
commit a6e54f524d
43 changed files with 99 additions and 153 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
import importlib import importlib
import logging import logging
import os import os
import sys
import yaml import yaml
@@ -11,7 +12,7 @@ if not os.path.isfile("config.yml"):
logger.error( logger.error(
"Your config file is missing. Ensure you have copied config-example.yml to config.yml and updated it according to your needs." "Your config file is missing. Ensure you have copied config-example.yml to config.yml and updated it according to your needs."
) )
exit() sys.exit()
# Load config # Load config
with open("config.yml") as f: with open("config.yml") as f:
+2 -2
View File
@@ -73,7 +73,7 @@ def lat_lon_for_grid_sw_corner(grid):
"""Convert a Maidenhead grid reference of arbitrary precision to the lat/long of the southwest corner of the square. """Convert a Maidenhead grid reference of arbitrary precision to the lat/long of the southwest corner of the square.
Returns None if the grid format is invalid.""" Returns None if the grid format is invalid."""
lat, lon, lat_cell_size, lon_cell_size = lat_lon_for_grid_sw_corner_plus_size(grid) lat, lon, _lat_cell_size, _lon_cell_size = lat_lon_for_grid_sw_corner_plus_size(grid)
if lat is not None and lon is not None: if lat is not None and lon is not None:
return [lat, lon] return [lat, lon]
else: else:
@@ -156,7 +156,7 @@ def lat_lon_for_grid_sw_corner_plus_size(grid):
lat -= 90.0 lat -= 90.0
# Return None values on maths errors # Return None values on maths errors
if any(x != x for x in [lat, lon, lat_cell_size, lon_cell_size]): # NaN check if any(x != x for x in [lat, lon, lat_cell_size, lon_cell_size]):
return None, None, None, None return None, None, None, None
return lat, lon, lat_cell_size, lon_cell_size return lat, lon, lat_cell_size, lon_cell_size
+1 -1
View File
@@ -71,7 +71,7 @@ class LiveDataCache:
data = [(k, v, time.time()) for k, v in self._cache.items()] data = [(k, v, time.time()) for k, v in self._cache.items()]
try: try:
self._disk_cache.set("snapshot", data) self._disk_cache.set("snapshot", data)
except Exception as e: except Exception:
logger.exception(f"Failed to write snapshot to {self._snapshot_dir}") logger.exception(f"Failed to write snapshot to {self._snapshot_dir}")
def _load_snapshot(self): def _load_snapshot(self):
+1 -1
View File
@@ -60,7 +60,7 @@ def get_sig_ref_info(sig, ref_id):
sig_ref.grid = latlong_to_locator(ll[0], ll[1], 6) sig_ref.grid = latlong_to_locator(ll[0], ll[1], 6)
sig_ref.latitude = ll[0] sig_ref.latitude = ll[0]
sig_ref.longitude = ll[1] sig_ref.longitude = ll[1]
except: except Exception:
logger.warning("Invalid lat/lon received for WAB/WAI reference") logger.warning("Invalid lat/lon received for WAB/WAI reference")
return sig_ref return sig_ref
+12 -42
View File
@@ -54,9 +54,7 @@ class StatusReporter:
DATA_STORE.status_data["mem_use_mb"] = round(psutil.Process(os.getpid()).memory_info().rss / (1024 * 1024), 3) DATA_STORE.status_data["mem_use_mb"] = round(psutil.Process(os.getpid()).memory_info().rss / (1024 * 1024), 3)
DATA_STORE.status_data["num_spots"] = len(DATA_STORE.spots.values()) DATA_STORE.status_data["num_spots"] = len(DATA_STORE.spots.values())
DATA_STORE.status_data["num_alerts"] = len(DATA_STORE.alerts.values()) DATA_STORE.status_data["num_alerts"] = len(DATA_STORE.alerts.values())
DATA_STORE.status_data["spot_providers"] = list( DATA_STORE.status_data["spot_providers"] = [{
map(
lambda p: {
"name": p.name, "name": p.name,
"enabled": p.enabled, "enabled": p.enabled,
"enabled_by_default_in_web_ui": p.enabled_by_default_in_web_ui, "enabled_by_default_in_web_ui": p.enabled_by_default_in_web_ui,
@@ -67,52 +65,32 @@ class StatusReporter:
"last_spot": p.last_spot_time.replace(tzinfo=pytz.UTC).timestamp() "last_spot": p.last_spot_time.replace(tzinfo=pytz.UTC).timestamp()
if p.last_spot_time.year > 2000 if p.last_spot_time.year > 2000
else 0, else 0,
}, } for p in DATA_PROVIDERS.spot_providers]
DATA_PROVIDERS.spot_providers, DATA_STORE.status_data["alert_providers"] = [{
)
)
DATA_STORE.status_data["alert_providers"] = list(
map(
lambda p: {
"name": p.name, "name": p.name,
"enabled": p.enabled, "enabled": p.enabled,
"status": p.status, "status": p.status,
"last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp() "last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp()
if p.last_update_time.year > 2000 if p.last_update_time.year > 2000
else 0, else 0,
}, } for p in DATA_PROVIDERS.alert_providers]
DATA_PROVIDERS.alert_providers, DATA_STORE.status_data["solar_condition_providers"] = [{
)
)
DATA_STORE.status_data["solar_condition_providers"] = list(
map(
lambda p: {
"name": p.name, "name": p.name,
"enabled": p.enabled, "enabled": p.enabled,
"status": p.status, "status": p.status,
"last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp() "last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp()
if p.last_update_time.year > 2000 if p.last_update_time.year > 2000
else 0, else 0,
}, } for p in DATA_PROVIDERS.solar_condition_providers]
DATA_PROVIDERS.solar_condition_providers, DATA_STORE.status_data["static_data_providers"] = [{
)
)
DATA_STORE.status_data["static_data_providers"] = list(
map(
lambda p: {
"name": p.name, "name": p.name,
"enabled": p.enabled, "enabled": p.enabled,
"status": p.status, "status": p.status,
"last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp() "last_updated": p.last_update_time.replace(tzinfo=pytz.UTC).timestamp()
if p.last_update_time.year > 2000 if p.last_update_time.year > 2000
else 0, else 0,
}, } for p in DATA_PROVIDERS.static_data_providers]
DATA_PROVIDERS.static_data_providers, DATA_STORE.status_data["sig_ref_data_providers"] = [{
)
)
DATA_STORE.status_data["sig_ref_data_providers"] = list(
map(
lambda p: {
"sig_name": p.sig_name, "sig_name": p.sig_name,
"enabled": p.enabled, "enabled": p.enabled,
"status": p.status, "status": p.status,
@@ -120,13 +98,8 @@ class StatusReporter:
if p.last_update_time.year > 2000 if p.last_update_time.year > 2000
else 0, else 0,
"reference_count": p.reference_count, "reference_count": p.reference_count,
}, } for p in DATA_PROVIDERS.sig_ref_data_providers]
DATA_PROVIDERS.sig_ref_data_providers, DATA_STORE.status_data["callsign_data_providers"] = [{
)
)
DATA_STORE.status_data["callsign_data_providers"] = list(
map(
lambda p: {
"name": p.name, "name": p.name,
"enabled": p.enabled, "enabled": p.enabled,
"status": p.status, "status": p.status,
@@ -134,10 +107,7 @@ class StatusReporter:
if p.last_update_time.year > 2000 if p.last_update_time.year > 2000
else 0, else 0,
"lookup_count": p.lookup_count, "lookup_count": p.lookup_count,
}, } for p in DATA_PROVIDERS.callsign_data_providers]
DATA_PROVIDERS.callsign_data_providers,
)
)
DATA_STORE.status_data["cleanup"] = { DATA_STORE.status_data["cleanup"] = {
"status": CLEANUP_TIMER.status, "status": CLEANUP_TIMER.status,
"last_ran": CLEANUP_TIMER.last_cleanup_time.replace(tzinfo=pytz.UTC).timestamp() "last_ran": CLEANUP_TIMER.last_cleanup_time.replace(tzinfo=pytz.UTC).timestamp()
+7 -7
View File
@@ -32,7 +32,7 @@ def infer_mode_from_comment(comment):
for mode in ALL_MODES: for mode in ALL_MODES:
if mode in comment.upper(): if mode in comment.upper():
return mode return mode
for mode in MODE_ALIASES.keys(): for mode in MODE_ALIASES:
if mode in comment.upper(): if mode in comment.upper():
return MODE_ALIASES[mode] return MODE_ALIASES[mode]
return None return None
@@ -101,7 +101,7 @@ def infer_mode_from_frequency(freq):
def get_flag_for_dxcc(dxcc): def get_flag_for_dxcc(dxcc):
"""Get an emoji flag for a given DXCC entity ID""" """Get an emoji flag for a given DXCC entity ID"""
dxcc_data = DATA_STORE.dxcc_data[dxcc] if dxcc in DATA_STORE.dxcc_data else None dxcc_data = DATA_STORE.dxcc_data.get(dxcc, None)
return dxcc_data["flag"] if dxcc_data else None return dxcc_data["flag"] if dxcc_data else None
@@ -113,11 +113,11 @@ def get_callsign_object_from_pyhamtools_callinfo(callsign, callinfo):
home_call = callinfo.get_homecall(callsign) home_call = callinfo.get_homecall(callsign)
data = callinfo.get_all(callsign) data = callinfo.get_all(callsign)
country = data["country"] if "country" in data else None country = data.get("country", None)
dxcc_id = data["adif"] if "adif" in data else None dxcc_id = data.get("adif", None)
continent = data["continent"] if "continent" in data else None continent = data.get("continent", None)
cq_zone = data["cqz"] if "cqz" in data else None cq_zone = data.get("cqz", None)
itu_zone = data["ituz"] if "ituz" in data else None itu_zone = data.get("ituz", None)
lat = float(data["latitude"]) if "latitude" in data else None lat = float(data["latitude"]) if "latitude" in data else None
lon = float(data["longitude"]) if "longitude" in data else None lon = float(data["longitude"]) if "longitude" in data else None
grid = None grid = None
+1 -1
View File
@@ -127,7 +127,7 @@ class Alert:
# DX operator name lookup, using QRZ.com/HamQTH. # DX operator name lookup, using QRZ.com/HamQTH.
if self.dx_calls and not self.dx_names: if self.dx_calls and not self.dx_names:
self.dx_names = list(map(lambda c: get_call_info(c, credentials).name, self.dx_calls)) self.dx_names = [get_call_info(c, credentials).name for c in self.dx_calls]
except Exception: except Exception:
logger.exception("Exception while inferring missing data from spot") logger.exception("Exception while inferring missing data from spot")
+5 -4
View File
@@ -4,6 +4,7 @@ import logging
import re import re
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timedelta from datetime import datetime, timedelta
from math import isnan
import pytz import pytz
from pyhamtools.locator import latlong_to_locator, locator_to_latlong from pyhamtools.locator import latlong_to_locator, locator_to_latlong
@@ -229,7 +230,7 @@ class Spot:
self.de_flag = get_flag_for_dxcc(self.de_dxcc_id) self.de_flag = get_flag_for_dxcc(self.de_dxcc_id)
# Remove NaNs in frequency # Remove NaNs in frequency
if self.freq and self.freq == float("nan"): if self.freq and isnan(self.freq):
self.freq = None self.freq = None
# Band from frequency # Band from frequency
@@ -364,12 +365,12 @@ class Spot:
ll = locator_to_latlong(self.dx_grid) ll = locator_to_latlong(self.dx_grid)
self.dx_latitude = ll[0] self.dx_latitude = ll[0]
self.dx_longitude = ll[1] self.dx_longitude = ll[1]
except: except Exception:
logger.debug("Invalid grid received for spot") logger.debug("Invalid grid received for spot")
if self.dx_latitude and self.dx_longitude and not self.dx_grid: if self.dx_latitude and self.dx_longitude and not self.dx_grid:
try: try:
self.dx_grid = latlong_to_locator(self.dx_latitude, self.dx_longitude, 8) self.dx_grid = latlong_to_locator(self.dx_latitude, self.dx_longitude, 8)
except: except Exception:
logger.debug("Invalid lat/lon received for spot") logger.debug("Invalid lat/lon received for spot")
# QRT comment detection # QRT comment detection
@@ -438,9 +439,9 @@ class Spot:
self.de_call self.de_call
and any(char.isdigit() for char in str(self.de_call)) and any(char.isdigit() for char in str(self.de_call))
and not (self.de_call.startswith("T2") and self.source == "APRS-IS") and not (self.de_call.startswith("T2") and self.source == "APRS-IS")
and not self.de_latitude
): ):
# DE operator location lookup # DE operator location lookup
if not self.de_latitude:
self.de_latitude = de_call_info.latitude self.de_latitude = de_call_info.latitude
self.de_longitude = de_call_info.longitude self.de_longitude = de_call_info.longitude
self.de_grid = de_call_info.grid self.de_grid = de_call_info.grid
+4 -4
View File
@@ -139,10 +139,10 @@ class HamQTH(APIQueryCallsignDataProvider):
return Callsign( return Callsign(
call=callsign, call=callsign,
home_call=callinfo.Callinfo.get_homecall(callsign), home_call=callinfo.Callinfo.get_homecall(callsign),
name=data["nick"] if "nick" in data else None, name=data.get("nick", None),
qth=data["qth"] if "qth" in data else None, qth=data.get("qth", None),
country=data["country"] if "country" in data else None, country=data.get("country", None),
continent=data["continent"] if "continent" in data else None, continent=data.get("continent", None),
latitude=lat, latitude=lat,
longitude=lon, longitude=lon,
grid=grid, grid=grid,
+3 -3
View File
@@ -161,9 +161,9 @@ class QRZ(APIQueryCallsignDataProvider):
call=callsign, call=callsign,
home_call=callinfo.Callinfo.get_homecall(callsign), home_call=callinfo.Callinfo.get_homecall(callsign),
name=name, name=name,
qth=data["addr2"] if "addr2" in data else None, qth=data.get("addr2", None),
country=data["country"] if "country" in data else None, country=data.get("country", None),
continent=data["continent"] if "continent" in data else None, continent=data.get("continent", None),
latitude=lat, latitude=lat,
longitude=lon, longitude=lon,
grid=grid, grid=grid,
+1 -1
View File
@@ -26,7 +26,7 @@ class ARLHS(FileDownloadSIGRefDataProvider):
SIGRef( SIGRef(
sig=self.SIG, sig=self.SIG,
id=ref_id, id=ref_id,
name=row["Name"] if "Name" in row else None, name=row.get("Name", None),
ref_type="Lighthouse", ref_type="Lighthouse",
url=f"https://www.cqgma.org/zinfo.php?ref={ref_id}", url=f"https://www.cqgma.org/zinfo.php?ref={ref_id}",
latitude=float(row["Latitude"]) if "Latitude" in row and row["Latitude"] != "" else None, latitude=float(row["Latitude"]) if "Latitude" in row and row["Latitude"] != "" else None,
+1 -1
View File
@@ -25,7 +25,7 @@ class GMA(FileDownloadSIGRefDataProvider):
SIGRef( SIGRef(
sig=self.SIG, sig=self.SIG,
id=ref_id, id=ref_id,
name=row["Name"] if "Name" in row else None, name=row.get("Name", None),
ref_type="Summit", ref_type="Summit",
url=f"https://www.cqgma.org/zinfo.php?ref={ref_id}", url=f"https://www.cqgma.org/zinfo.php?ref={ref_id}",
latitude=float(row["Latitude"]) if "Latitude" in row and row["Latitude"] != "" else None, latitude=float(row["Latitude"]) if "Latitude" in row and row["Latitude"] != "" else None,
+1 -1
View File
@@ -26,7 +26,7 @@ class ILLW(FileDownloadSIGRefDataProvider):
SIGRef( SIGRef(
sig=self.SIG, sig=self.SIG,
id=ref_id, id=ref_id,
name=row["Name"] if "Name" in row else None, name=row.get("Name", None),
ref_type="Lighthouse", ref_type="Lighthouse",
url=f"https://www.cqgma.org/zinfo.php?ref={ref_id}", url=f"https://www.cqgma.org/zinfo.php?ref={ref_id}",
latitude=float(row["Latitude"]) if "Latitude" in row and row["Latitude"] != "" else None, latitude=float(row["Latitude"]) if "Latitude" in row and row["Latitude"] != "" else None,
+1 -1
View File
@@ -25,7 +25,7 @@ class MOTA(FileDownloadSIGRefDataProvider):
SIGRef( SIGRef(
sig=self.SIG, sig=self.SIG,
id=ref_id, id=ref_id,
name=row["Name"] if "Name" in row else None, name=row.get("Name", None),
ref_type="Mill", ref_type="Mill",
url=f"https://www.cqgma.org/zinfo.php?ref={ref_id}", url=f"https://www.cqgma.org/zinfo.php?ref={ref_id}",
latitude=float(row["Latitude"]) if "Latitude" in row and row["Latitude"] != "" else None, latitude=float(row["Latitude"]) if "Latitude" in row and row["Latitude"] != "" else None,
+2 -2
View File
@@ -25,10 +25,10 @@ class POTA(FileDownloadSIGRefDataProvider):
SIGRef( SIGRef(
sig=self.SIG, sig=self.SIG,
id=ref_id, id=ref_id,
name=row["name"] if "name" in row else None, name=row.get("name", None),
ref_type="Park", ref_type="Park",
url=f"https://pota.app/#/park/{ref_id}", url=f"https://pota.app/#/park/{ref_id}",
grid=row["grid"] if "grid" in row else None, grid=row.get("grid", None),
latitude=float(row["latitude"]) if "latitude" in row and row["latitude"] != "" else None, latitude=float(row["latitude"]) if "latitude" in row and row["latitude"] != "" else None,
longitude=float(row["longitude"]) if "longitude" in row and row["longitude"] != "" else None, longitude=float(row["longitude"]) if "longitude" in row and row["longitude"] != "" else None,
) )
+2 -2
View File
@@ -25,9 +25,9 @@ class SIOTA(FileDownloadSIGRefDataProvider):
SIGRef( SIGRef(
sig=self.SIG, sig=self.SIG,
id=ref_id, id=ref_id,
name=row["NAME"] if "NAME" in row else None, name=row.get("NAME", None),
ref_type="Silo", ref_type="Silo",
grid=row["LOCATOR"] if "LOCATOR" in row else None, grid=row.get("LOCATOR", None),
latitude=float(row["LAT"]) if "LAT" in row else None, latitude=float(row["LAT"]) if "LAT" in row else None,
longitude=float(row["LNG"]) if "LNG" in row else None, longitude=float(row["LNG"]) if "LNG" in row else None,
) )
+1 -1
View File
@@ -29,7 +29,7 @@ class SOTA(FileDownloadSIGRefDataProvider):
ref = SIGRef( ref = SIGRef(
sig=self.SIG, sig=self.SIG,
id=ref_id, id=ref_id,
name=row["SummitName"] if "SummitName" in row else None, name=row.get("SummitName", None),
ref_type="Summit", ref_type="Summit",
url=f"https://www.sotadata.org.uk/en/summit/{ref_id}", url=f"https://www.sotadata.org.uk/en/summit/{ref_id}",
latitude=latitude, latitude=latitude,
+1 -1
View File
@@ -25,7 +25,7 @@ class Towers(FileDownloadSIGRefDataProvider):
SIGRef( SIGRef(
sig=self.SIG, sig=self.SIG,
id=ref_id, id=ref_id,
name=row["Nazev"] if "Nazev" in row else None, name=row.get("Nazev", None),
ref_type="Tower", ref_type="Tower",
url=f"https://wwtota.com/seznam/karta_rozhledny.php?ref={ref_id}", url=f"https://wwtota.com/seznam/karta_rozhledny.php?ref={ref_id}",
grid=row["Lokator"] if "Lokator" in row and row["Lokator"] != "" else None, grid=row["Lokator"] if "Lokator" in row and row["Lokator"] != "" else None,
+1 -1
View File
@@ -44,7 +44,7 @@ class WCA(FileDownloadSIGRefDataProvider):
SIGRef( SIGRef(
sig=self.SIG, sig=self.SIG,
id=ref_id, id=ref_id,
name=row["CLEAN NAME"] if "CLEAN NAME" in row else None, name=row.get("CLEAN NAME", None),
ref_type="Castle", ref_type="Castle",
url=f"https://www.cqgma.org/zinfo.php?ref={ref_id}", url=f"https://www.cqgma.org/zinfo.php?ref={ref_id}",
latitude=latitude, latitude=latitude,
+1 -1
View File
@@ -25,7 +25,7 @@ class WWBOTA(FileDownloadSIGRefDataProvider):
SIGRef( SIGRef(
sig=self.SIG, sig=self.SIG,
id=ref_id, id=ref_id,
name=row["Name"] if "Name" in row else None, name=row.get("Name", None),
ref_type="Bunker", ref_type="Bunker",
url=f"https://bunkerwiki.org/?s={ref_id}" if ref_id.startswith("B/G") else None, url=f"https://bunkerwiki.org/?s={ref_id}" if ref_id.startswith("B/G") else None,
grid=row["Locator"] if "Locator" in row and row["Locator"] != "" else None, grid=row["Locator"] if "Locator" in row and row["Locator"] != "" else None,
+1 -1
View File
@@ -25,7 +25,7 @@ class WWFF(FileDownloadSIGRefDataProvider):
SIGRef( SIGRef(
sig=self.SIG, sig=self.SIG,
id=ref_id, id=ref_id,
name=row["name"] if "name" in row else None, name=row.get("name", None),
ref_type="Park", ref_type="Park",
url=f"https://wwff.co/directory/?showRef={ref_id}", url=f"https://wwff.co/directory/?showRef={ref_id}",
grid=row["iaruLocator"] if "iaruLocator" in row and row["iaruLocator"] != "-" else None, grid=row["iaruLocator"] if "iaruLocator" in row and row["iaruLocator"] != "-" else None,
+4 -4
View File
@@ -30,15 +30,15 @@ class DXCluster(SpotProvider):
def __init__(self, provider_config): def __init__(self, provider_config):
"""Constructor requires hostname and port""" """Constructor requires hostname and port"""
name = provider_config["name"] if "name" in provider_config else "Cluster" name = provider_config.get("name", "Cluster")
super().__init__(name, provider_config) super().__init__(name, provider_config)
self._hostname = provider_config["host"] self._hostname = provider_config["host"]
self._port = provider_config["port"] self._port = provider_config["port"]
self._login_prompt = provider_config["login_prompt"] if "login_prompt" in provider_config else "login:" self._login_prompt = provider_config.get("login_prompt", "login:")
self._login_callsign = ( self._login_callsign = (
provider_config["login_callsign"] if "login_callsign" in provider_config else SERVER_OWNER_CALLSIGN provider_config.get("login_callsign", SERVER_OWNER_CALLSIGN)
) )
self._allow_rbn_spots = provider_config["allow_rbn_spots"] if "allow_rbn_spots" in provider_config else False self._allow_rbn_spots = provider_config.get("allow_rbn_spots", False)
self._spot_line_pattern = ( self._spot_line_pattern = (
self._LINE_PATTERN_ALLOW_RBN if self._allow_rbn_spots else self._LINE_PATTERN_EXCLUDE_RBN self._LINE_PATTERN_ALLOW_RBN if self._allow_rbn_spots else self._LINE_PATTERN_EXCLUDE_RBN
) )
+1 -1
View File
@@ -148,7 +148,7 @@ class GMA(HTTPSpotProvider):
logger.warning( logger.warning(
f"GMA API returned a malformed response when looking up ref {source_spot['REF']}" f"GMA API returned a malformed response when looking up ref {source_spot['REF']}"
) )
except: except Exception:
logger.exception( logger.exception(
f"Exception when looking up {self.REF_INFO_URL_ROOT}{source_spot['REF']}, ignoring this spot for now" f"Exception when looking up {self.REF_INFO_URL_ROOT}{source_spot['REF']}, ignoring this spot for now"
) )
+1 -1
View File
@@ -26,7 +26,7 @@ class RBN(SpotProvider):
def __init__(self, provider_config): def __init__(self, provider_config):
"""Constructor requires port number.""" """Constructor requires port number."""
name = provider_config["name"] if "name" in provider_config else "RBN" name = provider_config.get("name", "RBN")
super().__init__(name, provider_config) super().__init__(name, provider_config)
self._port = provider_config["port"] self._port = provider_config["port"]
self._telnet = None self._telnet = None
+1 -1
View File
@@ -39,7 +39,7 @@ class SpotProvider:
spot.infer_missing() spot.infer_missing()
self._add_spot(spot) self._add_spot(spot)
if spots: if spots:
self.last_spot_time = datetime.fromtimestamp(max(map(lambda s: s.time, spots)), pytz.UTC) self.last_spot_time = datetime.fromtimestamp(max(s.time for s in spots), pytz.UTC)
def _submit(self, spot): def _submit(self, spot):
"""Submit a single spot retrieved from the provider. This will be added to the list regardless of its age. Spots """Submit a single spot retrieved from the provider. This will be added to the list regardless of its age. Spots
+4 -4
View File
@@ -20,7 +20,7 @@ class UKPacketNet(HTTPSpotProvider):
new_spots = [] new_spots = []
# Iterate through source data # Iterate through source data
nodes = http_response.json()["nodes"] nodes = http_response.json()["nodes"]
for callsign, node in nodes.items(): for node in nodes.values():
# The node corresponse to the spotter here. It has an "mheard" section which indicates which nodes it has # The node corresponse to the spotter here. It has an "mheard" section which indicates which nodes it has
# recently heard, which will be our "DX". But "mheard" stations are not necessarily over RF, they could be # recently heard, which will be our "DX". But "mheard" stations are not necessarily over RF, they could be
# via the internet, so we also need to look up the "port" on which the station was heard, and check that it # via the internet, so we also need to look up the "port" on which the station was heard, and check that it
@@ -34,7 +34,7 @@ class UKPacketNet(HTTPSpotProvider):
# This is another packet station heard over RF, so we are good to create a Spot object. # This is another packet station heard over RF, so we are good to create a Spot object.
# First build a "full" comment combining some of the extra info # First build a "full" comment combining some of the extra info
comment = listed_port["comment"] if "comment" in listed_port else "" comment = listed_port.get("comment", "")
comment = f"{comment} {listed_port['mode']}" if "mode" in listed_port else comment comment = f"{comment} {listed_port['mode']}" if "mode" in listed_port else comment
comment = ( comment = (
f"{comment} {listed_port['modulation']}" if "modulation" in listed_port else comment f"{comment} {listed_port['modulation']}" if "modulation" in listed_port else comment
@@ -82,7 +82,7 @@ class UKPacketNet(HTTPSpotProvider):
time=datetime.strptime(heard["lastHeard"], "%Y-%m-%d %H:%M:%S") time=datetime.strptime(heard["lastHeard"], "%Y-%m-%d %H:%M:%S")
.replace(tzinfo=pytz.UTC) .replace(tzinfo=pytz.UTC)
.timestamp(), .timestamp(),
de_grid=node["location"]["locator"] if "locator" in node["location"] else None, de_grid=node["location"].get("locator", None),
de_latitude=node["location"]["coords"]["lat"], de_latitude=node["location"]["coords"]["lat"],
de_longitude=node["location"]["coords"]["lon"], de_longitude=node["location"]["coords"]["lon"],
) )
@@ -99,7 +99,7 @@ class UKPacketNet(HTTPSpotProvider):
for spot in new_spots: for spot in new_spots:
if spot.dx_call in nodes: if spot.dx_call in nodes:
spot.dx_grid = ( spot.dx_grid = (
nodes[spot.dx_call]["location"]["locator"] if "locator" in nodes[spot.dx_call]["location"] else None nodes[spot.dx_call]["location"].get("locator", None)
) )
spot.dx_latitude = nodes[spot.dx_call]["location"]["coords"]["lat"] spot.dx_latitude = nodes[spot.dx_call]["location"]["coords"]["lat"]
spot.dx_longitude = nodes[spot.dx_call]["location"]["coords"]["lon"] spot.dx_longitude = nodes[spot.dx_call]["location"]["coords"]["lon"]
+2 -2
View File
@@ -64,9 +64,9 @@ class WebsocketSpotProvider(SpotProvider):
except Exception: except Exception:
logger.exception(f"Exception processing message from Websocket Spot Provider ({self.name})") logger.exception(f"Exception processing message from Websocket Spot Provider ({self.name})")
except Exception as e: except Exception:
self.status = "Error" self.status = "Error"
logger.exception(f"Exception in Websocket Spot Provider ({self.name})", e) logger.exception(f"Exception in Websocket Spot Provider ({self.name})")
else: else:
self.status = "Disconnected" self.status = "Disconnected"
sleep(5) # Wait before trying to reconnect sleep(5) # Wait before trying to reconnect
+2 -3
View File
@@ -19,7 +19,6 @@ class WOTA(HTTPSpotProvider):
POLL_INTERVAL_SEC = 120 POLL_INTERVAL_SEC = 120
SPOTS_URL = "https://www.wota.org.uk/spots_rss.php" SPOTS_URL = "https://www.wota.org.uk/spots_rss.php"
LIST_URL = "https://www.wota.org.uk/mapping/data/summits.json"
RSS_DATE_TIME_FORMAT = "%a, %d %b %Y %H:%M:%S %z" RSS_DATE_TIME_FORMAT = "%a, %d %b %Y %H:%M:%S %z"
def __init__(self, provider_config): def __init__(self, provider_config):
@@ -83,8 +82,8 @@ class WOTA(HTTPSpotProvider):
) )
new_spots.append(spot) new_spots.append(spot)
except Exception as e: except Exception:
logger.error("Exception parsing WOTA spot", e) logger.exception("Exception parsing WOTA spot")
return new_spots return new_spots
def can_submit_spot(self, sig): def can_submit_spot(self, sig):
+1 -1
View File
@@ -20,7 +20,7 @@ class XOTA(WebsocketSpotProvider):
SIG = None SIG = None
def __init__(self, provider_config): def __init__(self, provider_config):
name = provider_config["name"] if "name" in provider_config else "xOTA" name = provider_config.get("name", "xOTA")
super().__init__(name, provider_config, provider_config["url"]) super().__init__(name, provider_config, provider_config["url"])
self.SIG = str(provider_config["sig"]) if "sig" in provider_config else None self.SIG = str(provider_config["sig"]) if "sig" in provider_config else None
self._sig_ref_prefix = str(provider_config["sig_ref_prefix"]) if "sig_ref_prefix" in provider_config else "" self._sig_ref_prefix = str(provider_config["sig_ref_prefix"]) if "sig_ref_prefix" in provider_config else ""
+3 -3
View File
@@ -150,7 +150,7 @@ def get_alert_list_with_filters(all_alerts, query):
alerts.append(a) alerts.append(a)
alerts = sorted(alerts, key=lambda alert: alert.start_time if alert and alert.start_time else 0) alerts = sorted(alerts, key=lambda alert: alert.start_time if alert and alert.start_time else 0)
alerts = list(filter(lambda alert: alert_allowed_by_query(alert, query), alerts)) alerts = list(filter(lambda alert: alert_allowed_by_query(alert, query), alerts))
if "limit" in query.keys(): if "limit" in query:
alerts = alerts[: int(query.get("limit"))] alerts = alerts[: int(query.get("limit"))]
return alerts return alerts
@@ -159,7 +159,7 @@ def alert_allowed_by_query(alert, query):
"""Given URL query params and an alert, figure out if the alert "passes" the requested filters or is rejected. The list """Given URL query params and an alert, figure out if the alert "passes" the requested filters or is rejected. The list
of query parameters and their function is defined in the API docs.""" of query parameters and their function is defined in the API docs."""
for k in query.keys(): for k in query:
match k: match k:
case "received_since": case "received_since":
since = datetime.fromtimestamp(float(query.get(k)), pytz.UTC) since = datetime.fromtimestamp(float(query.get(k)), pytz.UTC)
@@ -172,7 +172,7 @@ def alert_allowed_by_query(alert, query):
# the alert is a dxpedition, it also always passes the check. # the alert is a dxpedition, it also always passes the check.
if alert.is_dxpedition and ( if alert.is_dxpedition and (
query.get("dxpeditions_skip_max_duration_check").upper() == "TRUE" query.get("dxpeditions_skip_max_duration_check").upper() == "TRUE"
if "dxpeditions_skip_max_duration_check" in query.keys() if "dxpeditions_skip_max_duration_check" in query
else False else False
): ):
continue continue
+1 -1
View File
@@ -47,7 +47,7 @@ class APIDxStatsHandler(tornado.web.RequestHandler):
one_hour_ago = (datetime.now(pytz.UTC) - timedelta(hours=1)).timestamp() one_hour_ago = (datetime.now(pytz.UTC) - timedelta(hours=1)).timestamp()
counts = Counter() counts = Counter()
for key in self._spots.keys(): for key in self._spots:
spot = self._spots.get(key) spot = self._spots.get(key)
if spot is None: if spot is None:
continue continue
+1 -1
View File
@@ -108,7 +108,7 @@ class APILookupSIGRefHandler(tornado.web.RequestHandler):
if "sig" in query_params and "id" in query_params: if "sig" in query_params and "id" in query_params:
sig = str(query_params.get("sig")).upper() sig = str(query_params.get("sig")).upper()
ref_id = str(query_params.get("id")).upper() ref_id = str(query_params.get("id")).upper()
if sig in list(map(lambda p: p.name.upper(), SIGS)): if sig in [p.name.upper() for p in SIGS]:
if not get_ref_regex_for_sig(sig) or re.match(get_ref_regex_for_sig(sig), ref_id): if not get_ref_regex_for_sig(sig) or re.match(get_ref_regex_for_sig(sig), ref_id):
data = populate_missing_sig_ref_info(SIGRef(id=ref_id, sig=sig)) data = populate_missing_sig_ref_info(SIGRef(id=ref_id, sig=sig))
self.write(safe_json_dumps(data)) self.write(safe_json_dumps(data))
+6 -26
View File
@@ -62,36 +62,16 @@ class APIOptionsHandler(tornado.web.RequestHandler):
# Spot/alert sources are filtered for only ones that are enabled in config, no point letting the user toggle # Spot/alert sources are filtered for only ones that are enabled in config, no point letting the user toggle
# things that aren't even available. # things that aren't even available.
spot_providers: list = list( spot_providers: list = [p["name"] for p in filter(lambda p: p["enabled"], self._status_data["spot_providers"])]
map( alert_providers = [p["name"] for p in filter(lambda p: p["enabled"], self._status_data["alert_providers"])]
lambda p: p["name"], callsign_data_providers = [p["name"] for p in filter(
filter(lambda p: p["enabled"], self._status_data["spot_providers"]),
)
)
alert_providers = list(
map(
lambda p: p["name"],
filter(lambda p: p["enabled"], self._status_data["alert_providers"]),
)
)
callsign_data_providers = list(
map(
lambda p: p["name"],
filter(
lambda p: p["enabled"], lambda p: p["enabled"],
self._status_data["callsign_data_providers"], self._status_data["callsign_data_providers"],
), )]
) spot_providers_enabled_by_default = [p["name"] for p in filter(
)
spot_providers_enabled_by_default = list(
map(
lambda p: p["name"],
filter(
lambda p: p["enabled"] and p["enabled_by_default_in_web_ui"], lambda p: p["enabled"] and p["enabled_by_default_in_web_ui"],
self._status_data["spot_providers"], self._status_data["spot_providers"],
), )]
)
)
# If spotting to this server is enabled, "API" is another valid spot source even though it does not come from # If spotting to this server is enabled, "API" is another valid spot source even though it does not come from
# one of our providers. # one of our providers.
+3 -3
View File
@@ -153,7 +153,7 @@ def get_spot_list_with_filters(all_spots, query):
spots.append(s) spots.append(s)
spots = sorted(spots, key=lambda spot: spot.time if spot and spot.time else 0, reverse=True) spots = sorted(spots, key=lambda spot: spot.time if spot and spot.time else 0, reverse=True)
spots = list(filter(lambda spot: spot_allowed_by_query(spot, query), spots)) spots = list(filter(lambda spot: spot_allowed_by_query(spot, query), spots))
if "limit" in query.keys(): if "limit" in query:
spots = spots[: int(query.get("limit"))] spots = spots[: int(query.get("limit"))]
# Ensure only the latest spot of each callsign-SSID combo is present in the list. This relies on the # Ensure only the latest spot of each callsign-SSID combo is present in the list. This relies on the
@@ -163,7 +163,7 @@ def get_spot_list_with_filters(all_spots, query):
# This is a special consideration for the geo map and band map views (and Field Spotter) because while # This is a special consideration for the geo map and band map views (and Field Spotter) because while
# duplicates are fine in the main spot list (e.g. different cluster spots of the same DX) this doesn't # duplicates are fine in the main spot list (e.g. different cluster spots of the same DX) this doesn't
# work well for the other views. # work well for the other views.
if "dedupe" in query.keys(): if "dedupe" in query:
dedupe = query.get("dedupe").upper() == "TRUE" dedupe = query.get("dedupe").upper() == "TRUE"
if dedupe: if dedupe:
spots_temp = [] spots_temp = []
@@ -182,7 +182,7 @@ def spot_allowed_by_query(spot, query):
"""Given URL query params and a spot, figure out if the spot "passes" the requested filters or is rejected. The list """Given URL query params and a spot, figure out if the spot "passes" the requested filters or is rejected. The list
of query parameters and their function is defined in the API docs.""" of query parameters and their function is defined in the API docs."""
for k in query.keys(): for k in query:
match k: match k:
case "since": case "since":
since = datetime.fromtimestamp(int(query.get(k)), pytz.UTC).timestamp() since = datetime.fromtimestamp(int(query.get(k)), pytz.UTC).timestamp()
-5
View File
@@ -14,15 +14,10 @@ from server.webserver import WEB_SERVER
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Globals
run = True
def shutdown(_signum=None, _frame=None): def shutdown(_signum=None, _frame=None):
"""Shutdown function""" """Shutdown function"""
global run
logger.info("Stopping program...") logger.info("Stopping program...")
WEB_SERVER.stop() WEB_SERVER.stop()
DATA_PROVIDERS.stop() DATA_PROVIDERS.stop()
+1 -1
View File
@@ -76,7 +76,7 @@
</div> </div>
<script src="/static/js/add-spot.js?v=1786779306"></script> <script src="/static/js/add-spot.js?v=1786779799"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-add-spot").addClass("active"); $("#nav-link-add-spot").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+1 -1
View File
@@ -82,7 +82,7 @@
</div> </div>
<script src="/static/js/alerts.js?v=1786779307"></script> <script src="/static/js/alerts.js?v=1786779799"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-alerts").addClass("active"); $("#nav-link-alerts").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -79,8 +79,8 @@
</div> </div>
<script src="/static/js/spotsbandsandmap.js?v=1786779307"></script> <script src="/static/js/spotsbandsandmap.js?v=1786779799"></script>
<script src="/static/js/bands.js?v=1786779307"></script> <script src="/static/js/bands.js?v=1786779799"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-bands").addClass("active"); $("#nav-link-bands").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+5 -5
View File
@@ -1,6 +1,6 @@
{% extends "skeleton.html" %} {% extends "skeleton.html" %}
{% block head_extra %} {% block head_extra %}
<link rel="stylesheet" href="/static/css/style.css?v=1786779306" type="text/css"> <link rel="stylesheet" href="/static/css/style.css?v=1786779799" type="text/css">
<link href="/static/vendor/css/bootstrap-5.3.8.min.css" rel="stylesheet"> <link href="/static/vendor/css/bootstrap-5.3.8.min.css" rel="stylesheet">
<link href="/static/vendor/css/fontawesome-6.7.2.min.css" rel="stylesheet"> <link href="/static/vendor/css/fontawesome-6.7.2.min.css" rel="stylesheet">
<link href="/static/vendor/css/solid-6.7.2.min.css" rel="stylesheet"> <link href="/static/vendor/css/solid-6.7.2.min.css" rel="stylesheet">
@@ -15,10 +15,10 @@
window.fetchEventSource = fetchEventSource; window.fetchEventSource = fetchEventSource;
</script> </script>
<script src="/static/js/utils.js?v=1786779306"></script> <script src="/static/js/utils.js?v=1786779799"></script>
<script src="/static/js/ui-ham.js?v=1786779306"></script> <script src="/static/js/ui-ham.js?v=1786779799"></script>
<script src="/static/js/geo.js?v=1786779306"></script> <script src="/static/js/geo.js?v=1786779799"></script>
<script src="/static/js/common.js?v=1786779306"></script> <script src="/static/js/common.js?v=1786779799"></script>
{% end %} {% end %}
{% block body %} {% block body %}
<div class="container"> <div class="container">
+1 -1
View File
@@ -284,7 +284,7 @@
</div> </div>
<script src="/static/vendor/js/chart-4.4.9.umd.min.js"></script> <script src="/static/vendor/js/chart-4.4.9.umd.min.js"></script>
<script src="/static/js/conditions.js?v=1786779307"></script> <script src="/static/js/conditions.js?v=1786779799"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-conditions").addClass("active"); $("#nav-link-conditions").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -112,8 +112,8 @@
<script src="/static/vendor/js/leaflet-cqzones.js"></script> <script src="/static/vendor/js/leaflet-cqzones.js"></script>
<script src="/static/vendor/js/leaflet-workedallbritainireland.js" type="module"></script> <script src="/static/vendor/js/leaflet-workedallbritainireland.js" type="module"></script>
<script src="/static/js/spotsbandsandmap.js?v=1786779307"></script> <script src="/static/js/spotsbandsandmap.js?v=1786779799"></script>
<script src="/static/js/map.js?v=1786779307"></script> <script src="/static/js/map.js?v=1786779799"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-map").addClass("active"); $("#nav-link-map").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -118,8 +118,8 @@
</div> </div>
<script src="/static/js/spotsbandsandmap.js?v=1786779306"></script> <script src="/static/js/spotsbandsandmap.js?v=1786779799"></script>
<script src="/static/js/spots.js?v=1786779306"></script> <script src="/static/js/spots.js?v=1786779799"></script>
<script>$(document).ready(function () { <script>$(document).ready(function () {
$("#nav-link-spots").addClass("active"); $("#nav-link-spots").addClass("active");
}); <!-- highlight active page in nav --></script> }); <!-- highlight active page in nav --></script>
+1 -1
View File
@@ -86,7 +86,7 @@
</div> </div>
</div> </div>
<script src="/static/js/status.js?v=1786779307"></script> <script src="/static/js/status.js?v=1786779799"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$("#nav-link-status").addClass("active"); $("#nav-link-status").addClass("active");