diff --git a/agenda/fx.py b/agenda/fx.py index efd4d7d..90cbc5f 100644 --- a/agenda/fx.py +++ b/agenda/fx.py @@ -90,14 +90,10 @@ def get_rates(config: flask.config.Config) -> dict[str, Decimal]: except httpx.ConnectError: return read_cached_rates(full_path, currencies) - try: - data = json.loads(response.text, parse_float=Decimal) - except json.decoder.JSONDecodeError: - return read_cached_rates(full_path, currencies) - with open(os.path.join(fx_dir, filename), "w") as file: file.write(response.text) + data = json.loads(response.text, parse_float=Decimal) return { cur: Decimal(data["quotes"][f"GBP{cur}"]) for cur in currencies diff --git a/agenda/thespacedevs.py b/agenda/thespacedevs.py index 3192448..15ad455 100644 --- a/agenda/thespacedevs.py +++ b/agenda/thespacedevs.py @@ -136,7 +136,7 @@ def summarize_launch(launch: Launch) -> Summary: "launch_provider": launch_provider, "launch_provider_abbrev": launch_provider_abbrev, "launch_provider_type": get_nested(launch, ["launch_service_provider", "type"]), - "rocket": launch["rocket"]["configuration"], + "rocket": launch["rocket"]["configuration"]["full_name"], "mission": launch.get("mission"), "mission_name": get_nested(launch, ["mission", "name"]), "pad_name": launch["pad"]["name"], @@ -174,10 +174,7 @@ def get_launches( existing.sort(reverse=True) if refresh or not existing or (now - existing[0][0]).seconds > ttl: - try: - return next_launch_api(rocket_dir, limit=limit) - except Exception: - pass # fallback to cached version + return next_launch_api(rocket_dir, limit=limit) f = existing[0][1] diff --git a/agenda/types.py b/agenda/types.py index a8f3a8f..6d18909 100644 --- a/agenda/types.py +++ b/agenda/types.py @@ -12,12 +12,28 @@ from pycountry.db import Country import agenda from agenda import format_list_with_ampersand -from . import utils - StrDict = dict[str, typing.Any] DateOrDateTime = datetime.datetime | datetime.date +def as_date(d: DateOrDateTime) -> datetime.date: + """Convert datetime to date.""" + if isinstance(d, datetime.datetime): + return d.date() + assert isinstance(d, datetime.date) + return d + + +def as_datetime(d: DateOrDateTime) -> datetime.datetime: + """Date/time of event.""" + t0 = datetime.datetime.min.time() + return ( + d + if isinstance(d, datetime.datetime) + else datetime.datetime.combine(d, t0).replace(tzinfo=datetime.timezone.utc) + ) + + @dataclass class TripElement: """Trip element.""" @@ -90,20 +106,18 @@ class Trip: def end(self) -> datetime.date | None: """End date for trip.""" max_conference_end = ( - max(utils.as_date(item["end"]) for item in self.conferences) + max(as_date(item["end"]) for item in self.conferences) if self.conferences else datetime.date.min ) assert isinstance(max_conference_end, datetime.date) - arrive = [ - utils.as_date(item["arrive"]) for item in self.travel if "arrive" in item - ] + arrive = [as_date(item["arrive"]) for item in self.travel if "arrive" in item] travel_end = max(arrive) if arrive else datetime.date.min assert isinstance(travel_end, datetime.date) accommodation_end = ( - max(utils.as_date(item["to"]) for item in self.accommodation) + max(as_date(item["to"]) for item in self.accommodation) if self.accommodation else datetime.date.min ) @@ -300,7 +314,7 @@ class Trip: ) ) - return sorted(elements, key=lambda e: utils.as_datetime(e.start_time)) + return sorted(elements, key=lambda e: as_datetime(e.start_time)) def elements_grouped_by_day(self) -> list[tuple[datetime.date, list[TripElement]]]: """Group trip elements by day.""" @@ -311,7 +325,7 @@ class Trip: for element in self.elements(): # Extract the date part of the 'when' attribute - day = utils.as_date(element.start_time) + day = as_date(element.start_time) grouped_elements[day].append(element) # Sort elements within each day @@ -320,7 +334,7 @@ class Trip: key=lambda e: ( e.element_type == "check-in", # check-out elements last e.element_type != "check-out", # check-in elements first - utils.as_datetime(e.start_time), # then sort by time + as_datetime(e.start_time), # then sort by time ) ) @@ -389,7 +403,13 @@ class Event: @property def as_datetime(self) -> datetime.datetime: """Date/time of event.""" - return utils.as_datetime(self.date) + d = self.date + t0 = datetime.datetime.min.time() + return ( + d + if isinstance(d, datetime.datetime) + else datetime.datetime.combine(d, t0).replace(tzinfo=datetime.timezone.utc) + ) @property def has_time(self) -> bool: diff --git a/agenda/utils.py b/agenda/utils.py deleted file mode 100644 index 0324df3..0000000 --- a/agenda/utils.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Utility functions.""" - -import datetime - -DateOrDateTime = datetime.datetime | datetime.date - - -def as_date(d: DateOrDateTime) -> datetime.date: - """Convert datetime to date.""" - if isinstance(d, datetime.datetime): - return d.date() - assert isinstance(d, datetime.date) - return d - - -def as_datetime(d: DateOrDateTime) -> datetime.datetime: - """Date/time of event.""" - t0 = datetime.datetime.min.time() - return ( - d - if isinstance(d, datetime.datetime) - else datetime.datetime.combine(d, t0).replace(tzinfo=datetime.timezone.utc) - ) diff --git a/templates/launches.html b/templates/launches.html index 1756424..a8baede 100644 --- a/templates/launches.html +++ b/templates/launches.html @@ -6,40 +6,7 @@

Space launches

-

Filters

- -

Mission type: - - {% if request.args.type %}🗙{% endif %} - - {% for t in mission_types | sort %} - {% if t == request.args.type %} - {{ t }} - {% else %} - - {{ t }} - - {% endif %} - {% if not loop.last %} | {% endif %} - {% endfor %} -

- -

Vehicle: - {% if request.args.rocket %}🗙{% endif %} - - {% for r in rockets | sort %} - {% if r == request.args.rockets %} - {{ r }} - {% else %} - - {{ r }} - - {% endif %} - {% if not loop.last %} | {% endif %} - {% endfor %} -

- - {% for launch in launches %} + {% for launch in rockets %} {% set highlight =" bg-primary-subtle" if launch.slug in config.FOLLOW_LAUNCHES else "" %} {% set country = get_country(launch.country_code) %}
@@ -57,7 +24,7 @@
{{ country.flag }} - {{ launch.rocket.full_name }} + {{ launch.rocket }} – {{launch.mission.name }} – diff --git a/templates/weekends.html b/templates/weekends.html index f443ff6..e787aa6 100644 --- a/templates/weekends.html +++ b/templates/weekends.html @@ -21,7 +21,7 @@ {{ weekend.date.isocalendar().week }} - + {{ weekend.date.strftime("%-d %b %Y") }} {% for day in "saturday", "sunday" %} diff --git a/web_view.py b/web_view.py index c3e663a..ca643c4 100755 --- a/web_view.py +++ b/web_view.py @@ -35,7 +35,7 @@ agenda.error_mail.setup_error_mail(app) @app.before_request def handle_auth() -> None: - """Handle authentication and set global user.""" + """Handle autentication and set global user.""" flask.g.user = UniAuth.auth.get_current_user() @@ -145,34 +145,10 @@ def launch_list() -> str: now = datetime.now() data_dir = app.config["DATA_DIR"] rocket_dir = os.path.join(data_dir, "thespacedevs") - launches = agenda.thespacedevs.get_launches(rocket_dir, limit=100) - - mission_type_filter = flask.request.args.get("type") - rocket_filter = flask.request.args.get("rocket") - - mission_types = { - launch["mission"]["type"] for launch in launches if launch["mission"] - } - - rockets = {launch["rocket"]["full_name"] for launch in launches} - - launches = [ - launch - for launch in launches - if ( - not mission_type_filter - or (launch["mission"] and launch["mission"]["type"] == mission_type_filter) - ) - and (not rocket_filter or launch["rocket"]["full_name"] == rocket_filter) - ] + rockets = agenda.thespacedevs.get_launches(rocket_dir, limit=100) return flask.render_template( - "launches.html", - launches=launches, - rockets=rockets, - now=now, - get_country=agenda.get_country, - mission_types=mission_types, + "launches.html", rockets=rockets, now=now, get_country=agenda.get_country )