Chronological order validation for YAML

This commit is contained in:
Edward Betts 2025-07-20 01:10:56 +02:00
parent 4b8c29a8d0
commit 412d8c7ba7

View file

@ -4,7 +4,7 @@
import os
import sys
import typing
from datetime import date, timedelta
from datetime import date, timedelta, datetime
import yaml
from rich.pretty import pprint
@ -33,7 +33,26 @@ def check_currency(item: agenda.types.StrDict) -> None:
def check_trips() -> None:
"""Check trips."""
"""Check trips and ensure they are in chronological order."""
filepath = os.path.join(data_dir, "trips.yaml")
trips_data = yaml.safe_load(open(filepath, "r"))
prev_trip = None
prev_trip_data = None
for trip_data in trips_data:
current_trip = normalize_datetime(trip_data["trip"])
if prev_trip and current_trip < prev_trip:
print(f"Out of order trip found:")
print(
f" Previous: {prev_trip_data.get('trip')} - {prev_trip_data.get('name', 'No name')}"
)
print(
f" Current: {trip_data.get('trip')} - {trip_data.get('name', 'No name')}"
)
assert False, "Trips are not in chronological order by trip date."
prev_trip = current_trip
prev_trip_data = trip_data
trip_list = agenda.trip.build_trip_list(data_dir)
print(len(trip_list), "trips")
@ -76,25 +95,68 @@ def check_flights(airlines: set[str]) -> None:
)
def normalize_datetime(dt_value):
"""Convert date or datetime to datetime for comparison, removing timezone info."""
if isinstance(dt_value, date) and not isinstance(dt_value, datetime):
return datetime.combine(dt_value, datetime.min.time())
elif isinstance(dt_value, datetime):
# Remove timezone info to allow comparison between naive and aware datetimes
return dt_value.replace(tzinfo=None)
return dt_value
def check_trains() -> None:
"""Check trains."""
"""Check trains and ensure they are in chronological order."""
trains = agenda.travel.parse_yaml("trains", data_dir)
prev_depart = None
prev_train = None
for train in trains:
current_depart = normalize_datetime(train["depart"])
if prev_depart and current_depart < prev_depart:
print(f"Out of order train found:")
print(
f" Previous: {prev_train.get('depart')} {prev_train.get('from', '')} -> {prev_train.get('to', '')}"
)
print(
f" Current: {train.get('depart')} {train.get('from', '')} -> {train.get('to', '')}"
)
assert False, "Trains are not in chronological order by departure time."
prev_depart = current_depart
prev_train = train
print(len(trains), "trains")
def check_conferences() -> None:
"""Check conferences."""
"""Check conferences and ensure they are in chronological order."""
filepath = os.path.join(data_dir, "conferences.yaml")
conferences = [
agenda.conference.Conference(**conf)
for conf in yaml.safe_load(open(filepath, "r"))
]
for conf in conferences:
conferences_data = yaml.safe_load(open(filepath, "r"))
conferences = [agenda.conference.Conference(**conf) for conf in conferences_data]
prev_start = None
prev_conf_data = None
for i, conf_data in enumerate(conferences_data):
conf = conferences[i]
if not conf.currency or conf.currency in currencies:
continue
pprint(conf)
print(f"currency {conf.currency!r} not in {currencies!r}")
sys.exit(-1)
pass
else:
pprint(conf)
print(f"currency {conf.currency!r} not in {currencies!r}")
sys.exit(-1)
current_start = normalize_datetime(conf_data["start"])
if prev_start and current_start < prev_start:
print(f"Out of order conference found:")
print(
f" Previous: {prev_conf_data.get('start')} - {prev_conf_data.get('name', 'No name')}"
)
print(
f" Current: {conf_data.get('start')} - {conf_data.get('name', 'No name')}"
)
assert False, "Conferences are not in chronological order by start time."
prev_start = current_start
prev_conf_data = conf_data
print(len(conferences), "conferences")
@ -118,12 +180,14 @@ def check_coordinates(item: agenda.types.StrDict) -> None:
def check_accommodation() -> None:
"""Check accommodation."""
"""Check accommodation and ensure they are in chronological order."""
filepath = os.path.join(data_dir, "accommodation.yaml")
accommodation_list = yaml.safe_load(open(filepath))
required_fields = ["type", "name", "country", "location", "trip", "from", "to"]
prev_from = None
prev_stay = None
for stay in accommodation_list:
try:
assert all(field in stay for field in required_fields)
@ -134,6 +198,21 @@ def check_accommodation() -> None:
check_currency(stay)
current_from = normalize_datetime(stay["from"])
if prev_from and current_from < prev_from:
print(f"Out of order accommodation found:")
print(
f" Previous: {prev_stay.get('from')} - {prev_stay.get('name', 'No name')} ({prev_stay.get('location', '')})"
)
print(
f" Current: {stay.get('from')} - {stay.get('name', 'No name')} ({stay.get('location', '')})"
)
assert (
False
), "Accommodation is not in chronological order by check-in time."
prev_from = current_from
prev_stay = stay
print(len(accommodation_list), "stays")
@ -157,6 +236,30 @@ def check_stations() -> None:
assert agenda.get_country(station["country"])
def check_ferries() -> None:
"""Check ferries and ensure they are in chronological order."""
ferries = agenda.travel.parse_yaml("ferries", data_dir)
prev_depart = None
prev_ferry = None
for ferry in ferries:
current_depart = normalize_datetime(ferry["depart"])
if prev_depart and current_depart < prev_depart:
print(f"Out of order ferry found:")
print(
f" Previous: {prev_ferry.get('depart')} {prev_ferry.get('from', '')} -> {prev_ferry.get('to', '')}"
)
print(
f" Current: {ferry.get('depart')} {ferry.get('from', '')} -> {ferry.get('to', '')}"
)
assert False, "Ferries are not in chronological order by departure time."
prev_depart = current_depart
prev_ferry = ferry
check_currency(ferry)
print(len(ferries), "ferries")
def check_airlines() -> list[agenda.types.StrDict]:
"""Check airlines."""
airlines = agenda.travel.parse_yaml("airlines", data_dir)
@ -185,6 +288,7 @@ def check() -> None:
check_trips()
check_flights({airline["iata"] for airline in airlines})
check_trains()
check_ferries()
check_conferences()
check_events()
check_accommodation()