[server]: Update fetch_transient_data to parse display info
This commit is contained in:
@ -7,7 +7,7 @@ import boto3
|
|||||||
import time
|
import time
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
import re
|
||||||
# Create a reusable session for requests
|
# Create a reusable session for requests
|
||||||
session = requests.Session()
|
session = requests.Session()
|
||||||
|
|
||||||
@ -24,10 +24,10 @@ irishrail_url = "http://api.irishrail.ie/realtime/realtime.asmx/"
|
|||||||
|
|
||||||
def fetch_trains():
|
def fetch_trains():
|
||||||
"""
|
"""
|
||||||
Fetches train data from the Irish Rail API.
|
Fetches train data from the Irish Rail API and parses additional attributes.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list: A list of dictionaries containing train data.
|
list: A list of dictionaries containing processed train data.
|
||||||
"""
|
"""
|
||||||
print("Fetching Irish Rail data.")
|
print("Fetching Irish Rail data.")
|
||||||
api_function = "getCurrentTrainsXML_WithTrainType?TrainType="
|
api_function = "getCurrentTrainsXML_WithTrainType?TrainType="
|
||||||
@ -42,74 +42,57 @@ def fetch_trains():
|
|||||||
trains_json = xmltodict.parse(trains_xml)
|
trains_json = xmltodict.parse(trains_xml)
|
||||||
|
|
||||||
for train in trains_json["ArrayOfObjTrainPositions"]["objTrainPositions"]:
|
for train in trains_json["ArrayOfObjTrainPositions"]["objTrainPositions"]:
|
||||||
|
train_code = str(train["TrainCode"])
|
||||||
|
train_status = train["TrainStatus"]
|
||||||
|
public_message = train["PublicMessage"]
|
||||||
|
|
||||||
|
# Regex to extract punctuality: Matches positive/negative number followed by "mins late"
|
||||||
|
match = re.search(r"(-?\d+)\s+mins\s+late", public_message)
|
||||||
|
punctuality = int(match.group(1)) if match else 0 # Default to 0 if no match
|
||||||
|
|
||||||
|
if punctuality < 0:
|
||||||
|
punctuality_status = "early"
|
||||||
|
lateness_message = f"{-punctuality} minute{'s' if punctuality != -1 else ''} early"
|
||||||
|
elif punctuality == 0:
|
||||||
|
punctuality_status = "on-time"
|
||||||
|
lateness_message = "On time"
|
||||||
|
else:
|
||||||
|
punctuality_status = "late"
|
||||||
|
lateness_message = f"{punctuality} minute{'s' if punctuality != 1 else ''} late"
|
||||||
|
|
||||||
|
train_type_full = {
|
||||||
|
"M": "Mainline",
|
||||||
|
"S": "Suburban",
|
||||||
|
"D": "DART"
|
||||||
|
}.get(train_type, "Unknown")
|
||||||
|
|
||||||
|
train_status_full = {
|
||||||
|
"R": "Running",
|
||||||
|
"T": "Terminated",
|
||||||
|
"N": "Not yet running"
|
||||||
|
}.get(train_status, "Unknown")
|
||||||
|
|
||||||
trains.append({
|
trains.append({
|
||||||
"objectID": "IrishRailTrain-" + train["TrainCode"],
|
"objectID": "IrishRailTrain-" + train_code,
|
||||||
"objectType": "IrishRailTrain",
|
"objectType": "IrishRailTrain",
|
||||||
"timestamp": timestamp,
|
"timestamp": timestamp,
|
||||||
"latitude": str(train["TrainLatitude"]),
|
"latitude": str(train["TrainLatitude"]),
|
||||||
"longitude": str(train["TrainLongitude"]),
|
"longitude": str(train["TrainLongitude"]),
|
||||||
"trainCode": str(train["TrainCode"]),
|
"trainCode": train_code,
|
||||||
"trainType": train_type,
|
"trainType": train_type,
|
||||||
"trainStatus": train["TrainStatus"],
|
"trainTypeFull": train_type_full,
|
||||||
|
"trainStatus": train_status,
|
||||||
|
"trainStatusFull": train_status_full,
|
||||||
"trainDate": str(train["TrainDate"]),
|
"trainDate": str(train["TrainDate"]),
|
||||||
"trainPublicMessage": train["PublicMessage"],
|
"trainPublicMessage": public_message,
|
||||||
"trainDirection": train["Direction"]
|
"trainDirection": train["Direction"],
|
||||||
|
"trainPunctuality": punctuality,
|
||||||
|
"trainPunctualityStatus": punctuality_status,
|
||||||
|
"latenessMessage": lateness_message
|
||||||
})
|
})
|
||||||
|
|
||||||
return trains
|
return trains
|
||||||
|
|
||||||
def fetch_luas():
|
|
||||||
"""
|
|
||||||
Fetches Luas stop and forecast data.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list: A list of dictionaries containing Luas stop and forecast data.
|
|
||||||
"""
|
|
||||||
print("Fetching Luas data.")
|
|
||||||
stops = []
|
|
||||||
|
|
||||||
stops_tsv = session.get("https://data.tii.ie/Datasets/Luas/StopLocations/luas-stops.txt").content.decode('utf-8-sig')
|
|
||||||
tsv_reader = csv.DictReader(stops_tsv.splitlines(), delimiter="\t")
|
|
||||||
|
|
||||||
def fetch_forecast(stop):
|
|
||||||
"""
|
|
||||||
Fetches forecast data for a given Luas stop.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
stop (dict): A dictionary containing Luas stop information.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: A dictionary containing Luas stop and forecast data.
|
|
||||||
"""
|
|
||||||
response = session.get(f"https://luasforecasts.rpa.ie/xml/get.ashx?action=forecast&stop={stop['Abbreviation']}&encrypt=false")
|
|
||||||
response.raise_for_status()
|
|
||||||
trams_xml = response.text
|
|
||||||
trams_json = xmltodict.parse(trams_xml)
|
|
||||||
return {
|
|
||||||
"objectID": "LuasStop-" + stop["Abbreviation"],
|
|
||||||
"objectType": "LuasStop",
|
|
||||||
"timestamp": timestamp,
|
|
||||||
"latitude": str(stop["Latitude"]),
|
|
||||||
"longitude": str(stop["Longitude"]),
|
|
||||||
"luasStopName": stop["Name"],
|
|
||||||
"luasStopIrishName": stop["IrishName"],
|
|
||||||
"luasStopID": str(stop["StopID"]),
|
|
||||||
"luasStopCode": stop["Abbreviation"],
|
|
||||||
"luasStopLineID": str(stop["LineID"]),
|
|
||||||
"luasStopSortOrder": str(stop["SortOrder"]),
|
|
||||||
"luasStopIsEnabled": str(stop["IsEnabled"]),
|
|
||||||
"luasStopIsParkAndRide": str(stop["IsParkAndRide"]),
|
|
||||||
"luasStopIsCycleAndRide": str(stop["IsCycleAndRide"]),
|
|
||||||
"luasStopZoneCountA": str(stop["ZoneCountA"]),
|
|
||||||
"luasStopZoneCountB": str(stop["ZoneCountB"]),
|
|
||||||
"luasStopMessage": str(trams_json["stopInfo"]["message"]),
|
|
||||||
"luasStopTrams": str(trams_json["stopInfo"]["direction"])
|
|
||||||
}
|
|
||||||
|
|
||||||
with ThreadPoolExecutor() as executor:
|
|
||||||
stops = list(executor.map(fetch_forecast, tsv_reader))
|
|
||||||
|
|
||||||
return stops
|
|
||||||
|
|
||||||
def fetch_bus_routes():
|
def fetch_bus_routes():
|
||||||
"""
|
"""
|
||||||
|
@ -16,17 +16,6 @@ class TestTransientData(unittest.TestCase):
|
|||||||
def test_fetch_buses(self, mock_get):
|
def test_fetch_buses(self, mock_get):
|
||||||
"""
|
"""
|
||||||
Test the fetch_buses function to ensure it returns the correct data.
|
Test the fetch_buses function to ensure it returns the correct data.
|
||||||
|
|
||||||
Mocks the network requests to avoid real API calls and sets up the
|
|
||||||
expected responses for bus data and bus routes.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
mock_get (MagicMock): Mocked session.get method.
|
|
||||||
|
|
||||||
Asserts:
|
|
||||||
The length of the result is 1.
|
|
||||||
The busID of the first result is 'bus1'.
|
|
||||||
The busRouteAgencyName of the first result is 'Dublin Bus'.
|
|
||||||
"""
|
"""
|
||||||
# Mock response for bus data
|
# Mock response for bus data
|
||||||
mock_response_1 = MagicMock()
|
mock_response_1 = MagicMock()
|
||||||
@ -59,30 +48,18 @@ class TestTransientData(unittest.TestCase):
|
|||||||
def test_fetch_trains(self, mock_get):
|
def test_fetch_trains(self, mock_get):
|
||||||
"""
|
"""
|
||||||
Test the fetch_trains function to ensure it returns the correct data.
|
Test the fetch_trains function to ensure it returns the correct data.
|
||||||
|
|
||||||
Mocks the network requests to avoid real API calls and sets up the
|
|
||||||
expected response for train data.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
mock_get (MagicMock): Mocked session.get method.
|
|
||||||
|
|
||||||
Asserts:
|
|
||||||
The length of the result is 3.
|
|
||||||
The trainCode of the first result is 'A123'.
|
|
||||||
The trainStatus of the first result is 'Running'.
|
|
||||||
"""
|
"""
|
||||||
# Mock response for train API
|
# Mock response for train API
|
||||||
mock_response = MagicMock()
|
mock_response = MagicMock()
|
||||||
# Fix: Ensure xmltodict.parse() returns a proper dictionary
|
|
||||||
mock_response.text = '''
|
mock_response.text = '''
|
||||||
<ArrayOfObjTrainPositions>
|
<ArrayOfObjTrainPositions>
|
||||||
<objTrainPositions>
|
<objTrainPositions>
|
||||||
<TrainCode>A123</TrainCode>
|
<TrainCode>A123</TrainCode>
|
||||||
<TrainLatitude>53.0</TrainLatitude>
|
<TrainLatitude>53.0</TrainLatitude>
|
||||||
<TrainLongitude>-6.0</TrainLongitude>
|
<TrainLongitude>-6.0</TrainLongitude>
|
||||||
<TrainStatus>Running</TrainStatus>
|
<TrainStatus>R</TrainStatus>
|
||||||
<TrainDate>2025-03-09</TrainDate>
|
<TrainDate>2025-03-09</TrainDate>
|
||||||
<PublicMessage>On time</PublicMessage>
|
<PublicMessage>5 mins late</PublicMessage>
|
||||||
<Direction>Northbound</Direction>
|
<Direction>Northbound</Direction>
|
||||||
</objTrainPositions>
|
</objTrainPositions>
|
||||||
</ArrayOfObjTrainPositions>
|
</ArrayOfObjTrainPositions>
|
||||||
@ -98,9 +75,9 @@ class TestTransientData(unittest.TestCase):
|
|||||||
"TrainCode": "A123",
|
"TrainCode": "A123",
|
||||||
"TrainLatitude": "53.0",
|
"TrainLatitude": "53.0",
|
||||||
"TrainLongitude": "-6.0",
|
"TrainLongitude": "-6.0",
|
||||||
"TrainStatus": "Running",
|
"TrainStatus": "R",
|
||||||
"TrainDate": "2025-03-09",
|
"TrainDate": "2025-03-09",
|
||||||
"PublicMessage": "On time",
|
"PublicMessage": "5 mins late",
|
||||||
"Direction": "Northbound"
|
"Direction": "Northbound"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -110,7 +87,11 @@ class TestTransientData(unittest.TestCase):
|
|||||||
result = fetch_trains()
|
result = fetch_trains()
|
||||||
self.assertEqual(len(result), 3) # 3 train types: M, S, D
|
self.assertEqual(len(result), 3) # 3 train types: M, S, D
|
||||||
self.assertEqual(result[0]['trainCode'], 'A123')
|
self.assertEqual(result[0]['trainCode'], 'A123')
|
||||||
self.assertEqual(result[0]['trainStatus'], 'Running')
|
self.assertEqual(result[0]['trainStatus'], 'R')
|
||||||
|
self.assertEqual(result[0]['trainStatusFull'], 'Running')
|
||||||
|
self.assertEqual(result[0]['trainPunctuality'], 5)
|
||||||
|
self.assertEqual(result[0]['trainPunctualityStatus'], 'late')
|
||||||
|
self.assertEqual(result[0]['latenessMessage'], '5 minutes late')
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Reference in New Issue
Block a user