OpenMensa parser for STW Potsdam after canteen website redesign

This commit is contained in:
Falco Duersch
2018-09-19 17:15:34 +02:00
commit e0b88bbc87
17 changed files with 5788 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
.cache
.idea
.pytest_cache
+16
View File
@@ -0,0 +1,16 @@
RUN = pipenv run python -m stw_potsdam
run:
$(RUN)
debug:
FLASK_ENV=development $(RUN)
test:
pipenv run python -m pytest -v
test_debug:
pipenv run python -m pytest -v --trace
.PHONY: run debug test test_debug
+7
View File
@@ -0,0 +1,7 @@
[packages]
requests = "*"
pyopenmensa = "*"
flask = "*"
[dev-packages]
pytest = "*"
Generated
+192
View File
@@ -0,0 +1,192 @@
{
"_meta": {
"hash": {
"sha256": "c9813dd3ac9565de259cfecf7c479f2e6d0e4f756aeeea2a3168ae774a79b980"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"certifi": {
"hashes": [
"sha256:376690d6f16d32f9d1fe8932551d80b23e9d393a8578c5633a2ed39a64861638",
"sha256:456048c7e371c089d0a77a5212fb37a2c2dce1e24146e3b7e0261736aaeaa22a"
],
"version": "==2018.8.24"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"click": {
"hashes": [
"sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
"sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
],
"version": "==6.7"
},
"flask": {
"hashes": [
"sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
"sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
],
"index": "pypi",
"version": "==1.0.2"
},
"idna": {
"hashes": [
"sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
"sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"
],
"version": "==2.7"
},
"itsdangerous": {
"hashes": [
"sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"
],
"version": "==0.24"
},
"jinja2": {
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
],
"version": "==2.10"
},
"markupsafe": {
"hashes": [
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
],
"version": "==1.0"
},
"pyopenmensa": {
"hashes": [
"sha256:936100088ffc53699d2d893a1715210f4399a2881247342a6fb77947ebb0aaa0"
],
"index": "pypi",
"version": "==0.95.0"
},
"requests": {
"hashes": [
"sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1",
"sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a"
],
"index": "pypi",
"version": "==2.19.1"
},
"urllib3": {
"hashes": [
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
],
"markers": "python_version != '3.2.*' and python_version != '3.3.*' and python_version != '3.0.*' and python_version != '3.1.*' and python_version < '4' and python_version >= '2.6'",
"version": "==1.23"
},
"werkzeug": {
"hashes": [
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
],
"version": "==0.14.1"
}
},
"develop": {
"atomicwrites": {
"hashes": [
"sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0",
"sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee"
],
"markers": "python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.3.*'",
"version": "==1.2.1"
},
"attrs": {
"hashes": [
"sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69",
"sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb"
],
"version": "==18.2.0"
},
"funcsigs": {
"hashes": [
"sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca",
"sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"
],
"markers": "python_version < '3.0'",
"version": "==1.0.2"
},
"more-itertools": {
"hashes": [
"sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092",
"sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e",
"sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d"
],
"version": "==4.3.0"
},
"pathlib2": {
"hashes": [
"sha256:8eb170f8d0d61825e09a95b38be068299ddeda82f35e96c3301a8a5e7604cb83",
"sha256:d1aa2a11ba7b8f7b21ab852b1fb5afb277e1bb99d5dfc663380b5015c0d80c5a"
],
"markers": "python_version < '3.6'",
"version": "==2.3.2"
},
"pluggy": {
"hashes": [
"sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1",
"sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1"
],
"markers": "python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.3.*'",
"version": "==0.7.1"
},
"py": {
"hashes": [
"sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1",
"sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6"
],
"markers": "python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.3.*'",
"version": "==1.6.0"
},
"pytest": {
"hashes": [
"sha256:453cbbbe5ce6db38717d282b758b917de84802af4288910c12442984bde7b823",
"sha256:a8a07f84e680482eb51e244370aaf2caa6301ef265f37c2bdefb3dd3b663f99d"
],
"index": "pypi",
"version": "==3.8.0"
},
"scandir": {
"hashes": [
"sha256:04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6",
"sha256:1444134990356c81d12f30e4b311379acfbbcd03e0bab591de2696a3b126d58e",
"sha256:1b5c314e39f596875e5a95dd81af03730b338c277c54a454226978d5ba95dbb6",
"sha256:346619f72eb0ddc4cf355ceffd225fa52506c92a2ff05318cfabd02a144e7c4e",
"sha256:44975e209c4827fc18a3486f257154d34ec6eaec0f90fef0cca1caa482db7064",
"sha256:61859fd7e40b8c71e609c202db5b0c1dbec0d5c7f1449dec2245575bdc866792",
"sha256:a5e232a0bf188362fa00123cc0bb842d363a292de7126126df5527b6a369586a",
"sha256:c14701409f311e7a9b7ec8e337f0815baf7ac95776cc78b419a1e6d49889a383",
"sha256:c7708f29d843fc2764310732e41f0ce27feadde453261859ec0fca7865dfc41b",
"sha256:c9009c527929f6e25604aec39b0a43c3f831d2947d89d6caaab22f057b7055c8",
"sha256:f5c71e29b4e2af7ccdc03a020c626ede51da471173b4a6ad1e904f2b2e04b4bd"
],
"markers": "python_version < '3.5'",
"version": "==1.9.0"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
],
"version": "==1.11.0"
}
}
}
+7
View File
@@ -0,0 +1,7 @@
# OpenMensa STW Potsdam
## Development Quickstart
$ pipenv install --two --dev # Create venv
$ make test # Check setup by running tests
$ make debug # Start app instance with debugger
+1
View File
@@ -0,0 +1 @@
# -*- encoding: utf-8 -*-
+4
View File
@@ -0,0 +1,4 @@
# -*- encoding: utf-8 -*-
from views import app
app.run()
+5
View File
@@ -0,0 +1,5 @@
# -*- encoding: utf-8 -*-
from collections import namedtuple
Canteen = namedtuple('Canteen', ('name', 'street', 'city', 'id', 'chash'))
+33
View File
@@ -0,0 +1,33 @@
# -*- encoding: utf-8 -*-
import json
import requests
from collections import namedtuple
MenuParams = namedtuple('MenuParams', ('canteen_id', 'chash'))
URL = 'https://www.studentenwerk-potsdam.de/essen/unsere-mensen-cafeterien/detailinfos/'
def _param_json(it):
return json.dumps(it, separators=(',', ':'))
def download_menu(menu_params):
context = {
'record': 'pages_66',
'path': 'tt_content.list.20.ddfmensa_ddfmensajson'
}
params = {
'tx_typoscriptrendering[context]': _param_json(context),
'tx_ddfmensa_ddfmensajson[mensa]': menu_params.canteen_id,
'cHash': menu_params.chash
}
body = {
'data': False
}
request = requests.post(URL, params=params, json=body)
return request.json()
+41
View File
@@ -0,0 +1,41 @@
[neues_palais]
name = Mensa Am Neuen Palais
street = Am Neuen Palais 10, Haus 12
city = 14469 Potsdam
id = 1
cHash = 677e69a0122d1ccca57a6c30dd149cc8
[golm]
name = Mensa Golm
street = Karl-Liebknecht-Straße 24/25
city = 14476 Potsdam / OT Golm
id = 4
cHash = b14a1168346e0b7db67da056660d3a0e
[griebnitzsee]
name = Mensa Griebnitzsee
street = August-Bebel-Straße 69, Haus 6
city = 14482 Potsdam
id = 6
cHash = 0c7f1095dcc78ff74b6cd32cd231c75f
[kiepenheuerallee]
name = Mensa Kiepenheuerallee
street = Kiepenheuerallee 5
city = 14469 Potsdam
id = 7
cHash = 3900afbd3d9b776e947708b7dfd2378c
[wildau]
name = Mensa Wildau
street = Hochschulring 1
city = 15745 Wildau
id = 33
cHash = 2ba7ac17766ceec4a35dac29b593378f
[brandenburg]
name = Mensa Brandenburg an der Havel
street = Magdeburger Straße 50
city = 14770 Brandenburg an der Havel
id = 38
cHash = 0843fa029901bdfc0e76d8f31eee7f56
+29
View File
@@ -0,0 +1,29 @@
# -*- encoding: utf-8 -*-
import ConfigParser
import io
import os
from functools import partial
from canteen import Canteen
def _get_config(filename):
config = ConfigParser.SafeConfigParser()
path = os.path.join('stw_potsdam', filename)
with io.open(path, encoding='utf-8') as f:
config.readfp(f)
return config
def _parse_canteen(config, canteen_name):
get = partial(config.get, canteen_name)
return Canteen(name=get('name'),
street=get('street'),
city=get('city'),
id=get('id'),
chash=get('cHash'))
def read_canteen_config():
config = _get_config('canteens.ini')
return {name: _parse_canteen(config, name) for name in config.sections()}
+65
View File
@@ -0,0 +1,65 @@
# -*- encoding: utf-8 -*-
from pyopenmensa.feed import LazyBuilder
PRICE_ROLE_MAPPING = {
'student': 'preis_s',
'other': 'preis_g',
'employee': 'preis_m'
}
def _active_days(menu):
for container in menu['wochentage']:
day = container['datum']
active = 'angebote' in day
if active:
yield day
def _notes(offer):
result = []
for label in offer['labels']:
result.append(label['name'].capitalize())
return result
def _prices(offer):
result = {}
for role, api_role in PRICE_ROLE_MAPPING.items():
if api_role not in offer:
continue
price = offer[api_role]
# When no price is set, this can be empty dict
if (isinstance(price, unicode) or isinstance(price, str)) and price.strip():
result[role] = str(price) # Convert unicode to str for PyOpenMensa -> misses type check
return result
def _process_day(builder, day):
for offer in day['angebote']:
builder.addMeal(date=day['data'],
category=offer['titel'],
name=offer['beschreibung'],
notes=_notes(offer),
prices=_prices(offer),
roles=None)
def _create_builder(canteen):
builder = LazyBuilder()
builder.name = canteen.name
builder.address = canteen.street
builder.city = canteen.city
return builder
def render(canteen, menu):
builder = _create_builder(canteen)
for day in _active_days(menu):
_process_day(builder, day)
return builder.toXMLFeed()
+56
View File
@@ -0,0 +1,56 @@
# -*- encoding: utf-8 -*-
from flask import Flask, make_response
from werkzeug.contrib.cache import SimpleCache
import feed
from config import read_canteen_config
from canteen_api import MenuParams, download_menu
CACHE_TIMEOUT = 45 * 60
app = Flask(__name__)
cache = SimpleCache()
def canteen_not_found(config, canteen_name):
app.logger.warn('Canteen %s not found', canteen_name)
configured = ', '.join("'{}'".format(c) for c in config.keys())
message = "Canteen '{canteen}' not found, available: {configured}".format(canteen=canteen_name,
configured=configured)
return make_response(message, 404)
def get_menu_cached(canteen):
params = MenuParams(canteen_id=canteen.id, chash=canteen.chash)
menu = cache.get(params)
if menu:
app.logger.info('Using cached menu for %s', canteen)
return menu or get_menu(canteen, params)
def get_menu(canteen, params):
app.logger.info('Downloading menu for %s', canteen)
menu = download_menu(params)
cache.set(params, menu, timeout=CACHE_TIMEOUT)
return menu
def canteen_feed_xml(canteen, menu):
xml = feed.render(canteen, menu)
response = make_response(xml)
response.mimetype = 'text/xml'
return response
@app.route('/canteen/<canteen_name>')
def canteen_feed(canteen_name):
config = read_canteen_config()
if canteen_name not in config:
return canteen_not_found(config, canteen_name)
canteen = config[canteen_name]
menu = get_menu_cached(canteen)
return canteen_feed_xml(canteen, menu)
File diff suppressed because it is too large Load Diff
+362
View File
@@ -0,0 +1,362 @@
<?xml version="1.0" encoding="UTF-8"?>
<openmensa version="2.1" xmlns="http://openmensa.org/open-mensa-v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://openmensa.org/open-mensa-v2 http://openmensa.org/open-mensa-v2.xsd">
<canteen>
<name>Mensa Griebnitzsee</name>
<address>August-Bebel-Straße 69, Haus 6</address>
<city>14482 Potsdam</city>
<day date="2018-09-19">
<category name="Angebot 1">
<meal>
<name>Gefüllter Germknödel
mit Vanillesauce und Mohnzucker</name>
<note>Vegetarisch</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
</category>
<category name="Angebot 2">
<meal>
<name>Gebratene Rindfleischstreifen mit Gemüse und Kidneybohnen-Dip, dazu Pommes frites</name>
<note>Rindfleisch</note>
<price role="employee">3.90</price>
<price role="other">3.90</price>
<price role="student">2.00</price>
</meal>
</category>
<category name="Angebot 3">
<meal>
<name>Fangfrisches Seelachsfilet auf Farfalle mit Kirschtomaten, Rucola , dazu Salat</name>
<note>Fisch</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
<category name="Angebot 4">
<meal>
<name>Bunte Gemüsepfanne dazu Bulgur und Blattsalatvariation</name>
<note>Knoblauch</note>
<note>Vegan</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
</day>
<day date="2018-09-20">
<category name="Angebot 1">
<meal>
<name>Eierfrikassee mit buntem Gemüse, dazu Kartoffelpüree</name>
<note>Vegetarisch</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
</category>
<category name="Angebot 2">
<meal>
<name>Schweinsbraten mit süßem Senf und Bratkartoffeln oder bayrischer Kartoffelsalat, dazu Blattsalat</name>
<note>Schweinefleisch</note>
<price role="employee">3.90</price>
<price role="other">3.90</price>
<price role="student">2.00</price>
</meal>
</category>
<category name="Angebot 3">
<meal>
<name>Truthahnsteak Strindberg Art aus Mecklenburg mit jungen Erbsen
und Grillkartoffeln oder frischen Eierknöpfle</name>
<note>Gefluegel</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
<category name="Angebot 4">
<meal>
<name>Falafelbällchen mit Tomatenreis und Ajvar-Dip, dazu Salatvariation mit Oliven</name>
<note>Knoblauch</note>
<note>Vegan</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
</day>
<day date="2018-09-21">
<category name="Angebot 1">
<meal>
<name>Spaghetti Bolognese mit Reibekäse</name>
<note>Schweinefleisch</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
<meal>
<name>Spaghetti mit veganer Tomatensauce mit geschrotetem Buchweizen</name>
<note>Vegan</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
</category>
<category name="Angebot 2">
<meal>
<name>Burger mit Putenfleisch aus Mecklenburg mit Pommes frites</name>
<note>Gefluegel</note>
<price role="employee">3.90</price>
<price role="other">3.90</price>
<price role="student">2.00</price>
</meal>
</category>
<category name="Angebot 3">
<meal>
<name>Forelle Müllerin Art mit Petersilienkartoffeln und Gurkensalat</name>
<note>Fisch</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
<category name="Angebot 4">
<meal>
<name>Kartoffelrösti mit Tomaten und Mozzarella überbacken, dazu Wildkräutersalat</name>
<note>Knoblauch</note>
<note>Vegetarisch</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
</day>
<day date="2018-09-24">
<category name="Angebot 1">
<meal>
<name>Backkartoffel mit Kräuterquark</name>
<note>Vegetarisch</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
<meal>
<name>Backkartoffel mit Soja-Kräuterdip</name>
<note>Knoblauch</note>
<note>Vegan</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
</category>
<category name="Angebot 2">
<meal>
<name>Putenbratwurst aus Mecklenburg mit hausgemachter Currysauce, dazu Kartoffel-Gurkensalat</name>
<note>Gefluegel</note>
<price role="employee">3.90</price>
<price role="other">3.90</price>
<price role="student">2.00</price>
</meal>
<meal>
<name>Vegetarische Bratwurst mit hausgemachter Currysauce, dazu Kartoffel-Gurkensalat</name>
<note>Vegetarisch</note>
<price role="employee">3.90</price>
<price role="other">3.90</price>
<price role="student">2.00</price>
</meal>
</category>
<category name="Angebot 3">
<meal>
<name>Knusperfisch mit Kräutersauce,
dazu Saisongemüse und Wildmischreis
oder Herzoginkartoffeln</name>
<note>Fisch</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
<category name="Angebot 4">
<meal>
<name>Pan Haggerty - mit Cheddar überbackenes Kartoffelgericht, dazu Sellerie-Apfelsalat</name>
<note>Vegetarisch</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
</day>
<day date="2018-09-25">
<category name="Angebot 1">
<meal>
<name>Rührei mit Rahmspinat und Salzkartoffeln</name>
<note>Vegetarisch</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
</category>
<category name="Angebot 2">
<meal>
<name>Hirtenrolle mit Balkangemüse, dazu bunter Nudelreis-Salat</name>
<note>Knoblauch</note>
<note>Schweinefleisch</note>
<price role="employee">3.90</price>
<price role="other">3.90</price>
<price role="student">2.00</price>
</meal>
<meal>
<name>Vegetarische Bratwurst mit hausgemachter Currysauce, dazu Kartoffel-Gurkensalat</name>
<note>Vegetarisch</note>
<price role="employee">3.90</price>
<price role="other">3.90</price>
<price role="student">2.00</price>
</meal>
</category>
<category name="Angebot 3">
<meal>
<name>Fangfrisches Seelachsfilet mit Rahm-Wirsing, dazu Gnocchi oder Langkornreis</name>
<note>Fisch</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
</day>
<day date="2018-09-26">
<category name="Angebot 1">
<meal>
<name>Gebratene Jagdwurst mit Nudeln und Tomatensauce</name>
<note>Schweinefleisch</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
<meal>
<name>Tofusteak mit Nudeln und veganer Tomatensauce</name>
<note>Vegan</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
</category>
<category name="Angebot 2">
<meal>
<name>Geflügelfrikassee mit jungen Erbsen, dazu Langkornreis oder Salzkartoffeln</name>
<note>Alkohol</note>
<note>Gefluegel</note>
<price role="employee">3.90</price>
<price role="other">3.90</price>
<price role="student">2.00</price>
</meal>
</category>
<category name="Angebot 3">
<meal>
<name>Rinder- oder Schweinesteak mit Kräuterbutter und Pfefferbohnen, dazu Pommes frites oder gebratene Drillinge</name>
<note>Rindfleisch</note>
<note>Schweinefleisch</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
<category name="Angebot 4">
<meal>
<name>Beelitzer Dinkel-Nudeln und Tomaten-Sauce mit körnigem Frischkäse, dazu Wildkräutersalat</name>
<note>Knoblauch</note>
<note>Vegetarisch</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
</day>
<day date="2018-09-27">
<category name="Angebot 1">
<meal>
<name>Kartoffelsuppe mit Wiener Würstchen oder Geflügelwiener aus Mecklenburg, dazu Roggenbrot</name>
<note>Rindfleisch</note>
<note>Schweinefleisch</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
<meal>
<name>vegane Kartoffelsuppe mit Räuchertofu und Roggenbrot</name>
<note>Vegetarisch</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
</category>
<category name="Angebot 2">
<meal>
<name>Thaicurry mit Hähnchenfleisch, Paprika und Sprossen, dazu Basmatirei</name>
<note>Gefluegel</note>
<price role="employee">3.90</price>
<price role="other">3.90</price>
<price role="student">2.00</price>
</meal>
</category>
<category name="Angebot 3">
<meal>
<name>Dönerteller mit Kräuter-Sauce, dazu Pommes frites oder Fladenbrot</name>
<note>Rindfleisch</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
<category name="Angebot 4">
<meal>
<name>Makkaroni-Tomaten-Brokkoli-Auflauf, dazu italienische Salatmischung</name>
<note>Vegetarisch</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
</day>
<day date="2018-09-28">
<category name="Angebot 1">
<meal>
<name>Hausgemachte Eierkuchen
mit Zitronen-Vanillequark oder Apfelmus</name>
<note>Vegetarisch</note>
<price role="employee">3.10</price>
<price role="other">3.10</price>
<price role="student">1.40</price>
</meal>
</category>
<category name="Angebot 2">
<meal>
<name>Rauch-Matjestopf
mit Preiselbeeren, dazu Bratkartoffeln
und Gurkensalat mit Sauerrahm</name>
<note>Fisch</note>
<price role="employee">3.90</price>
<price role="other">3.90</price>
<price role="student">2.00</price>
</meal>
</category>
<category name="Angebot 3">
<meal>
<name>Paniertes Schnitzel mit Blumenkohl in Semmelbutter, dazu Petersilienkartoffeln</name>
<note>Schweinefleisch</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
<category name="Angebot 4">
<meal>
<name>Gemüsebratling mit Pesto und buntem Gemüse-Nudelsalat</name>
<note>Knoblauch</note>
<note>Vegan</note>
<price role="employee">4.50</price>
<price role="other">4.50</price>
<price role="student">2.50</price>
</meal>
</category>
</day>
</canteen>
</openmensa>
+36
View File
@@ -0,0 +1,36 @@
# -*- encoding: utf-8 -*-
import io
import json
import os
from stw_potsdam import feed
from stw_potsdam.config import read_canteen_config
def _resource_path(filename):
return os.path.join('tests', 'resources', filename)
def _canteen():
return read_canteen_config()['griebnitzsee']
def _menu():
with open(_resource_path('input.json')) as f:
return json.load(f)
def _expected_feed():
with io.open(_resource_path('output.xml'), encoding='utf-8') as f:
return f.read()
def test_consistency():
canteen = _canteen()
menu = _menu()
actual = feed.render(canteen, menu)
expected = _expected_feed()
assert expected == actual
+30
View File
@@ -0,0 +1,30 @@
# -*- encoding: utf-8 -*-
import os
import pytest
from stw_potsdam import feed
from stw_potsdam.config import read_canteen_config
from stw_potsdam.canteen_api import download_menu
from stw_potsdam.canteen_api import MenuParams
ENV_ENABLED = 'ENABLE_API_QUERY'
CANTEENS = read_canteen_config()
@pytest.fixture(params=CANTEENS.values(), ids=lambda canteen: canteen.name)
def canteen(request):
return request.param
requires_online_api = pytest.mark.skipif(
not bool(os.getenv(ENV_ENABLED)),
reason='Querying the online API is disabled. Turn on by setting env variable %s.' % ENV_ENABLED
)
@requires_online_api
def test_retrieval(canteen):
menu = download_menu(MenuParams(canteen_id=canteen.id, chash=canteen.chash))
feed.render(canteen, menu)