-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: restructure package as library (#27)
* restructure app for library use * add error tracking, exit codes * add unit tests * add unit test workflow * revamp versioning system
- Loading branch information
Showing
13 changed files
with
824 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ build | |
jmenu.spec | ||
.ruff_cache | ||
*.egg-info | ||
.pytest_cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
build==1.0.0 | ||
certifi==2023.7.22 | ||
charset-normalizer==3.2.0 | ||
exceptiongroup==1.1.3 | ||
idna==3.4 | ||
iniconfig==2.0.0 | ||
packaging==23.1 | ||
pluggy==1.3.0 | ||
pyproject_hooks==1.0.0 | ||
pytest==7.4.2 | ||
requests==2.31.0 | ||
tomli==2.0.1 | ||
urllib3==2.0.4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
"""api.py | ||
Contains functions used to wrangle the JAMIX API. | ||
This file can be imported and exposes the following functions: | ||
* fetch_restaurant | ||
* parse_items_from_response | ||
* get_menu_items | ||
The following constants are also exposed: | ||
* API_URL | ||
""" | ||
|
||
|
||
import requests | ||
from datetime import datetime | ||
from .classes import Restaurant, MenuItem, SKIPPED_ITEMS | ||
|
||
API_URL = "https://fi.jamix.cloud/apps/menuservice/rest/haku/menu" | ||
|
||
|
||
def fetch_restaurant(rest: Restaurant, fetch_date: datetime) -> list[dict]: | ||
"""Return the JSON response containing all menu information for [Restaurant] | ||
Parameters | ||
---------- | ||
rest : Restaurant | ||
dataclass containing relevant restaurant information, see classes.RESTAURANTS | ||
fetch_date : datetime | ||
datetime object used to fetch the date specified menu | ||
Returns | ||
------- | ||
list[dict] | ||
parsed response json | ||
""" | ||
response = requests.get( | ||
f"{API_URL}/{rest.client_id}/{rest.kitchen_id}?lang=fi&date={fetch_date.strftime('%Y%m%d')}", | ||
timeout=5, | ||
) | ||
return response.json() | ||
|
||
|
||
def get_menu_items(rest: Restaurant, fetch_date: datetime) -> list[MenuItem]: | ||
"""Returns a list of restaurant [MenuItems] | ||
Parameters | ||
---------- | ||
rest : Restaurant | ||
dataclass containing relevant restaurant information, see classes.RESTAURANTS | ||
fetch_date : datetime | ||
datetime object used to fetch the date specified menu | ||
Returns | ||
------- | ||
list[MenuItem] | ||
list of restaurant menu items, see classes.MenuItem | ||
""" | ||
data = fetch_restaurant(rest, fetch_date) | ||
items = parse_items_from_response(data, rest.relevant_menus) | ||
return items | ||
|
||
|
||
def parse_items_from_response( | ||
data: list[dict], relevant_menus: list[str] = [] | ||
) -> list[MenuItem]: | ||
"""Returns a list of [MenuItems] parsed from JSON data | ||
Parameters | ||
---------- | ||
data : list[dict] | ||
parsed JSON response from the jamix API, see api._fetch_restaurant | ||
relevant_menus : list[str] | ||
list of menu names to consider when parsing | ||
defaults to empty list | ||
Returns | ||
------- | ||
list[MenuItem] | ||
list of restaurant menu items, see classes.MenuItem""" | ||
menus = [] | ||
for kitchen in data: | ||
for m_type in kitchen["menuTypes"]: | ||
if len(relevant_menus) == 0 or m_type["menuTypeName"] in relevant_menus: | ||
menus.extend(m_type["menus"]) | ||
if len(menus) == 0: | ||
return [] | ||
items = [] | ||
for menu in menus: | ||
day = menu["days"][0] | ||
mealopts = day["mealoptions"] | ||
sorted(mealopts, key=lambda x: x["orderNumber"]) | ||
for opt in mealopts: | ||
for item in opt["menuItems"]: | ||
if item["name"] not in SKIPPED_ITEMS: | ||
items.append(MenuItem(item["name"], item["diets"])) | ||
return items |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
"""Classes.py | ||
Contains dataclasses jmenu uses to manage data. | ||
This file can be imported and exposes the following classes: | ||
* MenuItem | ||
* Restaurant | ||
* Marker | ||
The following collections are use-case specific to the University of Oulu: | ||
* MARKERS | ||
* RESTAURANTS | ||
* SKIPPED_ITEMS | ||
""" | ||
|
||
from collections import namedtuple | ||
|
||
|
||
_MenuItem = namedtuple("MenuItem", ["name", "diets"]) | ||
|
||
|
||
class MenuItem(_MenuItem): | ||
"""Dataclass for single menu items and their properties | ||
Attributes | ||
--- | ||
name : str | ||
name of the dish | ||
diets : str | ||
list of allergen markers | ||
""" | ||
|
||
|
||
_Restaurant = namedtuple( | ||
"Restaurant", ["name", "client_id", "kitchen_id", "menu_type", "relevant_menus"] | ||
) | ||
|
||
|
||
class Restaurant(_Restaurant): | ||
"""Dataclass for relevant restaurant information | ||
Attributes | ||
--- | ||
name : str | ||
name of the restaurant | ||
client_id : str | ||
internal jamix identifier used for restaurant providers | ||
kitchen_id : str | ||
internal jamix identifier used to assign menu content | ||
menu_type : str | ||
internal jamix identifier used to classify menus based on content | ||
relevant_menus : str | ||
menu names used for filtering out desserts etc. | ||
""" | ||
|
||
|
||
_Marker = namedtuple("Marker", ["letters", "explanation"]) | ||
|
||
|
||
class Marker(_Marker): | ||
"""Dataclass for allergen information markings | ||
Attributes | ||
--- | ||
letters : str | ||
allergen markings | ||
explanation : str | ||
extended information about the marker | ||
""" | ||
|
||
|
||
SKIPPED_ITEMS = [ | ||
"proteiinilisäke", | ||
"Täysjyväriisi", | ||
"Lämmin kasvislisäke", | ||
"Höyryperunat", | ||
"Tumma pasta", | ||
"Meillä tehty perunamuusi", | ||
] | ||
|
||
RESTAURANTS = [ | ||
Restaurant("Foobar", 93077, 49, 84, ["Foobar Salad and soup", "Foobar Rohee"]), | ||
Restaurant("Foodoo", 93077, 48, 89, ["Foodoo Salad and soup", "Foodoo Reilu"]), | ||
Restaurant("Kastari", 95663, 5, 2, ["Ruokalista"]), | ||
Restaurant("Kylymä", 93077, 48, 92, ["Kylymä Rohee"]), | ||
Restaurant("Mara", 93077, 49, 111, ["Salad and soup", "Ravintola Mara"]), | ||
Restaurant("Napa", 93077, 48, 79, ["Napa Rohee"]), | ||
] | ||
|
||
MARKERS = [ | ||
Marker("G", "Gluteeniton"), | ||
Marker("M", "Maidoton"), | ||
Marker("L", "Laktoositon"), | ||
Marker("SO", "Sisältää soijaa"), | ||
Marker("SE", "Sisältää selleriä"), | ||
Marker("MU", "Munaton"), | ||
Marker("[S], *", "Kelan korkeakouluruokailunsuosituksen mukainen"), | ||
Marker("SIN", "Sisältää sinappia"), | ||
Marker("<3", "Sydänmerkki"), | ||
Marker("VEG", "Vegaani"), | ||
] |
Oops, something went wrong.