Skip to content

Menu System

jsem-nerad edited this page Nov 12, 2025 · 1 revision

Menu System

The Menu System is the core of the strava-cz-python library. This guide explains how the Menu class works and how to interact with menu data.

Overview

The Menu class is an independent component that:

  • Fetches menu data from the API
  • Processes and filters meal information
  • Provides ordering and cancellation functionality
  • Maintains a reference to the parent StravaCZ client

Accessing the Menu

The menu is accessed through the strava.menu property:

from strava_cz import StravaCZ

strava = StravaCZ(username="...", password="...", canteen_number="3753")

# Access menu
menu = strava.menu

Fetching Menu Data

Before accessing menu items, you must fetch the data:

strava.menu.fetch()

This method:

  • Downloads menu data from the API
  • Parses and processes the data
  • Filters out invalid entries (empty meals, holidays, etc.)
  • Returns self for method chaining

Method chaining example:

strava.menu.fetch().print()  # Fetch and immediately print

Menu Data Structure

Internal Storage

The menu stores all meals internally in a single list grouped by date:

# Internal structure (simplified)
[
    {
        "date": "2025-11-15",
        "ordered": False,  # True if any meal is ordered
        "meals": [
            {
                "id": 75,
                "type": MealType.SOUP,
                "orderType": OrderType.NORMAL,
                "name": "Vývar s kuskusem",
                "price": 0.0,
                "ordered": False,
                "alergens": "01 -Obiloviny obsahující lepek|06 -Sójové boby|",
                "forbiddenAlergens": "",
                "date": "2025-11-15"
            },
            # ... more meals
        ]
    },
    # ... more days
]

Meal Data Fields

Each meal contains:

Field Type Description Example
id int Unique meal identifier 75
type MealType Meal type enum MealType.SOUP or MealType.MAIN
orderType OrderType Order restriction type OrderType.NORMAL
name str Meal name "Vývar s kuskusem"
price float Meal price 40.0
ordered bool Order status True / False
alergens str Allergen information `"01 -Obiloviny
forbiddenAlergens str Forbidden allergens ""
date str Meal date "2025-11-15"

Retrieving Menu Data

The Menu class provides two main methods for data retrieval:

1. Get Days (get_days())

Returns meals grouped by date:

# Get all orderable days
days = strava.menu.get_days()

# Iterate through days
for day in days:
    print(f"Date: {day['date']}")
    print(f"Ordered: {day['ordered']}")
    for meal in day['meals']:
        print(f"  - {meal['name']}")

Parameters:

  • meal_types: Optional[List[MealType]] - Filter by meal types
  • order_types: Optional[List[OrderType]] - Filter by order types (default: [OrderType.NORMAL])
  • ordered: Optional[bool] - Filter by order status

Examples:

# Only orderable meals (default)
normal_days = strava.menu.get_days()

# Include restricted and optional meals
all_days = strava.menu.get_days(
    order_types=[OrderType.NORMAL, OrderType.RESTRICTED, OrderType.OPTIONAL]
)

# Only soups
soup_days = strava.menu.get_days(meal_types=[MealType.SOUP])

# Only ordered days
ordered_days = strava.menu.get_days(ordered=True)

# Unordered main dishes
unordered_main = strava.menu.get_days(
    meal_types=[MealType.MAIN],
    ordered=False
)

2. Get Meals (get_meals())

Returns a flat list of all meals:

# Get all orderable meals
meals = strava.menu.get_meals()

# Iterate through meals
for meal in meals:
    print(f"{meal['date']}: {meal['name']} - {meal['price']} Kč")

Parameters:

  • meal_types: Optional[List[MealType]] - Filter by meal types
  • order_types: Optional[List[OrderType]] - Filter by order types (default: [OrderType.NORMAL])
  • ordered: Optional[bool] - Filter by order status

Examples:

# All orderable meals
meals = strava.menu.get_meals()

# Only main dishes
main_meals = strava.menu.get_meals(meal_types=[MealType.MAIN])

# Only ordered meals
ordered = strava.menu.get_meals(ordered=True)

# Unordered soups
unordered_soups = strava.menu.get_meals(
    meal_types=[MealType.SOUP],
    ordered=False
)

Helper Methods

Get by Date

Find meals for a specific date:

date_menu = strava.menu.get_by_date("2025-11-15")

if date_menu:
    print(f"Meals for {date_menu['date']}:")
    for meal in date_menu['meals']:
        print(f"  - {meal['name']}")
else:
    print("No meals found for this date")

Get by ID

Find a specific meal by ID:

meal = strava.menu.get_by_id(75)

if meal:
    print(f"Found: {meal['name']}")
    print(f"Type: {meal['type'].value}")
    print(f"Price: {meal['price']} Kč")
else:
    print("Meal not found")

Check Order Status

Check if a meal is ordered:

if strava.menu.is_ordered(75):
    print("Meal 75 is ordered")
else:
    print("Meal 75 is not ordered")

Displaying Menu

Print Method

Display a formatted menu:

strava.menu.print()

Output example:

2025-11-15:
  - 75 Vývar s kuskusem (Polévka) - [Not ordered]
  - 1 Čočka s uzeným masem (Hlavní jídlo) - [Ordered]
  - 2 Čočka s vejcem (Hlavní jídlo) - [Not ordered]

2025-11-16:
  - 80 Hovězí polévka (Polévka) - [Not ordered]
  - 5 Kuřecí steak (Hlavní jídlo) - [Not ordered]

By default, print() shows only orderable meals (OrderType.NORMAL).

Magic Methods

The Menu class supports Python's magic methods for convenient access:

String Representation

print(strava.menu)
# Output: Menu(days=5, meals=15)

print(repr(strava.menu))
# Output: Menu(days=5, meals=15)

Iteration

Iterate directly over orderable days:

for day in strava.menu:
    print(f"{day['date']}: {len(day['meals'])} meals")

Equivalent to:

for day in strava.menu.get_days():
    print(f"{day['date']}: {len(day['meals'])} meals")

Length

Get the number of orderable days:

num_days = len(strava.menu)
print(f"Menu has {num_days} orderable days")

Indexing

Access days by index:

# First day
first_day = strava.menu[0]

# Last day
last_day = strava.menu[-1]

# First three days
first_three = strava.menu[:3]

Automatic Filtering

The Menu class automatically filters out:

  1. Empty meals - Meals with no description or generic names
  2. Holidays - Days marked with "VP" (vacation period)
  3. Unknown types - Meals that don't match SOUP or MAIN categories

Order Types Explained

Each meal has an orderType based on API restrictions:

OrderType Symbol Meaning Can Order?
NORMAL Empty Regular orderable meal ✅ Yes
RESTRICTED "CO" Too late to order/change ❌ No
OPTIONAL "T" Optional/not ordered usually ✅ Yes

Default behavior: Only NORMAL meals are returned unless you explicitly request other types.

# Default - only NORMAL
normal = strava.menu.get_meals()

# Include all types
all_meals = strava.menu.get_meals(
    order_types=[OrderType.NORMAL, OrderType.RESTRICTED, OrderType.OPTIONAL]
)

Raw Data Access

Access the raw API response:

strava.menu.fetch()

# Raw data from API
raw = strava.menu.raw_data

# Example structure
# {
#     "table0": [...],  # Day 1 meals
#     "table1": [...],  # Day 2 meals
#     ...
# }

⚠️ Note: The raw data structure is complex and not recommended for general use. Use the provided methods instead.

Refreshing Menu Data

The menu data is automatically refreshed after ordering or canceling meals:

strava.menu.fetch()
# ... data is current ...

strava.menu.order_meals(3)
# Menu is automatically refreshed after ordering

# Manual refresh if needed
strava.menu.fetch()

Performance Considerations

Caching

The Menu stores processed data in memory. Multiple calls to get_days() or get_meals() don't re-fetch from the API - they filter the stored data.

strava.menu.fetch()  # Fetches from API

# These are fast - use stored data
meals1 = strava.menu.get_meals()
meals2 = strava.menu.get_meals(meal_types=[MealType.MAIN])
days = strava.menu.get_days()

When to Re-fetch

Re-fetch when:

  • You need up-to-date meal availability
  • After ordering/canceling (done automatically)
  • When checking for menu updates from other devices
# Initial fetch
strava.menu.fetch()

# ... time passes ...

# Refresh to get latest data
strava.menu.fetch()

Best Practices

1. Always Fetch Before Use

# ✅ Good
strava.menu.fetch()
meals = strava.menu.get_meals()

# ❌ Bad - no data available
meals = strava.menu.get_meals()  # Returns empty list

2. Use Appropriate Filter Method

# ✅ Good - Use get_days() when you need day grouping
for day in strava.menu.get_days():
    print(f"\n{day['date']}")
    for meal in day['meals']:
        print(f"  {meal['name']}")

# ✅ Good - Use get_meals() for flat list
all_meals = strava.menu.get_meals()
print(f"Total: {len(all_meals)} meals")

3. Check for Empty Results

meals = strava.menu.get_meals(meal_types=[MealType.SOUP])

if not meals:
    print("No soups available")
else:
    print(f"Found {len(meals)} soups")

4. Use Helper Methods

# ✅ Good - Use helper methods
meal = strava.menu.get_by_id(75)

# ❌ Bad - Manual search
meal = None
for day in strava.menu.get_days():
    for m in day['meals']:
        if m['id'] == 75:
            meal = m
            break

Next Steps

Clone this wiki locally