-
Notifications
You must be signed in to change notification settings - Fork 0
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.
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
StravaCZclient
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.menuBefore 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
selffor method chaining
Method chaining example:
strava.menu.fetch().print() # Fetch and immediately printThe 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
]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" |
The Menu class provides two main methods for data retrieval:
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
)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
)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")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 if a meal is ordered:
if strava.menu.is_ordered(75):
print("Meal 75 is ordered")
else:
print("Meal 75 is not ordered")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).
The Menu class supports Python's magic methods for convenient access:
print(strava.menu)
# Output: Menu(days=5, meals=15)
print(repr(strava.menu))
# Output: Menu(days=5, meals=15)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")Get the number of orderable days:
num_days = len(strava.menu)
print(f"Menu has {num_days} orderable days")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]The Menu class automatically filters out:
- Empty meals - Meals with no description or generic names
- Holidays - Days marked with "VP" (vacation period)
- Unknown types - Meals that don't match SOUP or MAIN categories
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]
)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
# ...
# }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()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()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()# ✅ Good
strava.menu.fetch()
meals = strava.menu.get_meals()
# ❌ Bad - no data available
meals = strava.menu.get_meals() # Returns empty list# ✅ 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")meals = strava.menu.get_meals(meal_types=[MealType.SOUP])
if not meals:
print("No soups available")
else:
print(f"Found {len(meals)} soups")# ✅ 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- Learn about Meal Types and Orders
- Explore Filtering and Queries
- Read about Ordering Meals
- Check the Menu Class API Reference