mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2026-09-20 22:37:44 +00:00
Autogenerated type safety parameterisation of all methods
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from core.enums import ActivityName, ActivityRefType, ActivityType
|
||||
from data.activity import Activity
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from core.enums import ActivityName, ActivityRefType, ActivityType
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from core.enums import ActivityRefType
|
||||
|
||||
+10
-6
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
@@ -11,6 +13,8 @@ from core.activity_utils import get_icon_for_activity
|
||||
from core.call_lookup_helper import get_call_info
|
||||
from core.enums import Continent
|
||||
from core.utils import get_flag_for_dxcc
|
||||
from data.activity_ref import ActivityRef
|
||||
from data.lookup_credentials import LookupCredentials
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -25,9 +29,9 @@ class Alert:
|
||||
# DX (alerting) operator info
|
||||
|
||||
# Callsigns of the operators that has been alerted
|
||||
dx_calls: list | None = None
|
||||
dx_calls: list[str] | None = None
|
||||
# Names of the operators that has been alerted
|
||||
dx_names: list | None = None
|
||||
dx_names: list[str | None] | None = None
|
||||
# Country of the DX operator
|
||||
dx_country: str | None = None
|
||||
# Country flag of the DX operator
|
||||
@@ -64,7 +68,7 @@ class Alert:
|
||||
sig: str | None = None
|
||||
# Activity references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO. Still named
|
||||
# "sig_refs" for API backwards compatibility.
|
||||
sig_refs: list = field(default_factory=list)
|
||||
sig_refs: list[ActivityRef] = field(default_factory=list)
|
||||
|
||||
# Timing info
|
||||
|
||||
@@ -87,7 +91,7 @@ class Alert:
|
||||
# Icon to use when displaying this alert in the web UI. Chosen from the Font Awesome set.
|
||||
icon: str | None = None
|
||||
|
||||
def infer_missing(self, credentials=None):
|
||||
def infer_missing(self, credentials: LookupCredentials | None = None) -> None:
|
||||
"""Infer missing parameters where possible"""
|
||||
|
||||
try:
|
||||
@@ -160,12 +164,12 @@ class Alert:
|
||||
except Exception:
|
||||
logger.exception("Exception while inferring missing data from spot")
|
||||
|
||||
def to_json(self):
|
||||
def to_json(self) -> str:
|
||||
"""JSON serialise"""
|
||||
|
||||
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True)
|
||||
|
||||
def expired(self):
|
||||
def expired(self) -> bool:
|
||||
"""Decide if this alert has expired (in which case it should not be added to the system in the first place, and not
|
||||
returned by the web server if later requested, and removed by the cleanup functions). "Expired" is defined as
|
||||
either having an end_time in the past, or if it only has a start_time, then that start time was more than 3 hours
|
||||
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from core.enums import Continent, LocationSourceForCallsign
|
||||
@@ -40,7 +42,7 @@ class Callsign:
|
||||
# Location source
|
||||
location_source: LocationSourceForCallsign | None = None
|
||||
|
||||
def fully_populated(self):
|
||||
def fully_populated(self) -> bool:
|
||||
"""Utility method to indicate that the callsign data is fully populated. Multiple providers can return data for
|
||||
a callsign, and we try them in sequence until we have all the data we can, in which case there's no point
|
||||
querying any other providers."""
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from tornado.httputil import HTTPHeaders
|
||||
|
||||
|
||||
@dataclass
|
||||
class LookupCredentials:
|
||||
@@ -13,7 +17,7 @@ class LookupCredentials:
|
||||
hamqth_session_id: str = "" # alternative to username/password
|
||||
|
||||
|
||||
def extract_credentials(headers):
|
||||
def extract_credentials(headers: HTTPHeaders) -> LookupCredentials | None:
|
||||
"""Build a LookupCredentials from HTTP request headers; returns None if no usable credentials are present."""
|
||||
creds = LookupCredentials(
|
||||
qrz_username=headers.get("X-QRZ-Username", ""),
|
||||
|
||||
+16
-11
@@ -1,5 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
# Lookup tables for derived text descriptions.
|
||||
# Each threshold-based table is a list of (min_value, description) pairs in descending order;
|
||||
@@ -71,7 +76,7 @@ ELECTRON_FLUX_DESCRIPTIONS = [
|
||||
]
|
||||
|
||||
|
||||
def _xray_blackout_scale(xray):
|
||||
def _xray_blackout_scale(xray: str | None) -> int:
|
||||
"""Return the NOAA Radio Blackout scale number (R0-R5) for the given X-ray flux class string
|
||||
(e.g. "M4.5", "X12")."""
|
||||
|
||||
@@ -93,7 +98,7 @@ def _xray_blackout_scale(xray):
|
||||
return 0
|
||||
|
||||
|
||||
def _lookup_by_threshold(value, table, default=None):
|
||||
def _lookup_by_threshold(value: int | None, table: list[tuple[int, T]], default: T | None = None) -> T | None:
|
||||
"""Return the description from a threshold table for the given numeric value.
|
||||
The table is a list of (min_value, description) pairs in descending order."""
|
||||
|
||||
@@ -150,20 +155,20 @@ class SolarConditions:
|
||||
# Geomagnetic background noise level, e.g. "S0", "S1", "S2"
|
||||
geomag_noise: str | None = None
|
||||
# HF band propagation conditions, keyed by "{band}-{time}" e.g. "80m-40m-day"
|
||||
hf_conditions: dict | None = None
|
||||
hf_conditions: dict[str, str] | None = None
|
||||
# VHF propagation conditions, keyed by condition name
|
||||
vhf_conditions: dict | None = None
|
||||
vhf_conditions: dict[str, str | None] | None = None
|
||||
# NOAA Kp index 3-day forecast, keyed by UNIX timestamp of the start of each 3-hour UTC period
|
||||
k_index_forecast: dict | None = None
|
||||
k_index_forecast: dict[float, float] | None = None
|
||||
# NOAA Solar Radiation Storm (S1 or greater) probability forecast, keyed by UNIX timestamp of start of day UTC
|
||||
solar_storm_forecast: dict | None = None
|
||||
solar_storm_forecast: dict[float, int] | None = None
|
||||
# NOAA Radio Blackout (R1-R2) probability forecast, keyed by UNIX timestamp of start of day UTC
|
||||
blackout_forecast_r1r2: dict | None = None
|
||||
blackout_forecast_r1r2: dict[float, int] | None = None
|
||||
# NOAA Radio Blackout (R3 or greater) probability forecast, keyed by UNIX timestamp of start of day UTC
|
||||
blackout_forecast_r3_or_greater: dict | None = None
|
||||
blackout_forecast_r3_or_greater: dict[float, int] | None = None
|
||||
# Ionosonde measurements, dict keyed by URSI code, values are dicts with keys: ursi, name, fof2, muf, luf,
|
||||
# band_states. Populated by GIROIonosonde or KC2GProp providers.
|
||||
ionosonde_data: dict | None = None
|
||||
ionosonde_data: dict[str, Any] | None = None
|
||||
|
||||
# Derived values (populated by infer_descriptions())
|
||||
# HF radio blackout risk description, derived from xray
|
||||
@@ -183,7 +188,7 @@ class SolarConditions:
|
||||
# Electron flux description, derived from electron_flux
|
||||
electron_flux_desc: str | None = None
|
||||
|
||||
def infer_descriptions(self):
|
||||
def infer_descriptions(self) -> None:
|
||||
"""Populate derived text description fields from the current numeric/raw field values."""
|
||||
|
||||
if self.xray and len(self.xray) > 0:
|
||||
@@ -196,7 +201,7 @@ class SolarConditions:
|
||||
self.band_conditions_desc = _lookup_by_threshold(self.sfi, BAND_CONDITIONS_DESCRIPTIONS)
|
||||
self.electron_flux_desc = _lookup_by_threshold(self.electron_flux, ELECTRON_FLUX_DESCRIPTIONS)
|
||||
|
||||
def to_json(self):
|
||||
def to_json(self) -> str:
|
||||
"""JSON serialise. Dict key order is insertion order (Python 3.7+ guarantee), so callers receive
|
||||
fields in a predictable, logical sequence without relying on sort_keys."""
|
||||
|
||||
|
||||
+9
-6
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
@@ -32,6 +34,7 @@ from core.utils import (
|
||||
)
|
||||
from data.activities import ACTIVITIES
|
||||
from data.activity_ref import ActivityRef
|
||||
from data.lookup_credentials import LookupCredentials
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -129,7 +132,7 @@ class Spot:
|
||||
sig: str | None = None
|
||||
# Activity references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO. Still named
|
||||
# "sig_refs" for API backwards compatibility.
|
||||
sig_refs: list = field(default_factory=list)
|
||||
sig_refs: list[ActivityRef] = field(default_factory=list)
|
||||
|
||||
# Timing info
|
||||
|
||||
@@ -156,7 +159,7 @@ class Spot:
|
||||
# Icon to use when displaying this spot in the web UI. Chosen from the Font Awesome set.
|
||||
icon: str | None = None
|
||||
|
||||
def __post_init__(self):
|
||||
def __post_init__(self) -> None:
|
||||
"""Normalise fields that don't survive a plain dict to Spot conversion. This is used in the "add spot" API
|
||||
endpoint where the client is submitting JSON, and we want to recreate a full Spot object, including nested
|
||||
objects such as the sig_refs list.."""
|
||||
@@ -167,7 +170,7 @@ class Spot:
|
||||
for activity_ref in self.sig_refs
|
||||
]
|
||||
|
||||
def infer_missing(self, credentials=None):
|
||||
def infer_missing(self, credentials: LookupCredentials | None = None) -> None:
|
||||
"""Infer missing parameters where possible"""
|
||||
|
||||
try:
|
||||
@@ -538,12 +541,12 @@ class Spot:
|
||||
except Exception:
|
||||
logger.exception("Exception while inferring missing data from spot")
|
||||
|
||||
def to_json(self):
|
||||
def to_json(self) -> str:
|
||||
"""JSON serialise"""
|
||||
|
||||
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True)
|
||||
|
||||
def _append_activity_ref_if_missing(self, new_activity_ref):
|
||||
def _append_activity_ref_if_missing(self, new_activity_ref: ActivityRef) -> None:
|
||||
"""Append an activity ref to the list, so long as it's not already there."""
|
||||
|
||||
new_activity_ref.id = new_activity_ref.id.strip().upper()
|
||||
@@ -555,7 +558,7 @@ class Spot:
|
||||
return
|
||||
self.sig_refs.append(new_activity_ref)
|
||||
|
||||
def expired(self):
|
||||
def expired(self) -> bool:
|
||||
"""Decide if this spot has expired (in which case it should not be added to the system in the first place, and not
|
||||
returned by the web server if later requested, and removed by the cleanup functions). "Expired" is defined as
|
||||
either having a time further ago than the server's MAX_SPOT_AGE. If it somehow doesn't have a time either, it is
|
||||
|
||||
Reference in New Issue
Block a user