Bit of a facelift - getting to point of needing templating.

This commit is contained in:
2026-06-06 20:34:22 +01:00
parent a40ca8d806
commit 6d16194838
2 changed files with 74 additions and 44 deletions
+2 -29
View File
@@ -4,34 +4,15 @@ Standard functions to call for fares information.
# Imports # Imports
import requests import requests
import pandas as pd
from os import environ from os import environ
import json import json
# Init. # Init.
COLUMN_RENAMES = {
"origin_code": "Origin",
"destination_code": "Destination",
"route_code": "Route",
"status_code": "Status",
"usage_code": "Usage",
"direction": "Direction",
"end_date": "Ends",
"start_date": "Starts",
"toc": "TOC",
"cross_london_flag": "Cross London",
"settlement_flag": "Settlement",
"discount_flag": "Discount",
"flow_id": "ID",
"ticket_code": "Ticket Code",
"fare": "Fare",
"restriction_code": "Restriction",
}
# Functions # Functions
def fares_query(origin: str, destination: str) -> pd.DataFrame: def fares_query(origin: str, destination: str) -> list[dict[str, dict[str, str]]]:
response = requests.get( response = requests.get(
url=f"https://fares.ballast-data.co.uk/fares?origin={origin}&destination={destination}", url=f"https://fares.ballast-data.co.uk/fares?origin={origin}&destination={destination}",
auth=( auth=(
@@ -39,12 +20,4 @@ def fares_query(origin: str, destination: str) -> pd.DataFrame:
environ.get("BD_FARES_PASS", ""), environ.get("BD_FARES_PASS", ""),
), ),
) )
dfs, data = [], json.loads(response.content.decode()) return json.loads(response.content.decode()) # pyright: ignore[reportAny]
for flow_fares in data:
df = pd.json_normalize(flow_fares["fares"]).drop("flow_id", axis=1)
meta = pd.DataFrame.from_records(
[flow_fares["flow_id"] | {"Number": number} for number in df.index]
).rename(COLUMN_RENAMES, axis=1)
df.index = pd.MultiIndex.from_frame(meta)
dfs.append(df)
return pd.concat(dfs).rename(COLUMN_RENAMES, axis=1)
+72 -15
View File
@@ -3,8 +3,11 @@ Web server core for the fares site.
""" """
# Import # Import
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from logging import Logger, INFO from logging import INFO, Logger
import pandas as pd
from pandas.io.formats.style import Styler
from requests.exceptions import ConnectionError from requests.exceptions import ConnectionError
from fares_site.api_calling import fares_query from fares_site.api_calling import fares_query
@@ -13,6 +16,25 @@ from fares_site.api_calling import fares_query
DEFAULT_ADDRESS = "127.0.0.1" DEFAULT_ADDRESS = "127.0.0.1"
DEFAULT_PORT = 12_000 DEFAULT_PORT = 12_000
COLUMN_RENAMES = {
"origin_code": "Origin",
"destination_code": "Destination",
"route_code": "Route",
"status_code": "Status",
"usage_code": "Usage",
"direction": "Direction",
"end_date": "Ends",
"start_date": "Starts",
"toc": "TOC",
"cross_london_flag": "Cross London",
"settlement_flag": "Settlement",
"discount_flag": "Discount",
"flow_id": "ID",
"ticket_code": "Ticket Code",
"fare": "Fare",
"restriction_code": "Restriction",
}
HTML_CONTENT_HEADER = """ HTML_CONTENT_HEADER = """
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html>
@@ -23,13 +45,32 @@ HTML_CONTENT_HEADER = """
<link rel="stylesheet" href="https://cdn.ballast-data.co.uk/theme.css"> <link rel="stylesheet" href="https://cdn.ballast-data.co.uk/theme.css">
<link rel="icon" type="image/x-icon" href="https://cdn.ballast-data.co.uk/Icon.svg"> <link rel="icon" type="image/x-icon" href="https://cdn.ballast-data.co.uk/Icon.svg">
</head> </head>
<body> <body style="padding: 0px; margin: 0px;">
<div style="width: 100%; padding: 0px; margin: 0px; background-color: var(--dark-color);">
<div style="margin-left: auto; margin-right: auto; width: fit-content; background-color: var(--secondary-accent); margin-top: 0px; padding: 12px; border-radius: 0 0 9px 9px;">
Ballast-Data Product <br>
Contact: Non-Doxxing Email Lorum Ipsum <br>
Some Header Content
</div>
<br>
<div style="width: fit-content; margin-left: auto; margin-right: auto; border: 9px solid var(--light-color); border-radius: 3px; padding: 12px; background-color: white; border-radius: 9px;">
<div style="width: fit-content; margin-left: auto; margin-right: auto; border-bottom: 9px solid var(--secondary-accent);">
<br>
<img height=80px src="https://cdn.ballast-data.co.uk/Logo.svg"> <img height=80px src="https://cdn.ballast-data.co.uk/Logo.svg">
<b style="font-size: 100px; line-height: 1; font-weight: 400;"> Fares </b> <br> <b style="font-size: 60px; line-height: 1; font-weight: 400;"> RailFares </b> <br>
</div>
<br> <br>
""" """
HTML_CONTENT_FOOTER = """ HTML_CONTENT_FOOTER = """
</div>
<br>
<div style="margin-left: auto; margin-right: auto; width: fit-content; background-color: var(--primary-accent); margin-top: 0px; padding: 12px; border-radius: 9px 9px 0 0;">
Open Rail Data Disclaimer Etc. | No Guarantees or Whatever | We do freelance and dont want to be poor.
</div>
</div>
</body> </body>
</html> </html>
""" """
@@ -51,20 +92,36 @@ class FaresHandler(BaseHTTPRequestHandler):
Generates the content of a GET request. Generates the content of a GET request.
Responsible for receiving the requests' details and constructing the output. Responsible for receiving the requests' details and constructing the output.
""" """
table = fares_query( data = fares_query(
origin=(_d := self.parse_url_query()).get("origin", "NCL"), origin=(_d := self.parse_url_query()).get("origin", "NCL"),
destination=_d.get("destination", "NCL"), destination=_d.get("destination", "NCL"),
).style
table = table.set_table_styles(
[
{"selector": "tr", "props": [("vertical-align", "text-top")]},
{
"selector": "tbody td",
"props": [("border-top", "1px solid var(--dark-color)")],
},
]
) )
text = table.to_html() text = "<table>"
text += (
'<tr style="font-size: 1.6em;"> <th> Flow </th> <th> Fares </th> </tr>\n'
)
for flow_fares in data:
flow_table = (
pd.json_normalize(flow_fares["flow_id"])
.rename(COLUMN_RENAMES, axis=1)
.T.style
)
_ = flow_table.hide(axis=1)
fares_table = (
pd.json_normalize(flow_fares["fares"])
.drop("flow_id", axis=1)
.rename(COLUMN_RENAMES, axis=1)
.style
)
_ = fares_table.hide(axis=0)
text += '<tr> \n <td style="border-top: 6px solid var(--primary-accent); vertical-align: top;">'
text += flow_table.to_html()
text += '</td> <td style="border-top: 6px solid var(--primary-accent); vertical-align: top;">'
text += fares_table.to_html()
text += "</td> \n </tr>"
text += "</table>"
return HTML_CONTENT_HEADER + text + HTML_CONTENT_FOOTER return HTML_CONTENT_HEADER + text + HTML_CONTENT_FOOTER
def do_GET(self) -> None: def do_GET(self) -> None: