Bulk convert comments above classes/functions/methods into proper docstrings

This commit is contained in:
Ian Renton
2026-02-27 14:21:35 +00:00
parent 068c732796
commit 6b18ec6f88
63 changed files with 540 additions and 349 deletions

View File

@@ -16,8 +16,9 @@ from data.sig_ref import SIGRef
from data.spot import Spot
# API request handler for /api/v1/spot (POST)
class APISpotHandler(tornado.web.RequestHandler):
"""API request handler for /api/v1/spot (POST)"""
def initialize(self, spots, web_server_metrics):
self.spots = spots
self.web_server_metrics = web_server_metrics
@@ -34,15 +35,17 @@ class APISpotHandler(tornado.web.RequestHandler):
if not ALLOW_SPOTTING:
self.set_status(401)
self.write(json.dumps("Error - this server does not allow new spots to be added via the API.",
default=serialize_everything))
default=serialize_everything))
self.set_header("Cache-Control", "no-store")
self.set_header("Content-Type", "application/json")
return
# Reject if format not json
if 'Content-Type' not in self.request.headers or self.request.headers.get('Content-Type') != "application/json":
if 'Content-Type' not in self.request.headers or self.request.headers.get(
'Content-Type') != "application/json":
self.set_status(415)
self.write(json.dumps("Error - request Content-Type must be application/json", default=serialize_everything))
self.write(
json.dumps("Error - request Content-Type must be application/json", default=serialize_everything))
self.set_header("Cache-Control", "no-store")
self.set_header("Content-Type", "application/json")
return
@@ -72,7 +75,7 @@ class APISpotHandler(tornado.web.RequestHandler):
if not spot.time or not spot.dx_call or not spot.freq or not spot.de_call:
self.set_status(422)
self.write(json.dumps("Error - 'time', 'dx_call', 'freq' and 'de_call' must be provided as a minimum.",
default=serialize_everything))
default=serialize_everything))
self.set_header("Cache-Control", "no-store")
self.set_header("Content-Type", "application/json")
return
@@ -81,14 +84,14 @@ class APISpotHandler(tornado.web.RequestHandler):
if not re.match(r"^[A-Za-z0-9/\-]*$", spot.dx_call):
self.set_status(422)
self.write(json.dumps("Error - '" + spot.dx_call + "' does not look like a valid callsign.",
default=serialize_everything))
default=serialize_everything))
self.set_header("Cache-Control", "no-store")
self.set_header("Content-Type", "application/json")
return
if not re.match(r"^[A-Za-z0-9/\-]*$", spot.de_call):
self.set_status(422)
self.write(json.dumps("Error - '" + spot.de_call + "' does not look like a valid callsign.",
default=serialize_everything))
default=serialize_everything))
self.set_header("Cache-Control", "no-store")
self.set_header("Content-Type", "application/json")
return
@@ -97,7 +100,7 @@ class APISpotHandler(tornado.web.RequestHandler):
if lookup_helper.infer_band_from_freq(spot.freq) == UNKNOWN_BAND:
self.set_status(422)
self.write(json.dumps("Error - Frequency of " + str(spot.freq / 1000.0) + "kHz is not in a known band.",
default=serialize_everything))
default=serialize_everything))
self.set_header("Cache-Control", "no-store")
self.set_header("Content-Type", "application/json")
return
@@ -108,7 +111,7 @@ class APISpotHandler(tornado.web.RequestHandler):
spot.dx_grid.upper()):
self.set_status(422)
self.write(json.dumps("Error - '" + spot.dx_grid + "' does not look like a valid Maidenhead grid.",
default=serialize_everything))
default=serialize_everything))
self.set_header("Cache-Control", "no-store")
self.set_header("Content-Type", "application/json")
return

View File

@@ -14,8 +14,9 @@ SSE_HANDLER_MAX_QUEUE_SIZE = 100
SSE_HANDLER_QUEUE_CHECK_INTERVAL = 5000
# API request handler for /api/v1/alerts
class APIAlertsHandler(tornado.web.RequestHandler):
"""API request handler for /api/v1/alerts"""
def initialize(self, alerts, web_server_metrics):
self.alerts = alerts
self.web_server_metrics = web_server_metrics
@@ -47,14 +48,17 @@ class APIAlertsHandler(tornado.web.RequestHandler):
self.set_header("Cache-Control", "no-store")
self.set_header("Content-Type", "application/json")
# API request handler for /api/v1/alerts/stream
class APIAlertsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
"""API request handler for /api/v1/alerts/stream"""
def initialize(self, sse_alert_queues, web_server_metrics):
self.sse_alert_queues = sse_alert_queues
self.web_server_metrics = web_server_metrics
# Custom headers to avoid e.g. nginx reverse proxy from buffering SSE data
def custom_headers(self):
"""Custom headers to avoid e.g. nginx reverse proxy from buffering SSE data"""
return {"Cache-Control": "no-store",
"X-Accel-Buffering": "no"}
@@ -81,8 +85,9 @@ class APIAlertsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
except Exception as e:
logging.warn("Exception when serving SSE socket", e)
# When the user closes the socket, empty our queue and remove it from the list so the server no longer fills it
def close(self):
"""When the user closes the socket, empty our queue and remove it from the list so the server no longer fills it"""
try:
if self.alert_queue in self.sse_alert_queues:
self.sse_alert_queues.remove(self.alert_queue)
@@ -96,8 +101,9 @@ class APIAlertsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
self.alert_queue = None
super().close()
# Callback to check if anything has arrived in the queue, and if so send it to the client
def _callback(self):
"""Callback to check if anything has arrived in the queue, and if so send it to the client"""
try:
if self.alert_queue:
while not self.alert_queue.empty():
@@ -114,11 +120,10 @@ class APIAlertsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
self.close()
# Utility method to apply filters to the overall alert list and return only a subset. Enables query parameters in
# the main "alerts" GET call.
def get_alert_list_with_filters(all_alerts, query):
"""Utility method to apply filters to the overall alert list and return only a subset. Enables query parameters in
the main "alerts" GET call."""
# Create a shallow copy of the alert list ordered by start time, then filter the list to reduce it only to alerts
# that match the filter parameters in the query string. Finally, apply a limit to the number of alerts returned.
# The list of query string filters is defined in the API docs.
@@ -134,9 +139,11 @@ def get_alert_list_with_filters(all_alerts, query):
alerts = alerts[:int(query.get("limit"))]
return alerts
# 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.
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
of query parameters and their function is defined in the API docs."""
for k in query.keys():
match k:
case "received_since":

View File

@@ -16,8 +16,9 @@ from data.sig_ref import SIGRef
from data.spot import Spot
# API request handler for /api/v1/lookup/call
class APILookupCallHandler(tornado.web.RequestHandler):
"""API request handler for /api/v1/lookup/call"""
def initialize(self, web_server_metrics):
self.web_server_metrics = web_server_metrics
@@ -75,8 +76,9 @@ class APILookupCallHandler(tornado.web.RequestHandler):
self.set_header("Content-Type", "application/json")
# API request handler for /api/v1/lookup/sigref
class APILookupSIGRefHandler(tornado.web.RequestHandler):
"""API request handler for /api/v1/lookup/sigref"""
def initialize(self, web_server_metrics):
self.web_server_metrics = web_server_metrics
@@ -123,9 +125,9 @@ class APILookupSIGRefHandler(tornado.web.RequestHandler):
self.set_header("Content-Type", "application/json")
# API request handler for /api/v1/lookup/grid
class APILookupGridHandler(tornado.web.RequestHandler):
"""API request handler for /api/v1/lookup/grid"""
def initialize(self, web_server_metrics):
self.web_server_metrics = web_server_metrics
@@ -152,17 +154,17 @@ class APILookupGridHandler(tornado.web.RequestHandler):
center_itu_zone = lat_lon_to_itu_zone(center_lat, center_lon)
response = {
"center" : {
"center": {
"latitude": center_lat,
"longitude": center_lon,
"cq_zone": center_cq_zone,
"itu_zone": center_itu_zone
},
"southwest" : {
"southwest": {
"latitude": lat,
"longitude": lon,
},
"northeast" : {
"northeast": {
"latitude": lat + lat_cell_size,
"longitude": lon + lon_cell_size,
}}

View File

@@ -10,8 +10,9 @@ from core.prometheus_metrics_handler import api_requests_counter
from core.utils import serialize_everything
# API request handler for /api/v1/options
class APIOptionsHandler(tornado.web.RequestHandler):
"""API request handler for /api/v1/options"""
def initialize(self, status_data, web_server_metrics):
self.status_data = status_data
self.web_server_metrics = web_server_metrics

View File

@@ -14,8 +14,9 @@ SSE_HANDLER_MAX_QUEUE_SIZE = 1000
SSE_HANDLER_QUEUE_CHECK_INTERVAL = 5000
# API request handler for /api/v1/spots
class APISpotsHandler(tornado.web.RequestHandler):
"""API request handler for /api/v1/spots"""
def initialize(self, spots, web_server_metrics):
self.spots = spots
self.web_server_metrics = web_server_metrics
@@ -48,19 +49,22 @@ class APISpotsHandler(tornado.web.RequestHandler):
self.set_header("Content-Type", "application/json")
# API request handler for /api/v1/spots/stream
class APISpotsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
"""API request handler for /api/v1/spots/stream"""
def initialize(self, sse_spot_queues, web_server_metrics):
self.sse_spot_queues = sse_spot_queues
self.web_server_metrics = web_server_metrics
# Custom headers to avoid e.g. nginx reverse proxy from buffering SSE data
def custom_headers(self):
"""Custom headers to avoid e.g. nginx reverse proxy from buffering SSE data"""
return {"Cache-Control": "no-store",
"X-Accel-Buffering": "no"}
# Called once on the client opening a connection, set things up
def open(self):
"""Called once on the client opening a connection, set things up"""
try:
# Metrics
self.web_server_metrics["last_api_access_time"] = datetime.now(pytz.UTC)
@@ -83,8 +87,9 @@ class APISpotsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
except Exception as e:
logging.warn("Exception when serving SSE socket", e)
# When the user closes the socket, empty our queue and remove it from the list so the server no longer fills it
def close(self):
"""When the user closes the socket, empty our queue and remove it from the list so the server no longer fills it"""
try:
if self.spot_queue in self.sse_spot_queues:
self.sse_spot_queues.remove(self.spot_queue)
@@ -98,8 +103,9 @@ class APISpotsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
self.spot_queue = None
super().close()
# Callback to check if anything has arrived in the queue, and if so send it to the client
def _callback(self):
"""Callback to check if anything has arrived in the queue, and if so send it to the client"""
try:
if self.spot_queue:
while not self.spot_queue.empty():
@@ -116,10 +122,10 @@ class APISpotsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
self.close()
# Utility method to apply filters to the overall spot list and return only a subset. Enables query parameters in
# the main "spots" GET call.
def get_spot_list_with_filters(all_spots, query):
"""Utility method to apply filters to the overall spot list and return only a subset. Enables query parameters in
the main "spots" GET call."""
# Create a shallow copy of the spot list, ordered by spot time, then filter the list to reduce it only to spots
# that match the filter parameters in the query string. Finally, apply a limit to the number of spots returned.
# The list of query string filters is defined in the API docs.
@@ -142,22 +148,24 @@ def get_spot_list_with_filters(all_spots, query):
# 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.
if "dedupe" in query.keys():
dedupe = query.get("dedupe").upper() == "TRUE"
if dedupe:
spots_temp = []
already_seen = []
for s in spots:
call_plus_ssid = s.dx_call + (s.dx_ssid if s.dx_ssid else "")
if call_plus_ssid not in already_seen:
spots_temp.append(s)
already_seen.append(call_plus_ssid)
spots = spots_temp
dedupe = query.get("dedupe").upper() == "TRUE"
if dedupe:
spots_temp = []
already_seen = []
for s in spots:
call_plus_ssid = s.dx_call + (s.dx_ssid if s.dx_ssid else "")
if call_plus_ssid not in already_seen:
spots_temp.append(s)
already_seen.append(call_plus_ssid)
spots = spots_temp
return spots
# 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.
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
of query parameters and their function is defined in the API docs."""
for k in query.keys():
match k:
case "since":
@@ -240,4 +248,4 @@ def spot_allowed_by_query(spot, query):
needs_good_location = query.get(k).upper() == "TRUE"
if needs_good_location and not spot.dx_location_good:
return False
return True
return True

View File

@@ -8,8 +8,9 @@ from core.prometheus_metrics_handler import api_requests_counter
from core.utils import serialize_everything
# API request handler for /api/v1/status
class APIStatusHandler(tornado.web.RequestHandler):
"""API request handler for /api/v1/status"""
def initialize(self, status_data, web_server_metrics):
self.status_data = status_data
self.web_server_metrics = web_server_metrics