Use ruff linter to fix issues and provide consistent formatting

This commit is contained in:
Ian Renton
2026-08-15 08:25:54 +01:00
parent 7391c28cd0
commit af3f82c14d
121 changed files with 1989 additions and 996 deletions
@@ -5,7 +5,7 @@ class APIQueryCallsignDataProvider(CallsignDataProvider):
"""Generic callsign data provider class for providers that fetch their data from the web on-demand using an API."""
def __init__(self, name, provider_config, storage):
""" Set up the provider."""
"""Set up the provider."""
super().__init__(name, provider_config, storage)
if self.enabled:
@@ -51,7 +51,6 @@ class CallsignDataProvider:
else:
return None
def _perform_new_lookup(self, callsign, lookup_credentials):
"""Makes a new request to the data source for callsign data."""
+6 -4
View File
@@ -2,12 +2,14 @@ import logging
from datetime import datetime
import pytz
from pyhamtools import LookupLib, Callinfo
from pyhamtools import Callinfo, LookupLib
from core.data_store import DATA_STORE
from core.utils import get_callsign_object_from_pyhamtools_callinfo
from data.callsign import Callsign
from providers.callsigndata.api_query_callsign_data_provider import APIQueryCallsignDataProvider
from providers.callsigndata.api_query_callsign_data_provider import (
APIQueryCallsignDataProvider,
)
class ClublogAPI(APIQueryCallsignDataProvider):
@@ -24,11 +26,11 @@ class ClublogAPI(APIQueryCallsignDataProvider):
else:
provider_config["enabled"] = False
logging.warning(
"Clublog XML callsign data provider configured but no api key was provided, this has been disabled.")
"Clublog XML callsign data provider configured but no api key was provided, this has been disabled."
)
super().__init__("Clublog API", provider_config, DATA_STORE.callsign_data_clublogapi)
def _perform_new_lookup(self, callsign, lookup_credentials):
callsign_data = Callsign(call=callsign)
+14 -5
View File
@@ -1,12 +1,14 @@
import gzip
import logging
from pyhamtools import LookupLib, Callinfo
from pyhamtools import Callinfo, LookupLib
from core.data_store import DATA_STORE
from core.utils import get_callsign_object_from_pyhamtools_callinfo
from data.callsign import Callsign
from providers.callsigndata.file_download_callsign_data_provider import FileDownloadCallsignDataProvider
from providers.callsigndata.file_download_callsign_data_provider import (
FileDownloadCallsignDataProvider,
)
class ClublogXML(FileDownloadCallsignDataProvider):
@@ -24,10 +26,17 @@ class ClublogXML(FileDownloadCallsignDataProvider):
if self._api_key == "":
provider_config["enabled"] = False
logging.warning(
"Clublog XML callsign data provider configured but no api key was provided, this has been disabled.")
"Clublog XML callsign data provider configured but no api key was provided, this has been disabled."
)
super().__init__("Clublog XML", provider_config, f"{self.DATA_URL}?api={self._api_key}",
self.CACHE_PATH_ZIPPED, self.POLL_INTERVAL_DAYS, DATA_STORE.callsign_data_clublogxml)
super().__init__(
"Clublog XML",
provider_config,
f"{self.DATA_URL}?api={self._api_key}",
self.CACHE_PATH_ZIPPED,
self.POLL_INTERVAL_DAYS,
DATA_STORE.callsign_data_clublogxml,
)
def _handle_file(self, path):
try:
+12 -4
View File
@@ -1,11 +1,13 @@
import logging
from pyhamtools import LookupLib, Callinfo
from pyhamtools import Callinfo, LookupLib
from core.data_store import DATA_STORE
from core.utils import get_callsign_object_from_pyhamtools_callinfo
from data.callsign import Callsign
from providers.callsigndata.file_download_callsign_data_provider import FileDownloadCallsignDataProvider
from providers.callsigndata.file_download_callsign_data_provider import (
FileDownloadCallsignDataProvider,
)
class CountryFiles(FileDownloadCallsignDataProvider):
@@ -17,8 +19,14 @@ class CountryFiles(FileDownloadCallsignDataProvider):
_callinfo = None
def __init__(self, provider_config):
super().__init__("CountryFiles.com", provider_config, self.DATA_URL, self.CACHE_PATH, self.POLL_INTERVAL_DAYS,
DATA_STORE.callsign_data_countryfiles)
super().__init__(
"CountryFiles.com",
provider_config,
self.DATA_URL,
self.CACHE_PATH,
self.POLL_INTERVAL_DAYS,
DATA_STORE.callsign_data_countryfiles,
)
def _handle_file(self, path):
try:
@@ -1,6 +1,6 @@
import logging
from datetime import datetime
from threading import Thread, Event
from threading import Event, Thread
import pytz
from requests import ReadTimeout
@@ -15,7 +15,7 @@ class FileDownloadCallsignDataProvider(CallsignDataProvider):
"""Generic callsign data provider class for providers that fetch their data from the web by downloading a file."""
def __init__(self, name, provider_config, url, cache_file_path, poll_interval, storage):
""" Set up the provider, note poll_interval is in *days*."""
"""Set up the provider, note poll_interval is in *days*."""
super().__init__(name, provider_config, storage)
self._url = url
self._cache_file_path = cache_file_path
@@ -30,8 +30,7 @@ class FileDownloadCallsignDataProvider(CallsignDataProvider):
def start(self):
# Fire off the polling thread. It will poll immediately on startup, then sleep for poll_interval between
# subsequent polls, so start() returns immediately and the application can continue starting.
logging.info(
f"Set up query of {self.name} callsign reference data every {self._poll_interval!s} days.")
logging.info(f"Set up query of {self.name} callsign reference data every {self._poll_interval!s} days.")
self._thread = Thread(target=self._run, name=f"FileDownloadCallsignDataProvider-{self.name}")
self._thread.start()
@@ -68,7 +67,9 @@ class FileDownloadCallsignDataProvider(CallsignDataProvider):
else:
self.status = "Error"
logging.warning(f"HTTP {http_response.status_code} when downloading callsign reference data from {self.name}.")
logging.warning(
f"HTTP {http_response.status_code} when downloading callsign reference data from {self.name}."
)
except ConnectionError:
self.status = "Error"
+42 -31
View File
@@ -1,6 +1,6 @@
import logging
import urllib.parse
from datetime import timedelta, datetime
from datetime import datetime, timedelta
import pytz
import xmltodict
@@ -10,10 +10,12 @@ from requests_cache import CachedSession
from core.config import SERVER_OWNER_CALLSIGN
from core.constants import HTTP_HEADERS, SOFTWARE_VERSION
from core.data_store import DATA_STORE, CACHE_DIR
from core.data_store import CACHE_DIR, DATA_STORE
from core.url_data_cache import URLDataCache
from data.callsign import Callsign
from providers.callsigndata.api_query_callsign_data_provider import APIQueryCallsignDataProvider
from providers.callsigndata.api_query_callsign_data_provider import (
APIQueryCallsignDataProvider,
)
class HamQTH(APIQueryCallsignDataProvider):
@@ -26,14 +28,15 @@ class HamQTH(APIQueryCallsignDataProvider):
self._URL_DATA_CACHE = URLDataCache("hamqth")
# Separate URL cache for session key lookups. Once a session key is returned from logging in with a username
# and password, this is valid for an hour, so our cache stores this specifically for 55 minutes.
self._CREDENTIALS_CACHE = CachedSession(f"{CACHE_DIR}/urls/hamqth-creds",
expire_after=timedelta(minutes=55))
self._CREDENTIALS_CACHE = CachedSession(f"{CACHE_DIR}/urls/hamqth-creds", expire_after=timedelta(minutes=55))
def _perform_new_lookup(self, callsign, lookup_credentials):
# If we don't have HamQTH credentials, skip this lookup Return None so we don't *cache* the lack of data, because
# # someone might provide credentials next time around.
if not lookup_credentials or not ((lookup_credentials.hamqth_username and lookup_credentials.hamqth_password)
or lookup_credentials.hamqth_session_id):
if not lookup_credentials or not (
(lookup_credentials.hamqth_username and lookup_credentials.hamqth_password)
or lookup_credentials.hamqth_session_id
):
return None
try:
@@ -45,7 +48,8 @@ class HamQTH(APIQueryCallsignDataProvider):
try:
session_data = self._CREDENTIALS_CACHE.get(
f"{self._HAMQTH_BASE_URL}?u={urllib.parse.quote_plus(lookup_credentials.hamqth_username)}&p={urllib.parse.quote_plus(lookup_credentials.hamqth_password)}",
headers=HTTP_HEADERS).content
headers=HTTP_HEADERS,
).content
dict_data = xmltodict.parse(session_data)
if "session_id" in dict_data["HamQTH"]["session"]:
session_id = str(dict_data["HamQTH"]["session"]["session_id"])
@@ -67,13 +71,16 @@ class HamQTH(APIQueryCallsignDataProvider):
if home_call != callsign:
calls_to_try.append(home_call)
except ValueError:
logging.debug("Could not look up home call for callsign %s", callsign)
logging.debug(f"Could not look up home call for callsign {callsign}")
# Try looking up each call using the API
for lookup_call in calls_to_try:
try:
response = self._URL_DATA_CACHE.get(
f"{self._HAMQTH_BASE_URL}?id={session_id}&callsign={urllib.parse.quote_plus(lookup_call)}&prg={self._PRG}", headers=HTTP_HEADERS, timeout=10)
f"{self._HAMQTH_BASE_URL}?id={session_id}&callsign={urllib.parse.quote_plus(lookup_call)}&prg={self._PRG}",
headers=HTTP_HEADERS,
timeout=10,
)
if response.ok:
# Found data, convert it to our object and return it
data = xmltodict.parse(response.content)["HamQTH"]["search"]
@@ -83,19 +90,18 @@ class HamQTH(APIQueryCallsignDataProvider):
return self.hamqth_response_to_callsign(callsign, data)
elif not response.from_cache:
logging.warning("HTTP %d looking up callsign %s using HamQTH", response.status_code,
lookup_call)
logging.warning(f"HTTP {response.status_code} looking up callsign {lookup_call} using HamQTH")
except (KeyError, ValueError):
continue
except ConnectionError:
logging.warning(f"Connection error when looking up callsign %s using HamQTH", lookup_call)
logging.warning(f"Connection error when looking up callsign {lookup_call} using HamQTH")
continue
except (ConnectTimeout, ReadTimeout):
logging.warning(f"Timeout when looking up callsign %s using HamQTH", lookup_call)
logging.warning(f"Timeout when looking up callsign {lookup_call} using HamQTH")
continue
except Exception:
logging.exception("Exception when looking up callsign %s using HamQTH", lookup_call)
logging.exception(f"Exception when looking up callsign {lookup_call} using HamQTH")
continue
# Not found in HamQTH; return a Callsign object with no data so we cache that and don't keep retrying
@@ -114,9 +120,12 @@ class HamQTH(APIQueryCallsignDataProvider):
# Check for sensible latitudes
lat = None
lon = None
if "latitude" in data and "longitude" in data and (
float(data["latitude"]) != 0 or float(data["longitude"]) != 0) and -89.9 < float(
data["latitude"]) < 89.9:
if (
"latitude" in data
and "longitude" in data
and (float(data["latitude"]) != 0 or float(data["longitude"]) != 0)
and -89.9 < float(data["latitude"]) < 89.9
):
lat = float(data["latitude"])
lon = float(data["longitude"])
@@ -125,16 +134,18 @@ class HamQTH(APIQueryCallsignDataProvider):
if "grid" in data and not data["grid"].startswith("AA00"):
grid = data["grid"]
return Callsign(call=callsign,
home_call=callinfo.Callinfo.get_homecall(callsign),
name=data["nick"] if "nick" in data else None,
qth=data["qth"] if "qth" in data else None,
country=data["country"] if "country" in data else None,
continent=data["continent"] if "continent" in data else None,
latitude=lat,
longitude=lon,
grid=grid,
dxcc_id=int(data["adif"]) if "adif" in data else None,
cq_zone=int(data["cq"]) if "cq" in data else None,
itu_zone=int(data["itu"]) if "itu" in data else None,
location_source="HOME QTH")
return Callsign(
call=callsign,
home_call=callinfo.Callinfo.get_homecall(callsign),
name=data["nick"] if "nick" in data else None,
qth=data["qth"] if "qth" in data else None,
country=data["country"] if "country" in data else None,
continent=data["continent"] if "continent" in data else None,
latitude=lat,
longitude=lon,
grid=grid,
dxcc_id=int(data["adif"]) if "adif" in data else None,
cq_zone=int(data["cq"]) if "cq" in data else None,
itu_zone=int(data["itu"]) if "itu" in data else None,
location_source="HOME QTH",
)
+45 -34
View File
@@ -1,6 +1,6 @@
import logging
import urllib.parse
from datetime import timedelta, datetime
from datetime import datetime, timedelta
import pytz
import xmltodict
@@ -9,10 +9,12 @@ from requests import ConnectTimeout, ReadTimeout
from requests_cache import CachedSession
from core.constants import HTTP_HEADERS
from core.data_store import DATA_STORE, CACHE_DIR
from core.data_store import CACHE_DIR, DATA_STORE
from core.url_data_cache import URLDataCache
from data.callsign import Callsign
from providers.callsigndata.api_query_callsign_data_provider import APIQueryCallsignDataProvider
from providers.callsigndata.api_query_callsign_data_provider import (
APIQueryCallsignDataProvider,
)
class QRZ(APIQueryCallsignDataProvider):
@@ -24,14 +26,14 @@ class QRZ(APIQueryCallsignDataProvider):
self._URL_DATA_CACHE = URLDataCache("qrz")
# Separate URL cache for session key lookups. Once a session key is returned from logging in with a username
# and password, this is valid for an hour, so our cache stores this specifically for 55 minutes.
self._CREDENTIALS_CACHE = CachedSession(f"{CACHE_DIR}/urls/qrz-creds",
expire_after=timedelta(minutes=55))
self._CREDENTIALS_CACHE = CachedSession(f"{CACHE_DIR}/urls/qrz-creds", expire_after=timedelta(minutes=55))
def _perform_new_lookup(self, callsign, lookup_credentials):
# If we don't have QRZ credentials, skip this lookup. Return None so we don't *cache* the lack of data, because
# someone might provide credentials next time around.
if not lookup_credentials or not ((lookup_credentials.qrz_username and lookup_credentials.qrz_password)
or lookup_credentials.qrz_session_key):
if not lookup_credentials or not (
(lookup_credentials.qrz_username and lookup_credentials.qrz_password) or lookup_credentials.qrz_session_key
):
return None
try:
@@ -43,7 +45,8 @@ class QRZ(APIQueryCallsignDataProvider):
try:
login_response = self._CREDENTIALS_CACHE.get(
f"{self._QRZ_BASE_URL}?username={urllib.parse.quote_plus(lookup_credentials.qrz_username)}&password={urllib.parse.quote_plus(lookup_credentials.qrz_password)}&agent=spothole",
headers=HTTP_HEADERS).content
headers=HTTP_HEADERS,
).content
login_data = xmltodict.parse(login_response)
session = login_data.get("QRZDatabase", {}).get("Session", {})
if "Key" in session:
@@ -66,14 +69,16 @@ class QRZ(APIQueryCallsignDataProvider):
if home_call != callsign:
calls_to_try.append(home_call)
except ValueError:
logging.debug("Could not look up home call for callsign %s", callsign)
logging.debug(f"Could not look up home call for callsign {callsign}")
# Try looking up each call using the API
for lookup_call in calls_to_try:
try:
response = self._URL_DATA_CACHE.get(
f"{self._QRZ_BASE_URL}?s={session_key}&callsign={urllib.parse.quote_plus(lookup_call)}",
headers=HTTP_HEADERS, timeout=10)
headers=HTTP_HEADERS,
timeout=10,
)
if response.ok:
qrz_response = xmltodict.parse(response.content).get("QRZDatabase", {})
if qrz_response:
@@ -88,24 +93,25 @@ class QRZ(APIQueryCallsignDataProvider):
elif "Session" in qrz_response and "Error" in qrz_response.get("Session"):
# Errors here are normally just "callsign not in database", no need to log that ourselves
# above debug level.
logging.debug("QRZ returned an error looking up callsign %s: %s", lookup_call,
qrz_response.get("Session").get("Error"))
logging.debug(
f"QRZ returned an error looking up callsign {lookup_call}: {qrz_response.get('Session').get('Error')}"
)
elif not response.from_cache:
logging.warning("QRZ returned a malformed response looking up callsign %s", lookup_call)
logging.warning(f"QRZ returned a malformed response looking up callsign {lookup_call}")
elif not response.from_cache:
logging.warning("HTTP %d looking up callsign %s using QRZ", lookup_call)
logging.warning(f"HTTP {response.status_code} looking up callsign {lookup_call} using QRZ")
except (KeyError, ValueError):
continue
except ConnectionError:
logging.warning(f"Connection error when looking up callsign %s using QRZ", lookup_call)
logging.warning(f"Connection error when looking up callsign {lookup_call} using QRZ")
continue
except (ConnectTimeout, ReadTimeout):
logging.warning(f"Timeout when looking up callsign %s using QRZ.", lookup_call)
logging.warning(f"Timeout when looking up callsign {lookup_call} using QRZ.")
continue
except Exception:
logging.exception("Exception when looking up callsign %s using QRZ", lookup_call)
logging.exception(f"Exception when looking up callsign {lookup_call} using QRZ")
continue
# Not found in QRZ; return a Callsign object with no data so we cache that and don't keep retrying
@@ -128,16 +134,19 @@ class QRZ(APIQueryCallsignDataProvider):
if "fname" in data:
name = data["fname"]
if "nick" in data:
name = f"{name} \"{data['nick']}\""
name = f'{name} "{data["nick"]}"'
if "name" in data:
name = f"{name} {data['name']}"
# Check for sensible latitudes
lat = None
lon = None
if "latitude" in data and "longitude" in data and (
float(data["latitude"]) != 0 or float(data["longitude"]) != 0) and -89.9 < float(
data["latitude"]) < 89.9:
if (
"latitude" in data
and "longitude" in data
and (float(data["latitude"]) != 0 or float(data["longitude"]) != 0)
and -89.9 < float(data["latitude"]) < 89.9
):
lat = float(data["latitude"])
lon = float(data["longitude"])
@@ -146,16 +155,18 @@ class QRZ(APIQueryCallsignDataProvider):
if "grid" in data and not data["grid"].startswith("AA00"):
grid = data["grid"]
return Callsign(call=callsign,
home_call=callinfo.Callinfo.get_homecall(callsign),
name=name,
qth=data["addr2"] if "addr2" in data else None,
country=data["country"] if "country" in data else None,
continent=data["continent"] if "continent" in data else None,
latitude=lat,
longitude=lon,
grid=grid,
dxcc_id=int(data["adif"]) if "adif" in data else None,
cq_zone=int(data["cqzone"]) if "cqzone" in data else None,
itu_zone=int(data["ituzone"]) if "ituzone" in data else None,
location_source="HOME QTH")
return Callsign(
call=callsign,
home_call=callinfo.Callinfo.get_homecall(callsign),
name=name,
qth=data["addr2"] if "addr2" in data else None,
country=data["country"] if "country" in data else None,
continent=data["continent"] if "continent" in data else None,
latitude=lat,
longitude=lon,
grid=grid,
dxcc_id=int(data["adif"]) if "adif" in data else None,
cq_zone=int(data["cqzone"]) if "cqzone" in data else None,
itu_zone=int(data["ituzone"]) if "ituzone" in data else None,
location_source="HOME QTH",
)