Пример #1
0
    def get_menus(self, text, year, week_number):
        menus = {}
        count = 0
        lines = text.replace("Extraessen", "").splitlines()
        for line in lines:
            if "Montag" in line:
                break

            count += 1

        lines = lines[count:]

        # get rid of Zusatzstoffe and Allergene: everything below the last ***-delimiter is irrelevant
        last_relevant_line = len(lines)
        for index, line in enumerate(lines):
            if "***" in line:
                last_relevant_line = index
        lines = lines[:last_relevant_line]

        days_list = [d for d in
                     re.split(r"(Montag|Dienstag|Mittwoch|Donnerstag|Freitag|Samstag|Sonntag),\s\d{1,2}.\d{1,2}.\d{4}",
                              "\n".join(lines).replace("*", "").strip())
                     if d not in ["", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]]
        if len(days_list) != 7:
            # as the Mediziner Mensa is part of hospital, it should serve food on each day
            return None
        days = {"mon": days_list[0], "tue": days_list[1], "wed": days_list[2], "thu": days_list[3], "fri": days_list[4],
                "sat": days_list[5], "sun": days_list[6]}

        for key in days:
            day_lines = unicodedata.normalize("NFKC", days[key]).splitlines(True)
            soup_str = ""
            mains_str = ""
            for day_line in day_lines:
                soup_str += day_line[:36].strip() + "\n"
                mains_str += day_line[40:100].strip() + "\n"

            soup_str = soup_str.replace("-\n", "").strip().replace("\n", " ")
            soup = self.parse_dish(soup_str)
            dishes = []
            if (soup.name not in ["", "Feiertag"]):
                dishes.append(soup)
            # https://regex101.com/r/MDFu1Z/1
            for dish_str in re.split(r"(\n{2,}|(?<!mit)\n(?=[A-Z]))", mains_str):
                dish_str = dish_str.strip().replace("\n", " ")
                dish = self.parse_dish(dish_str)
                dish.name = dish.name.strip()
                if dish.name not in ["", "Feiertag"]:
                    dishes.append(dish)

            date = self.get_date(year, week_number, self.weekday_positions[key])
            menu = Menu(date, dishes)
            # remove duplicates
            menu.remove_duplicates()
            menus[date] = menu

        return menus
Пример #2
0
    def test_surprise_holiday_first_line_y19w22(self):
        menus_actual = self.ipp_parser.get_menus(self.y19w22_test_menu,
                                                 year=2019,
                                                 week_number=22)

        self.assertEqual(self.y19w22_menu_mon,
                         menus_actual[self.y19w22_date_mon])
        self.assertEqual(self.y19w22_menu_tue,
                         menus_actual[self.y19w22_date_tue])
        self.assertEqual(self.y19w22_menu_wed,
                         menus_actual[self.y19w22_date_wed])
        self.assertEqual(Menu(self.y19w22_date_thu, []),
                         menus_actual[self.y19w22_date_thu])
        self.assertEqual(Menu(self.y19w22_date_fri, []),
                         menus_actual[self.y19w22_date_fri])
Пример #3
0
def get_menu_by_id(id):
    """
    Get a menu record by its id
    :param id: The id to find the record by
    :return: A JSON object representing a menu record along with its associated list of recipe objects
    """
    menu = Menu()
    menu_data = menu.find_by_id(id)

    if not menu_data:
        return jsonify({"error": "No menu with id {} found".format(id)}), 404

    menu_data['recipes'] = menu.recipes

    return jsonify(menu_data)
Пример #4
0
    def get_menus(self, page: html.Element, location: str):
        # initialize empty dictionary
        menus: Dict[date, Menu] = dict()
        # convert passed date to string
        # get all available daily menus
        daily_menus: html.Element = self.__get_daily_menus_as_html(page)

        # iterate through daily menus
        for daily_menu in daily_menus:
            # get html representation of current menu
            menu_html = html.fromstring(html.tostring(daily_menu))
            # get the date of the current menu; some string modifications are necessary
            current_menu_date_str = menu_html.xpath("//strong/text()")[0]
            # parse date
            try:
                current_menu_date: date = util.parse_date(
                    current_menu_date_str)
            except ValueError:
                print(
                    "Warning: Error during parsing date from html page. Problematic date: %s"
                    % current_menu_date_str)
                # continue and parse subsequent menus
                continue
            # parse dishes of current menu
            dishes: List[Dish] = self.__parse_dishes(menu_html, location)
            # create menu object
            menu: Menu = Menu(current_menu_date, dishes)
            # add menu object to dictionary using the date as key
            menus[current_menu_date] = menu

        # return the menu for the requested date; if no menu exists, None is returned
        return menus
Пример #5
0
    def parse_by_date(self, location: str, on_date=date.today()):
        menu_table = self._get_menu(location=location, date=on_date)
        days = list(menu_table.loc[:0].loc[0])[1:]
        dishes = menu_table[0][menu_table[0].apply(lambda x: len(x) > 0)]
        self._ingredient_map = Ingredients(location)

        week_menu = {}
        menu = menu_table.loc[dishes.index]
        daily_dishes = None
        for day_id, day in enumerate(days):
            date_repr = self._parse_date(day, on_date)
            week_menu[date_repr] = Menu(menu_date=date_repr, dishes=[])
            for dish_id, dish_type in enumerate(menu[0]):
                try:
                    if 'täglich' not in dish_type.strip().lower():
                        if len(menu[1 + day_id][1 + dish_id].strip()) == 0:
                            continue
                        week_menu[date_repr].dishes.append(
                            self._parse_dish(
                                location=location,
                                dish_str=menu[1 + day_id][1 + dish_id],
                                dish_type=self._demangle_name(dish_type)))
                    else:
                        if not daily_dishes:
                            daily_dishes = self._parse_daily_dish(
                                location=location,
                                dish_str=menu[1][1 + dish_id])
                        week_menu[date_repr].dishes.extend(daily_dishes)
                except:
                    print(menu.to_string())
                    warn(
                        f"Could not parse dish \"{menu[1+day_id][1+dish_id]}\"."
                    )
                    continue
        return week_menu
Пример #6
0
def get_menu_in_date_range(begin, end):
    """
    Get menus in-between two dates (inclusive)
    :param begin: A string in the format of YYYY-MM-DD specifying the start day (inclusive)
    :param end: A string in the format of YYYY-MM-DD specifying the end day (inclusive)
    :return: A JSON format in the form of
    {"menus": [<list of JSON objects representing a menu record that also contains a list of recipe objects for that menu record>]}
    """
    if not check_date(begin) or not check_date(end):
        return jsonify({"error": "Dates must be in YYYY-MM-DD format"}), 400

    menus = Menu().all(comparisons={"date": ["BETWEEN", [begin, end]]})
    if not menus:
        return jsonify({"error": "No menus between dates {} and {} found".format(begin, end)}), 404

    cursor = g.db.cursor()
    for menu in menus:
        cursor.execute(
            "SELECT *\n"
            "FROM mongoose.recipes\n"
            "WHERE rec_id IN (SELECT recipe_id\n"
            "                 FROM mongoose.serves\n"
            "                 WHERE menu_id = %s)",
            (menu['id'],))
        menu['recipes'] = cursor.fetchall()
    cursor.close()

    return jsonify({"menus": menus})
Пример #7
0
def get_menu_by_date(date):
    """
    Get menus on a specific date
    :param date: A date string in the format YYYY-MM-DD
    :return: A JSON format in the form of
    {"menus": [<list of JSON objects representing a menu record that also contains a list of recipe objects for that menu record>]}
    """
    if not check_date(date):
        return jsonify({"error": "Dates must be in YYYY-MM-DD format"}), 400

    menus = Menu().find_by_attribute("date", date, limit=-1)
    if not menus:
        return jsonify({"error": "No menus for the date {}".format(date)}), 404

    cursor = g.db.cursor()
    for menu in menus:
        cursor.execute(
            "SELECT *\n"
            "FROM mongoose.recipes\n"
            "WHERE rec_id IN (SELECT recipe_id\n"
            "                 FROM mongoose.serves\n"
            "                 WHERE menu_id = %s)",
            (menu['id'],))
        menu['recipes'] = cursor.fetchall()
    cursor.close()

    return jsonify({"menus": menus})
Пример #8
0
def get_menus_by_time_of_day(time_of_day):
    """
    Get all menus for a time of day
    :param time_of_day: A lowercase string of one of the following: ('breakfast', 'lunch', 'dinner')
    :return: A JSON format in the form of
    {"menus": [<list of JSON objects representing a menu record that also contains a list of recipe objects for that menu record>]}
    """
    menus = Menu().find_by_attribute("time_of_day", time_of_day, limit=-1)
    if not menus:
        return jsonify({"error": "No menus with the time of day {} found".format(time_of_day)}), 404

    cursor = g.db.cursor()
    for menu in menus:
        cursor.execute(
            "SELECT *\n"
            "FROM mongoose.recipes\n"
            "WHERE rec_id IN (SELECT recipe_id\n"
            "                 FROM mongoose.serves\n"
            "                 WHERE menu_id = %s)",
            (menu['id'],))
        menu['recipes'] = cursor.fetchall()

    cursor.close()

    return jsonify({"menus": menus})
Пример #9
0
    def test_Should_Add_Week_to_Canteen(self):
        date_mon2 = date(2017, 11, 6)
        date_tue2 = date(2017, 11, 7)
        date_wed2 = date(2017, 11, 8)
        date_thu2 = date(2017, 11, 9)
        date_fri2 = date(2017, 11, 10)
        dish_aktion2 = Dish("Pochiertes Lachsfilet mit Dillsoße dazu Minze-Reis", 6.5, set(["Sl", "Mi"]))
        dish1_mon2 = Dish("Dampfkartoffeln mit Zucchinigemüse", 3.6, set(["Sl"]))
        dish2_mon2 = Dish("Valess-Schnitzel mit Tomaten-Couscous", 4.3, set(["Sl", "Gl", "Ei", "Mi"]))
        dish3_mon2 = Dish("Kasslerpfanne mit frischen Champignons und Spätzle", 4.9, set(["Sl", "Mi"]))
        dish1_tue2 = Dish("Gemüsereispfanne mit geräuchertem Tofu", 3.6, set(["Sl"]))
        dish2_tue2 = Dish("Schweineschnitzel in Karottenpanade mit Rosmarin- Risoleekartoffeln", 5.3, set(["Sl", "Gl", "Ei"]))
        dish1_wed2 = Dish("Spaghetti al Pomodoro", 3.6, set(["Sl", "Gl"]))
        dish2_wed2 = Dish("Krustenbraten vom Schwein mit Kartoffelknödel und Krautsalat", 5.3, set(["Sl", "Gl"]))
        dish1_thu2 = Dish("Red-Thaicurrysuppe mit Gemüse und Kokosmilch", 2.9, set(["Sl"]))
        dish2_thu2 = Dish("Senf-Eier mit Salzkartoffeln", 3.8, set(["Sl", "Sf", "Mi"]))
        dish3_thu2 = Dish("Putengyros mit Zaziki und Tomatenreis", 5.3, set(["Sl", "Mi"]))
        dish1_fri2 = Dish("Spiralnudeln mit Ratatouillegemüse", 3.6, set(["Gl"]))
        dish2_fri2 = Dish("Milchreis mit warmen Sauerkirschen", 3, set(["Mi"]))
        dish3_fri2 = Dish("Lasagne aus Seelachs und Blattspinat", 5.3, set(["Sl", "Gl", "Mi"]))
        menu_mon2 = Menu(date_mon2, [dish_aktion2, dish1_mon2, dish2_mon2, dish3_mon2])
        menu_tue2 = Menu(date_tue2, [dish_aktion2, dish1_tue2, dish2_tue2])
        menu_wed2 = Menu(date_wed2, [dish_aktion2, dish1_wed2, dish2_wed2])
        menu_thu2 = Menu(date_thu2, [dish_aktion2, dish1_thu2, dish2_thu2, dish3_thu2])
        menu_fri2 = Menu(date_fri2, [dish_aktion2, dish1_fri2, dish2_fri2, dish3_fri2])
        week = Week(45, 2017, [menu_mon2, menu_tue2, menu_wed2, menu_thu2, menu_fri2])
        week = {}
        week[date_mon2] = menu_mon2
        week[date_tue2] = menu_tue2
        week[date_wed2] = menu_wed2
        week[date_thu2] = menu_thu2
        week[date_fri2] = menu_fri2
        weeks = Week.to_weeks(week)

        canteen = openmensa.weeksToCanteenFeed(weeks)
        self.assertEqual(canteen.hasMealsFor(date_mon2), True)
        self.assertEqual(canteen.hasMealsFor(date_tue2), True)
        self.assertEqual(canteen.hasMealsFor(date_wed2), True)
        self.assertEqual(canteen.hasMealsFor(date_thu2), True)
        self.assertEqual(canteen.hasMealsFor(date_fri2), True)
        
        canteen_wed2 = canteen._days[date_wed2]['Speiseplan']
        self.assertEqual(canteen_wed2[0], ("Pochiertes Lachsfilet mit Dillsoße dazu Minze-Reis", [], {'other': 650}))
        self.assertEqual(canteen_wed2[1], ("Spaghetti al Pomodoro", [], {'other': 360}))
        self.assertEqual(canteen_wed2[2], ("Krustenbraten vom Schwein mit Kartoffelknödel und Krautsalat", [], {'other': 530}))
Пример #10
0
def get_menu_by_time_of_day_and_date(time_of_day, date):
    """
    Get a menu given its time of day and date
    :param time_of_day: A lowercase string of one of the following: ('breakfast', 'lunch', 'dinner')
    :param date: A date string in the form of YYYY-MM-DD
    :return: A JSON format in the form of
    {"menu": {<A JSON object representing a menu record that also contains a list of recipe objects for that menu record>}}
    """
    if not check_date(date):
        return jsonify({"error": "Dates must be in YYYY-MM-DD format"})

    if time_of_day not in Menu.__columns__['time_of_day']:
        return jsonify({"error": "Time of day must be one of {}".format(Menu.__columns__['time_of_day'])}), 400

    menu = Menu().find_by_attribute("date", date, limit=-1)
    menu = filter(lambda x: x['time_of_day'] == time_of_day, menu)
    if not menu:
        return jsonify({"error": "No menu found for the time of day {} at date {}".format(time_of_day, date)}), 404

    return jsonify({"menu": menu})
Пример #11
0
def get_all_menus():
    """
    Get all menu items in the database
    :return: A JSON format in the form of
    {"menus": [<list of JSON objects representing a menu record that also contains a list of recipe objects for that menu record>]}
    """
    cursor = g.db.cursor()
    menus = Menu().all()

    for menu in menus:
        cursor.execute(
            "SELECT *\n"
            "FROM mongoose.recipes\n"
            "WHERE rec_id IN (SELECT recipe_id\n"
            "                 FROM mongoose.serves\n"
            "                 WHERE menu_id = %s)",
            (menu['id'],))
        menu['recipes'] = cursor.fetchall()
    cursor.close()

    return jsonify({"menus": menus})
Пример #12
0
class MedizinerMensaParserTest(unittest.TestCase):
    mediziner_mensa_parser = MedizinerMensaMenuParser()
    test_menu1 = open(
        'src/test/assets/mediziner-mensa/KW_44_Herbst_4_Mensa_2018.txt',
        'r').read()
    year1 = 2018
    week_number1 = 44

    date_mon1 = date(2018, 10, 29)
    date_tue1 = date(2018, 10, 30)
    date_wed1 = date(2018, 10, 31)
    date_thu1 = date(2018, 11, 1)
    date_fri1 = date(2018, 11, 2)
    date_sat1 = date(2018, 11, 3)
    date_sun1 = date(2018, 11, 4)

    dish1_mon1 = Dish("Spinatcremesuppe", "N/A", set(["Mi", "Gl"]))
    dish2_mon1 = Dish("Gekochtes Ochsenfleisch mit Meerrettich", "N/A",
                      set(["Sw", "Mi", "R", "3", "5"]))
    dish3_mon1 = Dish("Kürbisauflauf", "N/A", set(["1", "2", "Ei", "Mi",
                                                   "Gl"]))
    dish4_mon1 = Dish("Asiatische Gemüse-Puten-Pfanne mit Reisnudeln", 3.8,
                      set(["G", "Se", "Gl", "Fi", "So", "G"]))

    dish1_tue1 = Dish("Selleriecremesuppe", "N/A", set(["Mi", "Gl"]))
    dish2_tue1 = Dish("Oldenburger Grünkohl mit Mettenden", "N/A",
                      set(["Gl", "Mi", "Sf", "2", "3", "4", "S", "8"]))
    dish3_tue1 = Dish("Kaschmir Kohlrabi und Brokkoli", "N/A", set(["Mi"]))
    dish4_tue1 = Dish("Conchiglioni Nudeln mit mit mediterranem Gemüse", 3.15,
                      set(["1", "2", "Ei", "Gl", "Mi"]))

    dish1_wed1 = Dish("Französische Zwiebelsuppe", "N/A", set())
    dish2_wed1 = Dish("Germknödel mit Vanillesoße", "N/A",
                      set(["1", "9", "Ei", "Mi", "Gl"]))
    dish3_wed1 = Dish("Herzhaftes Kartoffelgratin", "N/A",
                      set(["Gl", "Ei", "Mi", "Sl", "1", "2"]))
    dish4_wed1 = Dish("Holzfällersteak mit Bratkartoffeln und Weißkrautsalat",
                      3.7, set(["Sw", "Gl", "S"]))

    dish1_thu1 = Dish("Süßkartoffelcremesuppe", "N/A", set(["Mi", "Gl"]))
    dish2_thu1 = Dish("Hähnchenbrust gegrillt", "N/A", set(["G"]))
    dish3_thu1 = Dish("In Sesamöl gebratenes Wokgemüse", "N/A",
                      set(["2", "Se", "Gl", "So"]))

    dish1_fri1 = Dish("Brokkolicremesuppe", "N/A", set(["Mi", "Gl"]))
    dish2_fri1 = Dish("Forelle \"Müllerin Art \"", "N/A", set(["Gl", "Fi"]))
    dish3_fri1 = Dish("Quarkklößchen", "N/A",
                      set(["Gl", "Ei", "Mi", "Sw", "2", "3", "5"]))
    dish4_fri1 = Dish("Chili con Cous Cous mit Kürbis-Apfel-Salat", 2.15,
                      set(["3", "9", "Sw", "Gl"]))

    dish1_sat1 = Dish("Bratspätzlesuppe", "N/A",
                      set(["Ei", "Sl", "R", "Gl", "S"]))
    dish2_sat1 = Dish("Geflügelpflanzerl", "N/A",
                      set(["Gl", "Ei", "Mi", "So", "G"]))
    dish3_sat1 = Dish("Krauttopf mit einer Vollkornsemmel", "N/A", set(["Gl"]))

    dish1_sun1 = Dish("Käsecremesuppe", "N/A", set(["1", "2", "Mi", "Gl"]))
    dish2_sun1 = Dish("Geschmortes Kalbfleisch", "N/A", set(["K"]))
    dish3_sun1 = Dish("Vegetarische Moussaka", "N/A",
                      set(["1", "2", "Mi", "Gl"]))

    menu_mon1 = Menu(date_mon1,
                     [dish1_mon1, dish2_mon1, dish3_mon1, dish4_mon1])
    menu_tue1 = Menu(date_tue1,
                     [dish1_tue1, dish2_tue1, dish3_tue1, dish4_tue1])
    menu_wed1 = Menu(date_wed1,
                     [dish1_wed1, dish2_wed1, dish3_wed1, dish4_wed1])
    menu_thu1 = Menu(date_thu1, [dish1_thu1, dish2_thu1, dish3_thu1])
    menu_fri1 = Menu(date_fri1,
                     [dish1_fri1, dish2_fri1, dish3_fri1, dish4_fri1])
    menu_sat1 = Menu(date_sat1, [dish1_sat1, dish2_sat1, dish3_sat1])
    menu_sun1 = Menu(date_sun1, [dish1_sun1, dish2_sun1, dish3_sun1])

    test_menu2 = open(
        'src/test/assets/mediziner-mensa/KW_47_Herbst_3_Mensa_2018.txt',
        'r').read()
    year2 = 2018
    week_number2 = 47

    date_mon2 = date(2018, 11, 19)
    date_tue2 = date(2018, 11, 20)
    date_wed2 = date(2018, 11, 21)
    date_thu2 = date(2018, 11, 22)
    date_fri2 = date(2018, 11, 23)
    date_sat2 = date(2018, 11, 24)
    date_sun2 = date(2018, 11, 25)

    dish1_mon2 = Dish("Blumenkohlcremesuppe", "N/A", set(["Gl", "Mi"]))
    dish2_mon2 = Dish("Pfannengyros mit Tzaziki", "N/A", set(["S", "Mi"]))
    dish3_mon2 = Dish("Spaghetti \" Gemüsebolognese \"", "N/A",
                      set(["Sl", "Gl"]))
    dish4_mon2 = Dish(
        "Thai-Curry aus Blumenkohl und Kartoffeln mit Gemüsreis und Salat",
        2.2, set(["Sw", "So", "Gl", "Mi"]))

    dish1_tue2 = Dish("Gelbe Erbsensuppe", "N/A", set(["Gl", "Mi"]))
    dish2_tue2 = Dish("Grüner Bohneneintopf mit Rindfleisch", "N/A",
                      set(["Sl", "R"]))
    dish3_tue2 = Dish("Veggi-Gulasch", "N/A", set(["Sl", "Gl"]))
    dish4_tue2 = Dish(
        "Rotbarschfischfilet in Dillsoße mit Kürbisgemüse und Wacholderreis",
        3.65, set(["Mi", "Gl", "Fi"]))

    dish1_wed2 = Dish("Rinderbrühe \" Gärtnerin \"", "N/A", set(["Sl", "R"]))
    dish2_wed2 = Dish("Schweinegulasch", "N/A", set(["Gl", "S"]))
    dish3_wed2 = Dish("Gemüsekuchen mit Mozzarella überbacken", "N/A",
                      set(["Sl", "Ei", "Gl", "Mi"]))
    dish4_wed2 = Dish("Schinkennudeln mit Tomatensoße, dazu gemischter Salat",
                      2.1, set(["Gl", "Mi", "Sf", "Sw", "2", "3", "8", "G"]))

    dish1_thu2 = Dish("Kürbiscremesuppe", "N/A", set(["Gl", "Mi"]))
    dish2_thu2 = Dish("Rinderhackbraten", "N/A",
                      set(["Gl", "Ei", "Mi", "Sf", "So", "R"]))
    dish3_thu2 = Dish("Dinkel-Kräuterbratling", "N/A", set(["Ei", "Gl", "Mi"]))
    dish4_thu2 = Dish(
        "Pikantes Risotto mit buntem Gemüse und Tomatensalat mit Basilikum",
        2.15, set(["Mi", "1", "2", "Sw"]))

    dish1_fri2 = Dish("Minestrone", "N/A", set(["Sl", "Ei", "Gl"]))
    dish2_fri2 = Dish("Gebratene Hähnchenbrust", "N/A", set(["G"]))
    dish3_fri2 = Dish("Scheiterhaufen mit Apfel-Vanille-Ragout", "N/A",
                      set(["Ei", "Gl", "Mi", "So", "9", "3"]))
    dish4_fri2 = Dish(
        "Paniertes Schnitzel vom Schwein und Pute mit Kartoffelmayosalat und Zitronenecke",
        3.6, set(["Gl", "Ei", "Sf", "4", "3", "G", "S"]))

    dish1_sat2 = Dish("Tomatencremesuppe", "N/A", set(["Gl", "Mi"]))
    dish2_sat2 = Dish("Pichelsteiner Gemüseeintopf mit Rindfleisch", "N/A",
                      set(["Sl", "R"]))
    dish3_sat2 = Dish("Ofenkartoffel mit herzhaftem Gemüseragout", "N/A",
                      set(["Sl", "Gl", "Mi"]))

    dish1_sun2 = Dish("Grießnockerlsuppe", "N/A", set(["Ei", "Gl"]))
    dish2_sun2 = Dish("Glasierter Putenbraten in Kräuterrahmsoße", "N/A",
                      set(["G", "Gl", "Mi"]))
    dish3_sun2 = Dish("Eieromelett", "N/A", set(["Ei", "Gl", "Mi"]))

    menu_mon2 = Menu(date_mon2,
                     [dish1_mon2, dish2_mon2, dish3_mon2, dish4_mon2])
    menu_tue2 = Menu(date_tue2,
                     [dish1_tue2, dish2_tue2, dish3_tue2, dish4_tue2])
    menu_wed2 = Menu(date_wed2,
                     [dish1_wed2, dish2_wed2, dish3_wed2, dish4_wed2])
    menu_thu2 = Menu(date_thu2,
                     [dish1_thu2, dish2_thu2, dish3_thu2, dish4_thu2])
    menu_fri2 = Menu(date_fri2,
                     [dish1_fri2, dish2_fri2, dish3_fri2, dish4_fri2])
    menu_sat2 = Menu(date_sat2, [dish1_sat2, dish2_sat2, dish3_sat2])
    menu_sun2 = Menu(date_sun2, [dish1_sun2, dish2_sun2, dish3_sun2])

    def test_Should_Return_Menu1(self):
        menus_actual1 = self.mediziner_mensa_parser.get_menus(
            self.test_menu1, self.year1, self.week_number1)
        self.assertEqual(7, len(menus_actual1))
        self.assertEqual(self.menu_mon1, menus_actual1[self.date_mon1])
        self.assertEqual(self.menu_tue1, menus_actual1[self.date_tue1])
        self.assertEqual(self.menu_wed1, menus_actual1[self.date_wed1])
        self.assertEqual(self.menu_thu1, menus_actual1[self.date_thu1])
        self.assertEqual(self.menu_fri1, menus_actual1[self.date_fri1])
        self.assertEqual(self.menu_sat1, menus_actual1[self.date_sat1])
        self.assertEqual(self.menu_sun1, menus_actual1[self.date_sun1])

        menus_actual2 = self.mediziner_mensa_parser.get_menus(
            self.test_menu2, self.year2, self.week_number2)
        self.assertEqual(7, len(menus_actual2))
        self.assertEqual(self.menu_mon2, menus_actual2[self.date_mon2])
        self.assertEqual(self.menu_tue2, menus_actual2[self.date_tue2])
        self.assertEqual(self.menu_wed2, menus_actual2[self.date_wed2])
        self.assertEqual(self.menu_thu2, menus_actual2[self.date_thu2])
        self.assertEqual(self.menu_fri2, menus_actual2[self.date_fri2])
        self.assertEqual(self.menu_sat2, menus_actual2[self.date_sat2])
        self.assertEqual(self.menu_sun2, menus_actual2[self.date_sun2])
Пример #13
0
    def get_menus(self, text, year, week_number):
        menus = {}
        lines = text.splitlines()
        count = 0
        # remove headline etc.
        for line in lines:
            if line.replace(" ", "").replace(
                    "\n",
                    "").lower() == "montagdienstagmittwochdonnerstagfreitag":
                break

            count += 1

        lines = lines[count:]
        weekdays = lines[0]

        # The column detection is done through the string "Tagessuppe siehe Aushang" which is at the beginning of
        # every column. However, due to center alignment the column do not begin at the 'T' character and broader
        # text in the column might be left of this character, which then gets truncated. But the gap between the 'T'
        # and the '€' character of the previous column¹ — the real beginning of the current column — is always three,
        # which will be subtracted here. Monday is the second column, so the value should never become negative
        # although it is handled here.
        # ¹or 'e' of "Internationale Küche" if it is the monday column

        # find lines which match the regex
        soup_lines_iter = (x for x in lines if self.split_days_regex.search(x))

        soup_line1 = next(soup_lines_iter)
        soup_line2 = next(soup_lines_iter, '')

        positions1 = [(max(a.start() - 3, 0), a.end()) for a in list(
            re.finditer(self.split_days_regex_soup_one_line, soup_line1))]
        # In the second line there is just 'Aushang' (two lines "Tagessuppe siehe Aushang" or
        # closed days ("Geschlossen", "Feiertag")
        positions2 = [(max(a.start() - 14, 0), a.end() + 3) for a in list(
            re.finditer(self.split_days_regex_soup_two_line, soup_line2))]
        positions3 = [(max(a.start() - 3, 0), a.end()) for a in list(
            re.finditer(self.split_days_regex_closed, soup_line2))]

        if positions2:  # Two lines "Tagessuppe siehe Aushang"
            soup_line_index = lines.index(soup_line2)
        else:
            soup_line_index = lines.index(soup_line1)

        positions = sorted(positions1 + positions2 + positions3)

        if len(positions) != 5:
            warn(
                "IPP PDF parsing of week {} in year {} failed. Only {} of 5 columns detected."
                .format(week_number, year, len(positions)))
            return None

        pos_mon = positions[0][0]
        pos_tue = positions[1][0]
        pos_wed = positions[2][0]
        pos_thu = positions[3][0]
        pos_fri = positions[4][0]

        lines_weekdays = {
            "mon": "",
            "tue": "",
            "wed": "",
            "thu": "",
            "fri": ""
        }
        # it must be lines[3:] instead of lines[2:] or else the menus would start with "Preis ab 0,90€" (from the
        # soups) instead of the first menu, if there is a day where the bistro is closed.
        for line in lines[soup_line_index + 3:]:
            lines_weekdays["mon"] += " " + line[pos_mon:pos_tue].replace(
                "\n", " ")
            lines_weekdays["tue"] += " " + line[pos_tue:pos_wed].replace(
                "\n", " ")
            lines_weekdays["wed"] += " " + line[pos_wed:pos_thu].replace(
                "\n", " ")
            lines_weekdays["thu"] += " " + line[pos_thu:pos_fri].replace(
                "\n", " ")
            lines_weekdays["fri"] += " " + line[pos_fri:].replace("\n", " ")

        for key in lines_weekdays:
            # get rid of two-character umlauts (e.g. SMALL_LETTER_A+COMBINING_DIACRITICAL_MARK_UMLAUT)
            lines_weekdays[key] = unicodedata.normalize(
                "NFKC", lines_weekdays[key])
            # remove multi-whitespaces
            lines_weekdays[key] = ' '.join(lines_weekdays[key].split())
            # get all dish including name and price
            dish_names = re.findall(self.dish_regex, lines_weekdays[key] + " ")
            # get dish prices
            prices = re.findall(self.price_regex, ' '.join(dish_names))
            # convert prices to float
            prices = [
                float(price.replace("€", "").replace(",", ".").strip())
                for price in prices
            ]
            # remove price and commas from dish names
            dish_names = [
                re.sub(self.price_regex, "", dish).strip()
                for dish in dish_names
            ]
            # create list of Dish objects
            dishes = [
                Dish(dish_name, price)
                for (dish_name, price) in list(zip(dish_names, prices))
            ]
            date = self.get_date(year, week_number,
                                 self.weekday_positions[key])
            # create new Menu object and add it to dict
            menu = Menu(date, dishes)
            # remove duplicates
            menu.remove_duplicates()
            menus[date] = menu

        return menus
Пример #14
0
class IPPBistroParserTest(unittest.TestCase):
    ipp_parser = IPPBistroMenuParser()
    test_menu1 = open('src/test/assets/ipp/KW-47_20.11-24.11.2017-1.txt',
                      'r').read()
    year1 = 2017
    week_number1 = 47
    test_menu2 = open('src/test/assets/ipp/KW-48_27.11-01.12.10.2017-3.txt',
                      'r').read()
    year2 = 2017
    week_number2 = 48

    date_mon1 = date(2017, 11, 20)
    date_tue1 = date(2017, 11, 21)
    date_wed1 = date(2017, 11, 22)
    date_thu1 = date(2017, 11, 23)
    date_fri1 = date(2017, 11, 24)
    dish1_mon1 = Dish("Gefüllter Germknödel mit Vanillesauce", 3.5,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish2_mon1 = Dish(
        "Ofengulasch vom Rind mit Kürbis und Pflaumen, dazu Rigatoni", 5.5,
        {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish3_mon1 = Dish(
        "\"Palek Tofu\" Gebratener Tofu mit Spinat, Ingwer, Curry-Sahnesauce und Basmatireis",
        5.2, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish4_mon1 = Dish(
        "Gebratene Hähnchenbrust auf Fenchelgemüse, dazu Kräuterreis und Orangensauce",
        6.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish1_tue1 = Dish(
        "Gebratene Weißkohl-Kartoffelpfanne mit gerösteten Sonnenblumenkernen",
        3.5, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish2_tue1 = Dish("Jägerschnitzel mit Spätzle oder Reis", 4.8,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish3_tue1 = Dish(
        "Vegetarisch gefüllte Tortelli mit leichter Zitronen-Buttersauce und gehobeltem Parmesan",
        4.8, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish4_tue1 = Dish("\"Bami Goreng\" indonesische Bratnudeln mit Gemüse, Huhn, Schweinefleisch und Pilzen, " \
                      "dazu Honig-Chili- Dip", 6.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish1_wed1 = Dish("Erbseneintopf (mit Wienerle 4,20 €)", 3.5,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish2_wed1 = Dish("Hackbraten mit Zigeunersauce und Reis", 4.8,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish3_wed1 = Dish(
        "\"Farfalle Rustico\" mit Champignons, Schinken Tomaten und Peperoni (auf Wunsch mit "
        "Reibekäse)", 4.6, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish4_wed1 = Dish("Rumpsteak mit Balsamico Pilzen und Wedges", 7.9,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish1_thu1 = Dish(
        "Mediterrane Frittata mit Zucchini, Kartoffeln, Paprika, kleiner Salatbeilage und "
        "Joghurt-Limetten Dip", 3.5, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish2_thu1 = Dish(
        "Frischer Bayrischer Schweinenackenbraten vom Brett geschnitten dazu Kartoffel- Gurkensalat",
        4.5, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish3_thu1 = Dish(
        "\"Enchilada Verdura\", überbackene Weizentortilla, gefüllt mit Hähnchenfleisch, Sauerrahm, "
        "Kidneybohnen, Mais, dazu", 5.9,
        {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish4_thu1 = Dish(
        "\"Lamm Palak\" mit Spinat und Curry (mittelscharf), dazu Reis", 6.9,
        {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish1_fri1 = Dish("Nudelpfanne mit Gemüsesauce (auf Wunsch mit Reibekäse)",
                      3.5, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish2_fri1 = Dish("Matjes \"Hausfrauen Art\" mit Salzkartoffeln", 5.2,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish3_fri1 = Dish("Currygeschnetzeltes von der Pute mit Früchten und Reis",
                      4.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish4_fri1 = Dish("Honig-Kassler mit Apfel-Spitzkohl und Kartoffelspalten",
                      6.2, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    menu_mon1 = Menu(date_mon1,
                     [dish1_mon1, dish2_mon1, dish3_mon1, dish4_mon1])
    menu_tue1 = Menu(date_tue1,
                     [dish1_tue1, dish2_tue1, dish3_tue1, dish4_tue1])
    menu_wed1 = Menu(date_wed1,
                     [dish1_wed1, dish2_wed1, dish3_wed1, dish4_wed1])
    menu_thu1 = Menu(date_thu1,
                     [dish1_thu1, dish2_thu1, dish3_thu1, dish4_thu1])
    menu_fri1 = Menu(date_fri1,
                     [dish1_fri1, dish2_fri1, dish3_fri1, dish4_fri1])

    date_mon2 = date(2017, 11, 27)
    date_tue2 = date(2017, 11, 28)
    date_wed2 = date(2017, 11, 29)
    date_thu2 = date(2017, 11, 30)
    date_fri2 = date(2017, 12, 1)
    dish1_mon2 = Dish("Wirsing-Kartoffelauflauf mit Bechamel und Käse", 3.5,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish2_mon2 = Dish("Paprikarahm Geschnetzeltes mit Paprikamix und Nudeln",
                      4.8, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish3_mon2 = Dish(
        "\"Dal Curry\" mit Kartoffeln, Kokosmilch, Ingwer, Koriander, Reis und scharfem Chutney",
        4.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish4_mon2 = Dish(
        "Deftiger Hüttenschmaus, Rinderrostbraten mit Zwiebeln, Semmelknödel und gebratenem Gemüse",
        7.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish1_tue2 = Dish("Herbstliche Gemüse-Reis Pfanne mit pikantem Mango Dip",
                      3.5, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish2_tue2 = Dish("Krautwickerl mit Speck-Zwieblsauce und Püree", 4.5,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish3_tue2 = Dish("Rigatoni mit Rosenkohl und Schnittlauch", 4.6,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish4_tue2 = Dish("Spanferkelrücken mit Knödel und Bayerisch Kraut", 6.8,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish1_wed2 = Dish(
        "Weißwurst Gröst ́l mit Knödel, Lauchzwiebeln, Karotten und Kräuter auf Wunsch mit "
        "Bratenjus", 3.5, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish2_wed2 = Dish("Estragonrahmschnitzel mit Pommes frites oder Reis", 4.6,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish3_wed2 = Dish("Gemüse Lasagne", 4.9,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish4_wed2 = Dish(
        "\"Tandoori Chicken\" mit Auberginen, Tomaten, Zucchini, Zitronenschale Minze und Reis",
        6.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish1_thu2 = Dish("Rote Beete Eintopf mit Kartoffeln, Nudeln und Dill",
                      3.5, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish2_thu2 = Dish(
        "Sauerbraten \"Nepal\" mit weißen Bohnen, getrockneten Tomaten und Pasta",
        5.8, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish3_thu2 = Dish(
        "\"Kaku Chicken\" mit geröstetem Curry, Kokosraspel, Tomaten und Reis",
        6.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish4_thu2 = Dish(
        "Leberkäs Burger special mit Pommes frites und Cole slaw", 4.8,
        {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish1_fri2 = Dish("Exotische Linsen-Spätzle Pfanne", 3.5,
                      {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish2_fri2 = Dish(
        "Seelachsfilet gebacken mit Sardellenmayonnaise und Pommes frites",
        4.6, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish3_fri2 = Dish("Gemüse-Linguini mit Pesto-Rahmsauce und Parmesankäse",
                      4.4, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    dish4_fri2 = Dish(
        "Schweinefilet Medaillons in grüner Pfefferrahmsauce mit Kroketten und karamellisierten "
        "Möhren", 7.2, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})

    menu_mon2 = Menu(date_mon2,
                     [dish1_mon2, dish2_mon2, dish3_mon2, dish4_mon2])
    menu_tue2 = Menu(date_tue2,
                     [dish1_tue2, dish2_tue2, dish3_tue2, dish4_tue2])
    menu_wed2 = Menu(date_wed2,
                     [dish1_wed2, dish2_wed2, dish3_wed2, dish4_wed2])
    menu_thu2 = Menu(date_thu2,
                     [dish1_thu2, dish2_thu2, dish3_thu2, dish4_thu2])
    menu_fri2 = Menu(date_fri2,
                     [dish1_fri2, dish2_fri2, dish3_fri2, dish4_fri2])

    def test_Should_Return_Menu1(self):
        menus_actual1 = self.ipp_parser.get_menus(self.test_menu1, self.year1,
                                                  self.week_number1)
        self.assertEqual(5, len(menus_actual1))
        self.assertEqual(self.menu_mon1, menus_actual1[self.date_mon1])
        self.assertEqual(self.menu_tue1, menus_actual1[self.date_tue1])
        self.assertEqual(self.menu_wed1, menus_actual1[self.date_wed1])
        self.assertEqual(self.menu_thu1, menus_actual1[self.date_thu1])
        self.assertEqual(self.menu_fri1, menus_actual1[self.date_fri1])

    def test_Should_Return_Menu2(self):
        menus_actual2 = self.ipp_parser.get_menus(self.test_menu2, self.year2,
                                                  self.week_number2)
        self.assertEqual(5, len(menus_actual2))
        self.assertEqual(self.menu_mon2, menus_actual2[self.date_mon2])
        self.assertEqual(self.menu_tue2, menus_actual2[self.date_tue2])
        self.assertEqual(self.menu_wed2, menus_actual2[self.date_wed2])
        self.assertEqual(self.menu_thu2, menus_actual2[self.date_thu2])
        self.assertEqual(self.menu_fri2, menus_actual2[self.date_fri2])

    ## Test Cases with holidays

    ## Two holidays (Mon & Tue)

    y18w18_date_mon = date(2018, 4, 30)
    y18w18_date_tue = date(2018, 5, 1)
    y18w18_date_wed = date(2018, 5, 2)
    y18w18_date_thu = date(2018, 5, 3)
    y18w18_date_fri = date(2018, 5, 4)

    y18w18_dishes_wed = [
        Dish("Kirschmichel mit Vanillesauce", 3.5,
             {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish(
            "Fitnessteak vom Grill, dazu Zitrone oder Kräuterbutter, Grilltomate und Ofenkartoffel mit "
            "Sauerrahmdip oder bunter Salatauswahl", 8.2,
            {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish(
            "\"Chana Dal\" Kichererbsen, Kartoffeln, Kokosmilch, Curryblätter und Reis",
            4.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish(
            "Calamari alla Romana, gebackene Tintenfischringe mit Knoblauchmayonnaise und "
            "gemischtem Blattsalat mit Tomate und Gurke", 6.2,
            {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    ]

    y18w18_dishes_thu = [
        Dish(
            "Grenaillekartoffeln mit Apfel-Möhren-Quark, auf Wunsch mit gerösteten Sonnenblumenkernen",
            3.5, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish(
            "Böfflamott, gebeizter Rinderschmorbraten mit Rotwein, dazu Frühlingsgemüse und Semmelknödel",
            6.8, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish("Fussili mit Lauch, Ricotta, Meerrettich und frischem Basilikum",
             4.5, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish(
            "Aus dem Wok Putengeschnetzeltes mit Mangold, Möhren, Frühlings- zwiebeln und Basmatireis",
            6.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    ]

    y18w18_dishes_fri = [
        Dish(
            "Curryreispfanne mit Gemüse, Ananas, Kreuzkümmel, Koriander und Chili-Dip",
            3.5, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish(
            "Zitronen Seelachs auf Paprika-Champignon Gemüse, Petersilien- Kartoffeln und leichter Buttersauce",
            5.90, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish("Paprikarahmgeschnetzeltes mit Hörnchennudeln", 5.2,
             {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish(
            "\"Pasta Arora\" italienische Nudeln mit Tomatensahne, Mozzarella und Basilikum",
            4.5, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    ]

    y18w18_menu_mon = Menu(y18w18_date_mon, set())
    y18w18_menu_tue = Menu(y18w18_date_tue, set())
    y18w18_menu_wed = Menu(y18w18_date_wed, y18w18_dishes_wed)
    y18w18_menu_thu = Menu(y18w18_date_thu, y18w18_dishes_thu)
    y18w18_menu_fri = Menu(y18w18_date_fri, y18w18_dishes_fri)

    y18w18_test_menu = open('src/test/assets/ipp/KW-18_30.04.-04.05.18.txt',
                            'r').read()

    def test_Holiday_Should_Return_Menu_y18w18(self):
        menus_actual = self.ipp_parser.get_menus(self.y18w18_test_menu,
                                                 year=2018,
                                                 week_number=18)
        self.assertEqual(5, len(menus_actual))

        self.assertEqual(self.y18w18_menu_mon,
                         menus_actual[self.y18w18_date_mon])
        self.assertEqual(self.y18w18_menu_tue,
                         menus_actual[self.y18w18_date_tue])
        self.assertEqual(self.y18w18_menu_wed,
                         menus_actual[self.y18w18_date_wed])
        self.assertEqual(self.y18w18_menu_thu,
                         menus_actual[self.y18w18_date_thu])
        self.assertEqual(self.y18w18_menu_fri,
                         menus_actual[self.y18w18_date_fri])

    ## One holiday (Thu)

    y18w19_date_mon = date(2018, 5, 7)
    y18w19_date_tue = date(2018, 5, 8)
    y18w19_date_wed = date(2018, 5, 9)
    y18w19_date_thu = date(2018, 5, 10)
    y18w19_date_fri = date(2018, 5, 11)

    y18w19_dishes_mon = [
        Dish("Gemüse-Schupfnudeln dazu Sauerrahm-Dip", 3.5,
             {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish("Würziger Putenbrustbraten mit Frühlingsgemüse und Kroketten",
             7.2, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish("Gnocchi-Lauch Gratin mit Käse überbacken", 4.8,
             {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish("Schweinefleisch süß-sauer mit Ananas, Paprika, Tomaten und Reis",
             6.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    ]

    y18w19_dishes_tue = [
        Dish("Gebackener Edamer mit Rohkostsalat und Preiselbeeren", 4.9,
             {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish(
            "Köttbullar (Hackfleischbällchen) mit Rahmsauce, Preiselbeeren und Petersilienkartoffeln",
            4.8, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish("Burgunderbraten vom Rind mit Knödel und Blaukraut", 6.2,
             {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish("Quarkknödel auf Erdbeer-Rhabarber Kompott", 3.5,
             {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    ]

    y18w19_dishes_wed = [
        Dish("Italienische Minestrone mit Reis", 3.5,
             {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish("Gebackenes Schweineschnitzel mit Zitrone und Pommes frites", 5.9,
             {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish(
            "\"Vegetarian Vindaloo\" Kartoffeln und Tomaten in Currysauce, dazu Reis und frischer Koriander",
            4.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        # Note the " after the Basilikum is correct since it is part of the PDF
        Dish(
            "Farfalle \"al Tonno\" mit Thunfisch, Kapern, Oliven, Tomaten und Basilikum\"",
            4.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    ]

    y18w19_dishes_fri = [
        Dish("Spaghetti mit Tomatensauce und Reibekäse", 3.5,
             {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish("2 Paar Schweinswürst ́l auf Sauerkraut und Püree", 4.8,
             {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish(
            "\"Chicken Padam Pasanda\" mit Nusssauce, Kokos- flocken und indischen Gewürzen, dazu Basmatireis",
            6.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"}),
        Dish(
            "Kartoffeltasche, gefüllt mit Kräuterfrischkäse auf Paprikagemüse",
            4.9, {"Mi", "Gl", "Sf", "Sl", "Ei", "Se", "4"})
    ]

    y18w19_menu_mon = Menu(y18w19_date_mon, y18w19_dishes_mon)
    y18w19_menu_tue = Menu(y18w19_date_tue, y18w19_dishes_tue)
    y18w19_menu_wed = Menu(y18w19_date_wed, y18w19_dishes_wed)
    y18w19_menu_thu = Menu(y18w19_date_thu, set())
    y18w19_menu_fri = Menu(y18w19_date_fri, y18w19_dishes_fri)

    y18w19_test_menu = open('src/test/assets/ipp/KW-19_07.05.-11.05.18.txt',
                            'r').read()

    def test_Holiday_Should_Return_Menu_y18w19(self):
        menus_actual = self.ipp_parser.get_menus(self.y18w19_test_menu,
                                                 year=2018,
                                                 week_number=19)
        self.assertEqual(5, len(menus_actual))

        self.assertEqual(self.y18w19_menu_mon,
                         menus_actual[self.y18w19_date_mon])
        self.assertEqual(self.y18w19_menu_tue,
                         menus_actual[self.y18w19_date_tue])
        self.assertEqual(self.y18w19_menu_wed,
                         menus_actual[self.y18w19_date_wed])
        self.assertEqual(self.y18w19_menu_thu,
                         menus_actual[self.y18w19_date_thu])
        self.assertEqual(self.y18w19_menu_fri,
                         menus_actual[self.y18w19_date_fri])

    ## "Überraschungsmenü" and "Geschlossen" in first line of table

    y19w22_dishes_mon = [
        Dish("Kohlrabieintopf mit Kartoffeln (mit Wiener 4,50 €)", 3.5,
             {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'}),
        Dish("Pfefferrahmgeschnetzeltes von der Pute mit Reis", 5.9,
             {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'}),
        Dish("Überraschungsmenü", "?€",
             {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'}),
        Dish(
            "Luganer Schweinesteak mit Senf, Schinken, Käse und Tomatenragout gratiniert, dazu Pommes frites",
            6.9, {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'})
    ]
    y19w22_dishes_tue = [
        Dish("Überraschungsmenü", 3.7,
             {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'}),
        Dish("Gnocchi Aurora, dazu Pesto und Grana", 4.8,
             {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'}),
        Dish(
            "Wokgericht Gemüse-Couscous mit mariniertem Harissa-Honig- Hühnchen (leicht scharf)",
            6.9, {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'}),
        Dish(
            "\"Kentucky-fried-Schnitzel\", Schweineschnitzel in Paprika- Oregano-Panade, dazu Pommes frites",
            6.2, {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'})
    ]
    y19w22_dishes_wed = [
        Dish("Puddingmilchreis mit Himbeersauce", 3.5,
             {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'}),
        Dish(
            "Putenschnitzel in Zitronen- Kapernsauce mit Petersilienkartoffeln",
            6.9, {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'}),
        Dish(
            "Penne \"Diabolo\" mit Cabanossi, Peperoni,Paprika, Zucchini, Chilipulver und Mais, dazu Grana",
            4.9, {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'}),
        Dish(
            "\"Battala Curry\", süße Kartoffeln, Erbsen, Kokosmilch, Senfkörner und Reis",
            4.9, {'Sf', 'Mi', 'Sl', 'Ei', '4', 'Se', 'Gl'})
    ]

    y19w22_date_mon = date(2019, 5, 27)
    y19w22_date_tue = date(2019, 5, 28)
    y19w22_date_wed = date(2019, 5, 29)
    y19w22_date_thu = date(2019, 5, 30)
    y19w22_date_fri = date(2019, 5, 30)

    y19w22_menu_mon = Menu(y19w22_date_mon, y19w22_dishes_mon)
    y19w22_menu_tue = Menu(y19w22_date_tue, y19w22_dishes_tue)
    y19w22_menu_wed = Menu(y19w22_date_wed, y19w22_dishes_wed)

    y19w22_test_menu = open('src/test/assets/ipp/KW_22-27.05.-31.05.19.txt',
                            'r').read()

    def test_surprise_holiday_first_line_y19w22(self):
        menus_actual = self.ipp_parser.get_menus(self.y19w22_test_menu,
                                                 year=2019,
                                                 week_number=22)

        self.assertEqual(self.y19w22_menu_mon,
                         menus_actual[self.y19w22_date_mon])
        self.assertEqual(self.y19w22_menu_tue,
                         menus_actual[self.y19w22_date_tue])
        self.assertEqual(self.y19w22_menu_wed,
                         menus_actual[self.y19w22_date_wed])
        self.assertEqual(Menu(self.y19w22_date_thu, []),
                         menus_actual[self.y19w22_date_thu])
        self.assertEqual(Menu(self.y19w22_date_fri, []),
                         menus_actual[self.y19w22_date_fri])
Пример #15
0
class FMIBistroParserTest(unittest.TestCase):
    bistro_parser = FMIBistroMenuParser()
    test_menu1 = open('src/test/assets/fmi/Garching-Speiseplan_KW44_2017.txt',
                      'r').read()
    year1 = 2017
    week_number1 = 44
    test_menu2 = open('src/test/assets/fmi/Garching-Speiseplan_KW45_2017.txt',
                      'r').read()
    year2 = 2017
    week_number2 = 45

    date_mon1 = date(2017, 10, 30)
    date_thu1 = date(2017, 11, 2)
    date_fri1 = date(2017, 11, 3)

    dish_aktion1 = Dish(
        "Tellerfleisch mit Bouillonkartoffeln und Sahnemeerrettich Kaiserschmarrn mit Zwetschenröster",
        3.0, set(["Sl", "Mi"]))
    dish1_mon1 = Dish("Kurkumareis mit Asia Wokgemüse", 3.6, set(["Sl"]))
    dish2_mon1 = Dish(
        "Kartoffel „Cordon Bleu“ mit Frischkäse gefüllt dazu Blattsalate", 4.3,
        set(["Sl", "Ei", "Mi"]))
    dish3_mon1 = Dish(
        "Putenschnitzel natur mit Paprikarahmsoße dazu Ebly Gemüseweizen", 5.3,
        set(["Sl", "Mi"]))
    dish1_thu1 = Dish("Süßkartoffel Gemüsepfanne", 3.6, set(["Sl"]))
    dish2_thu1 = Dish("Gemüse Nudelauflauf", 4.3, set(["Sl", "Gl", "Mi"]))
    dish3_thu1 = Dish("Hähnchenspieß in Kokos Currysoße dazu Früchtereis", 5.3,
                      set(["Sl", "Mi"]))
    dish1_fri1 = Dish("Antipasti Rosmarinkartoffeln", 3.6, set(["Sl"]))
    dish2_fri1 = Dish("Schlemmerfilet auf Antipasti Rosmarinkartoffeln", 4.5,
                      set(["Sl"]))
    dish3_fri1 = Dish("Kaiserschmarrn mit Zwetschenröster", 3,
                      set(["Gl", "Ei", "Mi"]))
    menu_mon1 = Menu(date_mon1,
                     [dish_aktion1, dish1_mon1, dish2_mon1, dish3_mon1])
    menu_thu1 = Menu(date_thu1,
                     [dish_aktion1, dish1_thu1, dish2_thu1, dish3_thu1])
    menu_fri1 = Menu(date_fri1,
                     [dish_aktion1, dish1_fri1, dish2_fri1, dish3_fri1])

    date_mon2 = date(2017, 11, 6)
    date_tue2 = date(2017, 11, 7)
    date_wed2 = date(2017, 11, 8)
    date_thu2 = date(2017, 11, 9)
    date_fri2 = date(2017, 11, 10)
    dish_aktion2 = Dish("Pochiertes Lachsfilet mit Dillsoße dazu Minze-Reis",
                        6.5, set(["Sl", "Mi"]))
    dish1_mon2 = Dish("Dampfkartoffeln mit Zucchinigemüse", 3.6, set(["Sl"]))
    dish2_mon2 = Dish("Valess-Schnitzel mit Tomaten-Couscous", 4.3,
                      set(["Sl", "Gl", "Ei", "Mi"]))
    dish3_mon2 = Dish("Kasslerpfanne mit frischen Champignons und Spätzle",
                      4.9, set(["Sl", "Mi"]))
    dish1_tue2 = Dish("Gemüsereispfanne mit geräuchertem Tofu", 3.6,
                      set(["Sl"]))
    dish2_tue2 = Dish(
        "Schweineschnitzel in Karottenpanade mit Rosmarin- Risoleekartoffeln",
        5.3, set(["Sl", "Gl", "Ei"]))
    dish1_wed2 = Dish("Spaghetti al Pomodoro", 3.6, set(["Sl", "Gl"]))
    dish2_wed2 = Dish(
        "Krustenbraten vom Schwein mit Kartoffelknödel und Krautsalat", 5.3,
        set(["Sl", "Gl"]))
    dish1_thu2 = Dish("Red-Thaicurrysuppe mit Gemüse und Kokosmilch", 2.9,
                      set(["Sl"]))
    dish2_thu2 = Dish("Senf-Eier mit Salzkartoffeln", 3.8,
                      set(["Sl", "Sf", "Mi"]))
    dish3_thu2 = Dish("Putengyros mit Zaziki und Tomatenreis", 5.3,
                      set(["Sl", "Mi"]))
    dish1_fri2 = Dish("Spiralnudeln mit Ratatouillegemüse", 3.6, set(["Gl"]))
    dish2_fri2 = Dish("Milchreis mit warmen Sauerkirschen", 3, set(["Mi"]))
    dish3_fri2 = Dish("Lasagne aus Seelachs und Blattspinat", 5.3,
                      set(["Sl", "Gl", "Mi"]))
    menu_mon2 = Menu(date_mon2,
                     [dish_aktion2, dish1_mon2, dish2_mon2, dish3_mon2])
    menu_tue2 = Menu(date_tue2, [dish_aktion2, dish1_tue2, dish2_tue2])
    menu_wed2 = Menu(date_wed2, [dish_aktion2, dish1_wed2, dish2_wed2])
    menu_thu2 = Menu(date_thu2,
                     [dish_aktion2, dish1_thu2, dish2_thu2, dish3_thu2])
    menu_fri2 = Menu(date_fri2,
                     [dish_aktion2, dish1_fri2, dish2_fri2, dish3_fri2])

    def test_Should_Return_Menu(self):
        menus_actual1 = self.bistro_parser.get_menus(self.test_menu1,
                                                     self.year1,
                                                     self.week_number1)
        menus_actual2 = self.bistro_parser.get_menus(self.test_menu2,
                                                     self.year2,
                                                     self.week_number2)

        self.assertEqual(3, len(menus_actual1))
        self.assertEqual(self.menu_mon1, menus_actual1[self.date_mon1])
        self.assertEqual(self.menu_thu1, menus_actual1[self.date_thu1])
        self.assertEqual(self.menu_fri1, menus_actual1[self.date_fri1])

        self.assertEqual(5, len(menus_actual2))
        self.assertEqual(self.menu_mon2, menus_actual2[self.date_mon2])
        self.assertEqual(self.menu_tue2, menus_actual2[self.date_tue2])
        self.assertEqual(self.menu_wed2, menus_actual2[self.date_wed2])
        self.assertEqual(self.menu_thu2, menus_actual2[self.date_thu2])
        self.assertEqual(self.menu_fri2, menus_actual2[self.date_fri2])
Пример #16
0
class StudentenwerkMenuParserTest(unittest.TestCase):
    studentenwerk_menu_parser = StudentenwerkMenuParser()

    menu_html_garching = html.fromstring(
        open("src/test/assets/speiseplan_garching.html").read())
    menu_html_arcisstrasse = html.fromstring(
        open("src/test/assets/speiseplan_arcisstrasse.html").read())
    menu_html_großhadern = html.fromstring(
        open("src/test/assets/speiseplan_großhadern.html").read())
    menu_html_wrong_date_format = html.fromstring(
        open("src/test/assets/speiseplan_garching_wrong_date_format.html").
        read())

    menu1_date = date(2017, 3, 27)
    menu2_date = date(2017, 4, 3)
    menu3_date = date(2017, 4, 4)

    # dishes in Garching
    dish1_1_garching = Dish("Kartoffelgulasch mit Paprika", 1, set())
    dish1_2_garching = Dish("Hackfleischbällchen mit Champignonrahmsauce", 1.9,
                            set(["R", "S", "Ei", "Gl", "GlW", "Kn", "Mi"]))
    dish1_3_garching = Dish(
        "Seelachsfilet (MSC) im Sesammantel mit Remouladensauce", 2.4,
        set(["1", "2", "3", "9", "Ei", "Fi", "Gl", "GlW", "Mi", "Se", "Sf"]))
    dish1_4_garching = Dish(
        "Gebackene Calamari-Ringe mit Remouladensauce", 2.6,
        set(["1", "2", "3", "9", "Ei", "Gl", "GlW", "Mi", "Sf", "Wt"]))

    dish2_1_garching = Dish("Kartoffeleintopf mit Majoran", 1, set(["Sl"]))
    dish2_2_garching = Dish("Gulasch vom Schwein", 1.9,
                            set(["S", "Gl", "GlG", "GlW", "Kn", "Mi"]))
    dish2_3_garching = Dish("Paniertes Hähnchenschnitzel", 2.4,
                            set(["Gl", "GlW", "GlG", "Kn", "Mi", "Sl"]))

    menu1_garching = Menu(menu1_date, [
        dish1_1_garching, dish1_2_garching, dish1_3_garching, dish1_4_garching
    ])
    menu2_garching = Menu(
        menu2_date, [dish2_1_garching, dish2_2_garching, dish2_3_garching])

    # dishes in Arcisstrasse
    dish1_1_arcisstrasse = Dish("Kartoffelgulasch mit Paprika", 1, set())
    dish1_2_arcisstrasse = Dish("Hackfleischbällchen mit Champignonrahmsauce",
                                1.55,
                                set(["R", "S", "Ei", "Gl", "GlW", "Kn", "Mi"]))
    dish1_3_arcisstrasse = Dish(
        "Hackfleischbällchen mit Champignonrahmsauce (2)", 1.9,
        set(["R", "S", "Ei", "Gl", "GlW", "Kn", "Mi"]))
    dish1_4_arcisstrasse = Dish("Pasta Pomodori", 1.9, set(["Gl", "GlW",
                                                            "Kn"]))
    dish1_5_arcisstrasse = Dish(
        "Gebackene Calamari-Ringe mit Zitronen-Knoblauch-Dip", 2.6,
        set(["1", "2", "3", "9", "Ei", "Gl", "GlW", "Kn", "Mi", "Sf", "Wt"]))
    dish1_6_arcisstrasse = Dish(
        "Seelachsfilet (MSC) im Sesammantel mit Zitronen-Knoblauch-Dip", 2.6,
        set(["1", "3", "9", "Ei", "Fi", "Gl", "GlW", "Kn", "Mi", "Se", "Sf"]))
    dish1_7_arcisstrasse = Dish("Pasta Pomodori (2)", "0.68€ / 100g",
                                set(["Gl", "GlW", "Kn"]))
    dish1_8_arcisstrasse = Dish("Kartoffelgulasch mit Paprika (2)",
                                "0.68€ / 100g", set())
    dish1_9_arcisstrasse = Dish("Pasta mit Sojabolognese", "0.68€ / 100g",
                                set(["Sl", "So"]))
    menu1_arcisstrasse = Menu(menu1_date, [
        dish1_1_arcisstrasse, dish1_2_arcisstrasse, dish1_3_arcisstrasse,
        dish1_4_arcisstrasse, dish1_5_arcisstrasse, dish1_6_arcisstrasse,
        dish1_7_arcisstrasse, dish1_8_arcisstrasse, dish1_9_arcisstrasse
    ])

    # dishes in Großhadern
    dish1_1_großhadern = Dish("Pasta-Gemüse-Auflauf mit Tomatensauce", 1.9,
                              set(["1", "Ei", "Gl", "GlW", "Kn", "Mi"]))
    dish1_2_großhadern = Dish(
        "Rinderroulade nach Hausfrauenart mit Senf-Gemüse-Sauce", 3,
        set([
            "R", "S", "2", "3", "99", "Gl", "GlG", "GlW", "Kn", "Mi", "Sf",
            "Sl", "Sw"
        ]))
    menu1_großhadern = Menu(menu3_date,
                            [dish1_1_großhadern, dish1_2_großhadern])

    def test_Should_ReturnMenu_When_PassedDateIsCorrect(self):
        self.assertEqual(
            self.menu1_garching,
            self.studentenwerk_menu_parser.get_menus(
                self.menu_html_garching, "mensa-garching")[self.menu1_date])
        self.assertEqual(
            self.menu2_garching,
            self.studentenwerk_menu_parser.get_menus(
                self.menu_html_garching, "mensa-garching")[self.menu2_date])

        self.assertEqual(
            self.menu1_arcisstrasse,
            self.studentenwerk_menu_parser.get_menus(
                self.menu_html_arcisstrasse,
                "mensa-arcisstrasse")[self.menu1_date])

        self.assertEqual(
            self.menu1_großhadern,
            self.studentenwerk_menu_parser.get_menus(
                self.menu_html_großhadern,
                "stubistro-grosshadern")[self.menu3_date])

    def test_Should_IgnoreDay_When_DateOfTheDayIsInAWrongFormat(self):
        self.assertEqual(
            22,
            len(
                self.studentenwerk_menu_parser.get_menus(
                    self.menu_html_wrong_date_format, "mensa-garching")))

    def test_Should_ReturnWeeks_When_ConvertingMenuToWeekObjects(self):
        menus = self.studentenwerk_menu_parser.get_menus(
            self.menu_html_garching, "mensa-garching")
        weeks_actual = Week.to_weeks(menus)
        length_weeks_actual = len(weeks_actual)

        self.assertEqual(5, length_weeks_actual)
        for calendar_week in weeks_actual:
            week = weeks_actual[calendar_week]
            week_length = len(week.days)
            # calendar weeks 15 and 16 have one day less, because of a holiday
            if calendar_week == 15 or calendar_week == 16:
                self.assertEqual(4, week_length)
            else:
                self.assertEqual(5, week_length)

    def order_json_objects(self, obj):
        """
        Recusively orders all elemts in a Json object.
        Source: https://stackoverflow.com/questions/25851183/how-to-compare-two-json-objects-with-the-same-elements-in-a-different-order-equa
        """
        if isinstance(obj, dict):
            return sorted(
                (k, self.order_json_objects(v)) for k, v in obj.items())
        if isinstance(obj, list):
            return sorted(self.order_json_objects(x) for x in obj)
        else:
            return obj

    def test_Should_ConvertWeekToJSON(self):
        with open('src/test/assets/speiseplan_garching_kw2017-13.json'
                  ) as data_file:
            week_2017_13 = json.load(data_file)
        with open('src/test/assets/speiseplan_garching_kw2017-14.json'
                  ) as data_file:
            week_2017_14 = json.load(data_file)
        with open('src/test/assets/speiseplan_garching_kw2017-15.json'
                  ) as data_file:
            week_2017_15 = json.load(data_file)
        with open('src/test/assets/speiseplan_garching_kw2017-16.json'
                  ) as data_file:
            week_2017_16 = json.load(data_file)
        with open('src/test/assets/speiseplan_garching_kw2017-17.json'
                  ) as data_file:
            week_2017_17 = json.load(data_file)

        menus = self.studentenwerk_menu_parser.get_menus(
            self.menu_html_garching, "mensa-garching")
        weeks = Week.to_weeks(menus)
        week_2017_13_actual = json.loads(weeks[13].to_json())
        week_2017_14_actual = json.loads(weeks[14].to_json())
        week_2017_15_actual = json.loads(weeks[15].to_json())
        week_2017_16_actual = json.loads(weeks[16].to_json())
        week_2017_17_actual = json.loads(weeks[17].to_json())

        a = self.order_json_objects(week_2017_13_actual)
        b = self.order_json_objects(week_2017_13)

        self.assertEqual(self.order_json_objects(week_2017_13_actual),
                         self.order_json_objects(week_2017_13))
        self.assertEqual(self.order_json_objects(week_2017_14_actual),
                         self.order_json_objects(week_2017_14))
        self.assertEqual(self.order_json_objects(week_2017_15_actual),
                         self.order_json_objects(week_2017_15))
        self.assertEqual(self.order_json_objects(week_2017_16_actual),
                         self.order_json_objects(week_2017_16))
        self.assertEqual(self.order_json_objects(week_2017_17_actual),
                         self.order_json_objects(week_2017_17))

    def test_Should_CreateCorrectDirectoriesAndJSONFiles(self):
        # parse menu
        menus = self.studentenwerk_menu_parser.get_menus(
            self.menu_html_garching, "mensa-garching")
        # get weeks
        weeks = Week.to_weeks(menus)

        # create temp dir for testing
        with tempfile.TemporaryDirectory() as temp_dir:
            # store output in the tempdir
            # location can be an empty string because combination won't get tested (combine_dishes is False) here
            main.jsonify(weeks, temp_dir, "", False)

            # check if two directories are created (one for 2016 and 2017)
            created_dirs = [
                name for name in os.listdir(temp_dir)
                if os.path.isdir(os.path.join(temp_dir, name))
            ]
            created_dirs.sort()
            self.assertEqual(1, len(created_dirs))
            self.assertEqual("2017", created_dirs[0])

            # check if the created directories contain the JSON files
            dir_2017 = "%s/2017" % temp_dir
            files_in_2017 = [
                name for name in os.listdir(dir_2017)
                if os.path.isfile(os.path.join(dir_2017, name))
            ]
            files_in_2017.sort()
            self.assertEqual(
                ["13.json", "14.json", "15.json", "16.json", "17.json"],
                files_in_2017)
Пример #17
0
class StudentenwerkMenuParserTest(unittest.TestCase):
    studentenwerk_menu_parser = StudentenwerkMenuParser()

    menu_html_garching = html.fromstring(
        open("src/test/assets/speiseplan_garching.html").read())
    menu_html_arcisstrasse = html.fromstring(
        open("src/test/assets/speiseplan_arcisstrasse.html").read())
    menu_html_großhadern = html.fromstring(
        open("src/test/assets/speiseplan_großhadern.html").read())
    menu_html_wrong_date_format = html.fromstring(
        open("src/test/assets/speiseplan_garching_wrong_date_format.html").
        read())

    menu1_date = date(2017, 3, 27)
    menu2_date = date(2017, 4, 3)
    menu3_date = date(2017, 4, 4)

    # dishes in Garching
    dish1_1_garching = Dish("Kartoffelgulasch mit Paprika", 1)
    dish1_2_garching = Dish("Hackfleischbällchen mit Champignonrahmsauce", 1.9)
    dish1_3_garching = Dish(
        "Seelachsfilet (MSC) im Sesammantel mit Remouladensauce", 2.4)
    dish1_4_garching = Dish("Gebackene Calamari-Ringe mit Remouladensauce",
                            2.6)

    dish2_1_garching = Dish("Kartoffeleintopf mit Majoran", 1)
    dish2_2_garching = Dish("Gulasch vom Schwein", 1.9)
    dish2_3_garching = Dish("Paniertes Hähnchenschnitzel", 2.4)

    menu1_garching = Menu(menu1_date, [
        dish1_1_garching, dish1_2_garching, dish1_3_garching, dish1_4_garching
    ])
    menu2_garching = Menu(
        menu2_date, [dish2_1_garching, dish2_2_garching, dish2_3_garching])

    # dishes in Arcisstrasse
    dish1_1_arcisstrasse = Dish("Kartoffelgulasch mit Paprika", 1)
    dish1_2_arcisstrasse = Dish("Hackfleischbällchen mit Champignonrahmsauce",
                                1.55)
    dish1_3_arcisstrasse = Dish(
        "Hackfleischbällchen mit Champignonrahmsauce (2)", 1.9)
    dish1_4_arcisstrasse = Dish("Pasta Pomodori", 1.9)
    dish1_5_arcisstrasse = Dish(
        "Gebackene Calamari-Ringe mit Zitronen-Knoblauch-Dip", 2.6)
    dish1_6_arcisstrasse = Dish(
        "Seelachsfilet (MSC) im Sesammantel mit Zitronen-Knoblauch-Dip", 2.6)
    dish1_7_arcisstrasse = Dish("Pasta Pomodori (2)", "0.68€ / 100g")
    dish1_8_arcisstrasse = Dish("Kartoffelgulasch mit Paprika (2)",
                                "0.68€ / 100g")
    dish1_9_arcisstrasse = Dish("Pasta mit Sojabolognese", "0.68€ / 100g")
    menu1_arcisstrasse = Menu(menu1_date, [
        dish1_1_arcisstrasse, dish1_2_arcisstrasse, dish1_3_arcisstrasse,
        dish1_4_arcisstrasse, dish1_5_arcisstrasse, dish1_6_arcisstrasse,
        dish1_7_arcisstrasse, dish1_8_arcisstrasse, dish1_9_arcisstrasse
    ])

    # dishes in Großhadern
    dish1_1_großhadern = Dish("Pasta-Gemüse-Auflauf mit Tomatensauce", 1.9)
    dish1_2_großhadern = Dish(
        "Rinderroulade nach Hausfrauenart mit Senf-Gemüse-Sauce", 3)
    menu1_großhadern = Menu(menu3_date,
                            [dish1_1_großhadern, dish1_2_großhadern])

    def test_Should_ReturnMenu_When_PassedDateIsCorrect(self):
        self.assertEqual(
            self.menu1_garching,
            self.studentenwerk_menu_parser.get_menus(
                self.menu_html_garching)[self.menu1_date])
        self.assertEqual(
            self.menu2_garching,
            self.studentenwerk_menu_parser.get_menus(
                self.menu_html_garching)[self.menu2_date])

        self.assertEqual(
            self.menu1_arcisstrasse,
            self.studentenwerk_menu_parser.get_menus(
                self.menu_html_arcisstrasse)[self.menu1_date])

        self.assertEqual(
            self.menu1_großhadern,
            self.studentenwerk_menu_parser.get_menus(
                self.menu_html_großhadern)[self.menu3_date])

    def test_Should_IgnoreDay_When_DateOfTheDayIsInAWrongFormat(self):
        self.assertEqual(
            22,
            len(
                self.studentenwerk_menu_parser.get_menus(
                    self.menu_html_wrong_date_format)))

    def test_Should_ReturnWeeks_When_ConvertingMenuToWeekObjects(self):
        menus = self.studentenwerk_menu_parser.get_menus(
            self.menu_html_garching)
        weeks_actual = Week.to_weeks(menus)
        length_weeks_actual = len(weeks_actual)

        self.assertEqual(5, length_weeks_actual)
        for calendar_week in weeks_actual:
            week = weeks_actual[calendar_week]
            week_length = len(week.days)
            # calendar weeks 15 and 16 have one day less, because of a holiday
            if calendar_week == 15 or calendar_week == 16:
                self.assertEqual(4, week_length)
            else:
                self.assertEqual(5, week_length)

    def test_Should_ConvertWeekToJSON(self):
        with open('src/test/assets/speiseplan_garching_kw2017-13.json'
                  ) as data_file:
            week_2017_13 = json.load(data_file)
        with open('src/test/assets/speiseplan_garching_kw2017-14.json'
                  ) as data_file:
            week_2017_14 = json.load(data_file)
        with open('src/test/assets/speiseplan_garching_kw2017-15.json'
                  ) as data_file:
            week_2017_15 = json.load(data_file)
        with open('src/test/assets/speiseplan_garching_kw2017-16.json'
                  ) as data_file:
            week_2017_16 = json.load(data_file)
        with open('src/test/assets/speiseplan_garching_kw2017-17.json'
                  ) as data_file:
            week_2017_17 = json.load(data_file)

        menus = self.studentenwerk_menu_parser.get_menus(
            self.menu_html_garching)
        weeks = Week.to_weeks(menus)
        week_2017_13_actual = json.loads(weeks[13].to_json())
        week_2017_14_actual = json.loads(weeks[14].to_json())
        week_2017_15_actual = json.loads(weeks[15].to_json())
        week_2017_16_actual = json.loads(weeks[16].to_json())
        week_2017_17_actual = json.loads(weeks[17].to_json())

        self.assertEqual(sorted(week_2017_13_actual.items()),
                         sorted(week_2017_13.items()))
        self.assertEqual(sorted(week_2017_14_actual.items()),
                         sorted(week_2017_14.items()))
        self.assertEqual(sorted(week_2017_15_actual.items()),
                         sorted(week_2017_15.items()))
        self.assertEqual(sorted(week_2017_16_actual.items()),
                         sorted(week_2017_16.items()))
        self.assertEqual(sorted(week_2017_17_actual.items()),
                         sorted(week_2017_17.items()))

    def test_Should_CreateCorrectDirectoriesAndJSONFiles(self):
        # parse menu
        menus = self.studentenwerk_menu_parser.get_menus(
            self.menu_html_garching)
        # get weeks
        weeks = Week.to_weeks(menus)

        # create temp dir for testing
        with tempfile.TemporaryDirectory() as temp_dir:
            # store output in the tempdir
            # location can be an empty string because combination won't get tested (combine_dishes is False) here
            main.jsonify(weeks, temp_dir, "", False)

            # check if two directories are created (one for 2016 and 2017)
            created_dirs = [
                name for name in os.listdir(temp_dir)
                if os.path.isdir(os.path.join(temp_dir, name))
            ]
            created_dirs.sort()
            self.assertEqual(1, len(created_dirs))
            self.assertEqual("2017", created_dirs[0])

            # check if the created directories contain the JSON files
            dir_2017 = "%s/2017" % temp_dir
            files_in_2017 = [
                name for name in os.listdir(dir_2017)
                if os.path.isfile(os.path.join(dir_2017, name))
            ]
            files_in_2017.sort()
            self.assertEqual(
                ["13.json", "14.json", "15.json", "16.json", "17.json"],
                files_in_2017)
Пример #18
0
    def get_menus(self, text, year, week_number):
        menus = {}
        lines = text.splitlines()
        count = 0
        # remove headline etc.
        for line in lines:
            if line.replace(" ", "").replace(
                    "\n",
                    "").lower() == "montagdienstagmittwochdonnerstagfreitag":
                break

            count += 1

        lines = lines[count:]
        # we assume that the weeksdays are now all in the first line
        pos_mon = lines[0].find("Montag")
        pos_tue = lines[0].find("Dienstag")
        pos_wed = lines[0].find("Mittwoch")
        pos_thu = lines[0].find("Donnerstag")
        pos_fri = lines[0].find("Freitag")

        # The text is formatted as table using whitespaces. Hence, we need to get those parts of each line that refer
        #  to the respective week day
        lines_weekdays = {
            "mon": "",
            "tue": "",
            "wed": "",
            "thu": "",
            "fri": ""
        }
        for line in lines:
            lines_weekdays["mon"] += " " + line[pos_mon:pos_tue].replace(
                "\n", " ").replace("Montag", "")
            lines_weekdays["tue"] += " " + line[pos_tue:pos_wed].replace(
                "\n", " ").replace("Dienstag", "")
            lines_weekdays["wed"] += " " + line[pos_wed:pos_thu].replace(
                "\n", " ").replace("Mittwoch", "")
            lines_weekdays["thu"] += " " + line[pos_thu:pos_fri].replace(
                "\n", " ").replace("Donnerstag", "")
            lines_weekdays["fri"] += " " + line[pos_fri:].replace(
                "\n", " ").replace("Freitag", "")

        # currently, up to 5 dishes are on the menu
        num_dishes = 5
        line_aktion = []
        if year < 2018:
            # in older versions of the FMI Bistro menu, the Aktionsgericht was the same for the whole week
            num_dishes = 3
            line_aktion = [s for s in lines if "Aktion" in s]
            if len(line_aktion) == 1:
                line_aktion_pos = lines.index(line_aktion[0]) - 2
                aktionsgericht = ' '.join(
                    lines[line_aktion_pos:line_aktion_pos + 3])
                aktionsgericht = aktionsgericht \
                    .replace("Montag – Freitag", "") \
                    .replace("Tagessuppe täglich wechselndes Angebot", "") \
                    .replace("ab € 1,00", "") \
                    .replace("Aktion", "")
                num_dishes += aktionsgericht.count('€')
                for key in lines_weekdays:
                    lines_weekdays[
                        key] = aktionsgericht + ", " + lines_weekdays[key]

        # Process menus for each day
        for key in lines_weekdays:
            # stop parsing day when bistro is closed at that day
            if "geschlossen" in lines_weekdays[key].lower():
                continue

            # extract all allergens
            dish_allergens = []
            for x in re.findall(self.allergens_regex, lines_weekdays[key]):
                if len(x) > 0:
                    dish_allergens.append(
                        re.sub(r"((Allergene:)|\s|\n)*", "", x[0]))
                else:
                    dish_allergens.append("")
            lines_weekdays[key] = re.sub(self.allergens_regex, "",
                                         lines_weekdays[key])
            # get rid of two-character umlauts (e.g. SMALL_LETTER_A+COMBINING_DIACRITICAL_MARK_UMLAUT)
            lines_weekdays[key] = unicodedata.normalize(
                "NFKC", lines_weekdays[key])
            # remove multi-whitespaces
            lines_weekdays[key] = ' '.join(lines_weekdays[key].split())

            # remove no allergens indicator
            lines_weekdays[key] = lines_weekdays[key].replace("./.", "")
            # get all dish including name and price
            dish_names = re.findall(self.dish_regex, lines_weekdays[key])
            # get dish prices
            prices = re.findall(self.price_regex, ' '.join(dish_names))
            # convert prices to float
            prices = [
                Prices(
                    Price(
                        float(
                            price.replace("€", "").replace(",", ".").strip())))
                for price in prices
            ]
            # remove price and commas from dish names
            dish_names = [
                re.sub(self.price_regex, "", dish).replace(",", "").strip()
                for dish in dish_names
            ]
            # create list of Dish objects; only take first 3/4 as the following dishes are corrupt and not necessary
            dishes = []
            for (dish_name, price,
                 dish_allergen) in list(zip(dish_names, prices,
                                            dish_allergens)):
                # filter empty dishes
                if dish_name:
                    ingredients = Ingredients("fmi-bistro")
                    ingredients.parse_ingredients(dish_allergen)
                    dishes.append(
                        Dish(dish_name, price, ingredients.ingredient_set,
                             "Tagesgericht"))
            dishes = dishes[:num_dishes]
            date = self.get_date(year, week_number,
                                 self.weekday_positions[key])
            # create new Menu object and add it to dict
            menu = Menu(date, dishes)
            # remove duplicates
            menu.remove_duplicates()
            menus[date] = menu

        return menus
Пример #19
0
def menu_post():
    """
    Take in a JSON object in the form of
    {
        "menus":
        [
            {
                "id": 1,
                "time_of_day": <one of ('breakfast', 'lunch', 'dinner')>,
                "date": <date string in the format YYYY-MM-DD>,
                "recipes": [a list of numeric (integer) ids representing the ids of recipes to associate to this menu]
            }, ...
        ]
    }

    Where for each entry in "menu" if there is an "id" attribute,
    it is assumed that we are updating an existing menu (because we wouldn't have the id otherwise),
    and the values given will update the record and its ingredients links in the database.

    Otherwise, if there is no "id" for an object, the system will assume the values
    given are for a new record in the database and will create a new record.

    :return: A JSON object of {"menu":[<list of JSON Objects corresponding to menus updated or created in the system]}
    """
    if not request.json or len(request.json) == 0:
        return jsonify({"error": "No JSON supplied"}), 400

    id_col = Menu.__keys__[0]
    menu = Menu()
    ret_val = []
    if not request.json.get('menus', None):
        return jsonify({"error": "Invalid schema"}), 400
    for m in request.json['menus']:
        menu_id = m.get(id_col, None)
        # check for data validity
        # Enforce a datetime format
        if m.get('date', None) and not check_date(m['date']):
            return jsonify({"error": "{} is not a valid date".format(m['date'])}), 400
        # Enforce enums
        if m.get('time_of_day', None):
            if m['time_of_day'] not in Menu.__columns__['time_of_day']:
                return jsonify({"error": "{} is not a valid time of day".format(m['time_of_day'])}), 400

        if menu_id:
            menu.find_by_id(menu_id)
            menu.update(**m)
            menu.flush()
        else:
            menu.create(**m)
        if m.get('recipes', None) is not None:
            try:
                menu.recipes = m['recipes']
            except TypeError:
                return jsonify(
                    {"error": "Invalid data. The recipes attribute must be a list of numeric recipe ids"}), 400

        ret_val.append(deepcopy(menu.data))

    return jsonify({"menus": ret_val})
Пример #20
0
    def get_menus(self, text, year, week_number):
        menus = {}
        lines = text.splitlines()
        count = 0
        # remove headline etc.
        for line in lines:
            # Find the line which is the header of the table and includes the day of week
            line_shrink = line.replace(" ", "").replace("\n", "").lower()
            # Note we do not include 'montag' und 'freitag' since they are also used in the line before the table
            # header to indicate the range of the week “Monday … until Friday _”
            if any(x in line_shrink
                   for x in ('dienstag', 'mittwoch', 'donnerstag')):
                break

            count += 1

        else:
            warn(
                "NotImplemented: IPP parsing failed. Menu text is not a weekly menu. First line: '{}'"
                .format(lines[0]))
            return None

        lines = lines[count:]
        weekdays = lines[0]

        # The column detection is done through the string "Tagessuppe siehe Aushang" which is at the beginning of
        # every column. However, due to center alignment the column do not begin at the 'T' character and broader
        # text in the column might be left of this character, which then gets truncated. But the gap between the 'T'
        # and the '€' character of the previous column¹ — the real beginning of the current column — is always three,
        # which will be subtracted here. Monday is the second column, so the value should never become negative
        # although it is handled here.
        # ¹or 'e' of "Internationale Küche" if it is the monday column

        # find lines which match the regex
        # lines[1:] == exclude the weekday line which also can contain `Geschlossen`
        soup_lines_iter = (x for x in lines[1:]
                           if self.split_days_regex.search(x))

        soup_line1 = next(soup_lines_iter)
        soup_line2 = next(soup_lines_iter, '')

        # Sometimes on closed days, the keywords are written instead of the week of day instead of the soup line
        positions1 = [
            (max(a.start() - 3, 0), a.end())
            for a in list(re.finditer(self.split_days_regex_closed, weekdays))
        ]

        positions2 = [(max(a.start() - 3, 0), a.end()) for a in list(
            re.finditer(self.split_days_regex_soup_one_line, soup_line1))]
        # In the second line there is just 'Aushang' (two lines "Tagessuppe siehe Aushang" or
        # closed days ("Geschlossen", "Feiertag")
        positions3 = [(max(a.start() - 14, 0), a.end() + 3) for a in list(
            re.finditer(self.split_days_regex_soup_two_line, soup_line2))]
        # closed days ("Geschlossen", "Feiertag", …) can be in first line and second line
        positions4 = [
            (max(a.start() - 3, 0), a.end()) for a in
            list(re.finditer(self.split_days_regex_closed, soup_line1)) +
            list(re.finditer(self.split_days_regex_closed, soup_line2))
        ]

        if positions3:  # Two lines "Tagessuppe siehe Aushang"
            soup_line_index = lines.index(soup_line2)
        else:
            soup_line_index = lines.index(soup_line1)

        positions = sorted(positions1 + positions2 + positions3 + positions4)

        if len(positions) != 5:
            warn(
                "IPP PDF parsing of week {} in year {} failed. Only {} of 5 columns detected."
                .format(week_number, year, len(positions)))
            return None

        pos_mon = positions[0][0]
        pos_tue = positions[1][0]
        pos_wed = positions[2][0]
        pos_thu = positions[3][0]
        pos_fri = positions[4][0]

        lines_weekdays = {
            "mon": "",
            "tue": "",
            "wed": "",
            "thu": "",
            "fri": ""
        }
        # it must be lines[3:] instead of lines[2:] or else the menus would start with "Preis ab 0,90€" (from the
        # soups) instead of the first menu, if there is a day where the bistro is closed.
        for line in lines[soup_line_index + 3:]:
            lines_weekdays["mon"] += " " + line[pos_mon:pos_tue].replace(
                "\n", " ")
            lines_weekdays["tue"] += " " + line[pos_tue:pos_wed].replace(
                "\n", " ")
            lines_weekdays["wed"] += " " + line[pos_wed:pos_thu].replace(
                "\n", " ")
            lines_weekdays["thu"] += " " + line[pos_thu:pos_fri].replace(
                "\n", " ")
            lines_weekdays["fri"] += " " + line[pos_fri:].replace("\n", " ")

        for key in lines_weekdays:
            # Appends `?€` to „Überraschungsmenü“ if it do not have a price. The second '€' is a separator for the
            # later split
            lines_weekdays[key] = self.surprise_without_price_regex.sub(
                r"\g<1>?€ € \g<2>", lines_weekdays[key])
            # get rid of two-character umlauts (e.g. SMALL_LETTER_A+COMBINING_DIACRITICAL_MARK_UMLAUT)
            lines_weekdays[key] = unicodedata.normalize(
                "NFKC", lines_weekdays[key])
            # remove multi-whitespaces
            lines_weekdays[key] = ' '.join(lines_weekdays[key].split())
            # get all dish including name and price
            dish_names_price = re.findall(self.dish_regex,
                                          lines_weekdays[key] + ' ')
            # create dish types
            # since we have the same dish types every day we can use them if there are 4 dishes available
            if len(dish_names_price) == 4:
                dish_types = [
                    "Veggie", "Traditionelle Küche", "Internationale Küche",
                    "Specials"
                ]
            else:
                dish_types = ["Tagesgericht"] * len(dish_names_price)

            # create ingredients
            # all dishes have the same ingridients
            ingredients = Ingredients("ipp-bistro")
            ingredients.parse_ingredients("Mi,Gl,Sf,Sl,Ei,Se,4")
            # create list of Dish objects
            counter = 0
            dishes = []
            for (dish_name, price) in dish_names_price:
                dishes.append(
                    Dish(dish_name.strip(),
                         Prices(Price(price.replace(',', '.').strip())),
                         ingredients.ingredient_set, dish_types[counter]))
                counter += 1
            date = self.get_date(year, week_number,
                                 self.weekday_positions[key])
            # create new Menu object and add it to dict
            menu = Menu(date, dishes)
            # remove duplicates
            menu.remove_duplicates()
            menus[date] = menu

        return menus
Пример #21
0
class IPPBistroParserTest(unittest.TestCase):
    ipp_parser = IPPBistroMenuParser()
    test_menu1 = open('src/test/assets/ipp/KW-47_20.11-24.11.2017-1.txt',
                      'r').read()
    year1 = 2017
    week_number1 = 47
    test_menu2 = open('src/test/assets/ipp/KW-48_27.11-01.12.10.2017-3.txt',
                      'r').read()
    year2 = 2017
    week_number2 = 48

    date_mon1 = date(2017, 11, 20)
    date_tue1 = date(2017, 11, 21)
    date_wed1 = date(2017, 11, 22)
    date_thu1 = date(2017, 11, 23)
    date_fri1 = date(2017, 11, 24)
    dish1_mon1 = Dish("Gefüllter Germknödel mit Vanillesauce", 3.5)
    dish2_mon1 = Dish(
        "Ofengulasch vom Rind mit Kürbis und Pflaumen, dazu Rigatoni", 5.5)
    dish3_mon1 = Dish(
        "\"Palek Tofu\" Gebratener Tofu mit Spinat, Ingwer, Curry-Sahnesauce und Basmatireis",
        5.2)
    dish4_mon1 = Dish(
        "Gebratene Hähnchenbrust auf Fenchelgemüse, dazu Kräuterreis und Orangensauce",
        6.9)
    dish1_tue1 = Dish(
        "Gebratene Weißkohl-Kartoffelpfanne mit gerösteten Sonnenblumenkernen",
        3.5)
    dish2_tue1 = Dish("Jägerschnitzel mit Spätzle oder Reis", 4.8)
    dish3_tue1 = Dish(
        "Vegetarisch gefüllte Tortelli mit leichter Zitronen-Buttersauce und gehobeltem Parmesan",
        4.8)
    dish4_tue1 = Dish("\"Bami Goreng\" indonesische Bratnudeln mit Gemüse, Huhn, Schweinefleisch und Pilzen, " \
                                   "dazu Honig-Chili- Dip", 6.9)
    dish1_wed1 = Dish("Erbseneintopf (mit Wienerle 4,20 €)", 3.5)
    # TODO fix "B"
    dish2_wed1 = Dish("Hackbraten mit Zigeunersauce und Reis B", 4.8)
    dish3_wed1 = Dish(
        "\"Farfalle Rustico\" mit Champignons, Schinken Tomaten und Peperoni (auf Wunsch mit "
        "Reibekäse)", 4.6)
    dish4_wed1 = Dish("Rumpsteak mit Balsamico Pilzen und Wedges", 7.9)
    dish1_thu1 = Dish(
        "Mediterrane Frittata mit Zucchini, Kartoffeln, Paprika, kleiner Salatbeilage und "
        "Joghurt-Limetten Dip", 3.5)
    # TODO fix bug that B of Brett is missing -> rett
    dish2_thu1 = Dish(
        "Frischer Bayrischer Schweinenackenbraten vom rett geschnitten dazu Kartoffel- Gurkensalat",
        4.5)
    dish3_thu1 = Dish(
        "\"Enchilada Verdura\", überbackene Weizentortilla, gefüllt mit Hähnchenfleisch, Sauerrahm, "
        "Kidneybohnen, Mais, dazu", 5.9)
    dish4_thu1 = Dish(
        "\"Lamm Palak\" mit Spinat und Curry (mittelscharf), dazu Reis", 6.9)
    dish1_fri1 = Dish("Nudelpfanne mit Gemüsesauce (auf Wunsch mit Reibekäse)",
                      3.5)
    dish2_fri1 = Dish("Matjes \"Hausfrauen Art\" mit Salzkartoffeln", 5.2)
    dish3_fri1 = Dish("Currygeschnetzeltes von der Pute mit Früchten und Reis",
                      4.9)
    dish4_fri1 = Dish("Honig-Kassler mit Apfel-Spitzkohl und Kartoffelspalten",
                      6.2)
    menu_mon1 = Menu(date_mon1,
                     [dish1_mon1, dish2_mon1, dish3_mon1, dish4_mon1])
    menu_tue1 = Menu(date_tue1,
                     [dish1_tue1, dish2_tue1, dish3_tue1, dish4_tue1])
    menu_wed1 = Menu(date_wed1,
                     [dish1_wed1, dish2_wed1, dish3_wed1, dish4_wed1])
    menu_thu1 = Menu(date_thu1,
                     [dish1_thu1, dish2_thu1, dish3_thu1, dish4_thu1])
    menu_fri1 = Menu(date_fri1,
                     [dish1_fri1, dish2_fri1, dish3_fri1, dish4_fri1])

    date_mon2 = date(2017, 11, 27)
    date_tue2 = date(2017, 11, 28)
    date_wed2 = date(2017, 11, 29)
    date_thu2 = date(2017, 11, 30)
    date_fri2 = date(2017, 12, 1)
    dish1_mon2 = Dish("Wirsing-Kartoffelauflauf mit Bechamel und Käse", 3.5)
    dish2_mon2 = Dish("Paprikarahm Geschnetzeltes mit Paprikamix und Nudeln",
                      4.8)
    dish3_mon2 = Dish(
        "\"Dal Curry\" mit Kartoffeln, Kokosmilch, Ingwer, Koriander, Reis und scharfem Chutney",
        4.9)
    # TODO fix missing "R" of "Rinderbraten"
    dish4_mon2 = Dish(
        "Deftiger Hüttenschmaus, inderrostbraten mit Zwiebeln, Semmelknödel und gebratenem Gemüse",
        7.9)
    dish1_tue2 = Dish("Herbstliche Gemüse-Reis Pfanne mit pikantem Mango Dip",
                      3.5)
    dish2_tue2 = Dish("Krautwickerl mit Speck-Zwieblsauce und Püree", 4.5)
    dish3_tue2 = Dish("Rigatoni mit Rosenkohl und Schnittlauch", 4.6)
    dish4_tue2 = Dish("Spanferkelrücken mit Knödel und Bayerisch Kraut", 6.8)
    dish1_wed2 = Dish(
        "Weißwurst Gröst ́l mit Knödel, Lauchzwiebeln, Karotten und Kräuter auf Wunsch mit "
        "Bratenjus", 3.5)
    dish2_wed2 = Dish("Estragonrahmschnitzel mit Pommes frites oder Reis", 4.6)
    dish3_wed2 = Dish("Gemüse Lasagne", 4.9)
    dish4_wed2 = Dish(
        "\"Tandoori Chicken\" mit Auberginen, Tomaten, Zucchini, Zitronenschale Minze und Reis",
        6.9)
    dish1_thu2 = Dish("Rote Beete Eintopf mit Kartoffeln, Nudeln und Dill",
                      3.5)
    dish2_thu2 = Dish(
        "Sauerbraten \"Nepal\" mit weißen Bohnen, getrockneten Tomaten und Pasta",
        5.8)
    dish3_thu2 = Dish(
        "\"Kaku Chicken\" mit geröstetem Curry, Kokosraspel, Tomaten und Reis",
        6.9)
    dish4_thu2 = Dish(
        "Leberkäs Burger special mit Pommes frites und Cole slaw", 4.8)
    dish1_fri2 = Dish("Exotische Linsen-Spätzle Pfanne", 3.5)
    dish2_fri2 = Dish(
        "Seelachsfilet gebacken mit Sardellenmayonnaise und Pommes frites",
        4.6)
    dish3_fri2 = Dish("Gemüse-Linguini mit Pesto-Rahmsauce und Parmesankäse",
                      4.4)
    dish4_fri2 = Dish(
        "Schweinefilet Medaillons in grüner Pfefferrahmsauce mit Kroketten und karamellisierten "
        "Möhren", 7.2)

    menu_mon2 = Menu(date_mon2,
                     [dish1_mon2, dish2_mon2, dish3_mon2, dish4_mon2])
    menu_tue2 = Menu(date_tue2,
                     [dish1_tue2, dish2_tue2, dish3_tue2, dish4_tue2])
    menu_wed2 = Menu(date_wed2,
                     [dish1_wed2, dish2_wed2, dish3_wed2, dish4_wed2])
    menu_thu2 = Menu(date_thu2,
                     [dish1_thu2, dish2_thu2, dish3_thu2, dish4_thu2])
    menu_fri2 = Menu(date_fri2,
                     [dish1_fri2, dish2_fri2, dish3_fri2, dish4_fri2])

    def test_Should_Return_Menu1(self):
        menus_actual1 = self.ipp_parser.get_menus(self.test_menu1, self.year1,
                                                  self.week_number1)
        self.assertEqual(5, len(menus_actual1))
        self.assertEqual(self.menu_mon1, menus_actual1[self.date_mon1])
        self.assertEqual(self.menu_tue1, menus_actual1[self.date_tue1])
        self.assertEqual(self.menu_wed1, menus_actual1[self.date_wed1])
        self.assertEqual(self.menu_thu1, menus_actual1[self.date_thu1])
        self.assertEqual(self.menu_fri1, menus_actual1[self.date_fri1])

    def test_Should_Return_Menu2(self):
        menus_actual2 = self.ipp_parser.get_menus(self.test_menu2, self.year2,
                                                  self.week_number2)
        self.assertEqual(5, len(menus_actual2))
        self.assertEqual(self.menu_mon2, menus_actual2[self.date_mon2])
        self.assertEqual(self.menu_tue2, menus_actual2[self.date_tue2])
        self.assertEqual(self.menu_wed2, menus_actual2[self.date_wed2])
        self.assertEqual(self.menu_thu2, menus_actual2[self.date_thu2])
        self.assertEqual(self.menu_fri2, menus_actual2[self.date_fri2])