diff --git a/stw_potsdam/swp_webspeiseplan_api.py b/stw_potsdam/swp_webspeiseplan_api.py index b485237..bdef6dc 100644 --- a/stw_potsdam/swp_webspeiseplan_api.py +++ b/stw_potsdam/swp_webspeiseplan_api.py @@ -1,9 +1,22 @@ import logging import urllib.request +import urllib.parse import re import time import json +from dataclasses import dataclass + + +@dataclass(frozen=True) +class SWPWebspeiseplanData: + """Downloaded SWP Webspeiseplan data grouped by outlet name.""" + + outlets: dict[str, dict] + locations: dict[str, dict] + menus: dict[str, dict] + meal_categories: dict[str, dict] + class SWPWebspeiseplanAPI: """This class is used download content from SWP_Webspeiseplan. @@ -16,25 +29,34 @@ class SWPWebspeiseplanAPI: logger = logging.getLogger(__name__) def __init__(self): - """Initialize the configuration for the web service.""" + """Initialize the web service client.""" logging.basicConfig() + + def fetch_all(self) -> SWPWebspeiseplanData: + """Download all data required to render OpenMensa feeds.""" proxy_token = self.parse_token() - self.outlets = self.parse_outlets(proxy_token) - self.locations: dict[str, dict] = {} + outlets = self.parse_outlets(proxy_token) locations = { item["id"]: item for item in self.parse_location(proxy_token) } - self.menus: dict[str, dict] = {} - self.meal_categories: dict[str, dict] = {} - for outlet in self.outlets.values(): + menus: dict[str, dict] = {} + meal_categories: dict[str, dict] = {} + outlet_locations: dict[str, dict] = {} + for outlet in outlets.values(): location = outlet["standortID"] menu = self.parse_menu(proxy_token, location) categories = self.parse_meal_category(proxy_token, location) id2cat = {item["gerichtkategorieID"]: item for item in categories} - self.menus[outlet["name"]] = menu - self.meal_categories[outlet["name"]] = id2cat - self.locations[outlet["name"]] = locations[location] + menus[outlet["name"]] = menu + meal_categories[outlet["name"]] = id2cat + outlet_locations[outlet["name"]] = locations[location] + return SWPWebspeiseplanData( + outlets=outlets, + locations=outlet_locations, + menus=menus, + meal_categories=meal_categories, + ) def __spoof_req_headers(self, req: urllib.request.Request): """Add headers to a request . @@ -77,9 +99,8 @@ class SWPWebspeiseplanAPI: Returns: [type]: [description] """ - url = f"{SWPWebspeiseplanAPI.URL_BASE}/index.php?" + "&".join( - [f"{k}={v}" for k, v in params.items()] - ) + query = urllib.parse.urlencode(params) + url = f"{SWPWebspeiseplanAPI.URL_BASE}/index.php?{query}" SWPWebspeiseplanAPI.logger.debug("__parse_model: %s", url) req = urllib.request.Request(url) self.__spoof_req_headers(req) diff --git a/stw_potsdam/xml_types/builder.py b/stw_potsdam/xml_types/builder.py index a2ecaa7..91cd3b2 100644 --- a/stw_potsdam/xml_types/builder.py +++ b/stw_potsdam/xml_types/builder.py @@ -3,7 +3,10 @@ from dataclasses import dataclass import logging from flask import url_for from stw_potsdam.xml_types.openmensa_xml import OpenMensaXML -from stw_potsdam.swp_webspeiseplan_api import SWPWebspeiseplanAPI +from stw_potsdam.swp_webspeiseplan_api import ( + SWPWebspeiseplanAPI, + SWPWebspeiseplanData, +) from stw_potsdam.swp_webspeiseplan_parser import SWPWebspeiseplanParser from stw_potsdam.config import Canteen from stw_potsdam.xml_types.feed_xml import FeedXML, ScheduleXML @@ -15,21 +18,26 @@ class Builder: VERSION = "2.0.1" - def __init__(self, config: dict[str, Canteen]): + def __init__( + self, + config: dict[str, Canteen], + swp_data: SWPWebspeiseplanData | None = None, + ): """Initialize the object for the OpenMensa Feed Doc XML.""" logging.basicConfig() self.logger = logging.getLogger(__name__) self._xml_data = {} - swp_api = SWPWebspeiseplanAPI() + if swp_data is None: + swp_data = SWPWebspeiseplanAPI().fetch_all() swp_parser = SWPWebspeiseplanParser() for cname, ntup in config.items(): - if ntup.name not in swp_api.outlets.keys(): + if ntup.name not in swp_data.outlets.keys(): self.logger.warning("%s not found in keys", ntup.name) continue - outlet = swp_api.outlets[ntup.name] - menus = swp_api.menus[ntup.name] - categories = swp_api.meal_categories[ntup.name] - locations = swp_api.locations[ntup.name] + outlet = swp_data.outlets[ntup.name] + menus = swp_data.menus[ntup.name] + categories = swp_data.meal_categories[ntup.name] + locations = swp_data.locations[ntup.name] outlet["isPublic"] = locations["isPublic"] canteen = swp_parser.parse_canteen_meta_times(outlet) meals = swp_parser.parse_meals(menus, categories) diff --git a/tests/test_swp_webspeiseplan_api.py b/tests/test_swp_webspeiseplan_api.py new file mode 100644 index 0000000..4848b37 --- /dev/null +++ b/tests/test_swp_webspeiseplan_api.py @@ -0,0 +1,12 @@ +# -*- encoding: utf-8 -*- + +from stw_potsdam.swp_webspeiseplan_api import SWPWebspeiseplanAPI + +# pytest fixtures are linked via parameter names of test methods +# pragma pylint: disable=unused-import,unused-argument,redefined-outer-name +from tests.stub_api import api_offline + + +def test_api_init_does_not_fetch(api_offline): + """Creating the API client does not perform network requests.""" + SWPWebspeiseplanAPI()