-
Notifications
You must be signed in to change notification settings - Fork 0
Menu System
The menu is reached as strava.menu. It holds the canteen's published menu as
Day objects, each holding Meal objects.
Nothing is loaded until you ask:
strava.menu.fetch()fetch() returns the menu, so you can chain:
days = strava.menu.fetch().get_days()Using the menu before fetching raises rather than quietly returning an empty list:
from strava_cz import MenuNotFetchedError
try:
strava.menu.get_days()
except MenuNotFetchedError:
strava.menu.fetch()strava.menu.fetched tells you which state you are in.
Re-fetching replaces everything, and the library does it automatically after every ordering operation so the local copy never drifts from the canteen's.
meal = strava.menu.get_by_id(5)| attribute | type | meaning |
|---|---|---|
id |
int |
Identifier used for ordering (the API's veta) |
date |
datetime.date |
The day it is served |
type |
MealType |
SOUP, MAIN or UNKNOWN
|
variant |
str |
The canteen's label, e.g. "Oběd 1"
|
name |
str |
What is being served |
price |
float |
Price in the account's currency |
ordered |
bool |
Whether it is currently ordered |
can_order |
bool |
Whether it can be ordered right now |
can_cancel |
bool |
Whether an existing order can be cancelled |
order_restriction |
Restriction |
Why it cannot be ordered |
cancel_restriction |
Restriction |
Why it cannot be cancelled |
allergens |
tuple[Allergen, ...] |
(code, name) pairs |
deadline |
datetime | None |
When ordering closes |
raw |
dict |
The untouched API record |
Meals are frozen dataclasses: you can compare them, put them in sets, and you cannot change them by accident.
print(meal) # [5] Kuřecí kostky na paprice (50) - not ordered
print(meal.name, meal.price, meal.date.strftime("%d.%m."))
for code, name in meal.allergens:
print(f"{code}: {name}")raw is the escape hatch. Anything the library does not model is still there:
print(meal.raw["alergeny_text"])
print(meal.raw["omezeniObj"])| attribute | type | meaning |
|---|---|---|
date |
datetime.date |
The day |
meals |
tuple[Meal, ...] |
Its meals, in the order the API returned them |
ordered |
bool |
Whether at least one meal is ordered |
orderable |
tuple[Meal, ...] |
The meals that can be ordered right now |
no_school |
bool |
Whether the canteen does not cook that day |
auto_ordered |
bool |
Whether the canteen orders that day for you |
status |
DayStatus |
What the canteen says about the day as a whole |
day_code |
str |
The raw day-level code (omezeniObj.den) |
day = strava.menu.get_by_date("2026-09-07")
print(day) # 2026-09-07 (3 meals)
print(len(day)) # 3
for meal in day: # days iterate over their meals
print(meal.name)get_days() returns days, get_meals() returns the same selection flattened. Both take
the same keyword arguments, and all of them default to "do not filter".
strava.menu.get_days(
meal_types=None, # e.g. [MealType.MAIN]
orderable=None, # True / False
ordered=None, # True / False
auto_ordered=None, # True / False - picks whole days
date_from=None, # date or "YYYY-MM-DD"
date_to=None, # inclusive
include_no_school=False,
)Nothing is hidden by default except days the canteen does not cook on. Every published meal comes back, and each one tells you whether it can be ordered. This is a deliberate change from v0.2.0, whose default silently dropped meals it classified as restricted — and misclassified about a quarter of them.
from strava_cz import MealType
# Everything
all_meals = strava.menu.get_meals()
# Just what you can order now
orderable = strava.menu.get_meals(orderable=True)
# Just what you cannot, to find out why
for meal in strava.menu.get_meals(orderable=False):
print(meal.name, "-", meal.order_restriction.description)
# The days nothing arrives on unless you order it yourself
for day in strava.menu.get_days(auto_ordered=False):
print(day.date, "- order it yourself or go hungry")
# Main dishes only
lunches = strava.menu.get_meals(meal_types=[MealType.MAIN])
# Already ordered
mine = strava.menu.get_meals(ordered=True)
# A date range
week = strava.menu.get_days(date_from="2026-09-07", date_to="2026-09-11")
# Filters combine
choices = strava.menu.get_meals(
meal_types=[MealType.MAIN], orderable=True, ordered=False, date_from="2026-09-07"
)Days that end up with no matching meals drop out of the result, so
get_days(meal_types=[MealType.SOUP], orderable=True) is empty in a canteen where soup
is never separately orderable.
Holidays and closure days are excluded unless you ask for them. They carry no meals —
the canteen fills those slots with placeholder rows such as "Nevaří se", which the
library does not present as food:
closed = [d for d in strava.menu.get_days(include_no_school=True) if d.no_school]
for day in closed:
print(f"No school on {day.date}")strava.menu.get_by_id(5) # Meal, or None
strava.menu.get_by_date("2026-09-07") # Day, or None
strava.menu.get_by_date(datetime.date(2026, 9, 7))
strava.menu.is_ordered(5) # bool; raises MealNotFoundError for unknown ids
5 in strava.menu # bool, never raisesis_ordered() raising for an unknown id is intentional: silently answering False for
an id that does not exist hides typos and stale ids.
Menu behaves like the list of days you would get from get_days():
len(strava.menu) # number of days with meals
strava.menu[0] # first Day
strava.menu[:3] # first three days
for day in strava.menu:
...
repr(strava.menu) # Menu(days=20, meals=57, orderable=36)strava.menu.print()
strava.menu.print(orderable=True) # takes the same filters
strava.menu.print(meal_types=[MealType.MAIN])strava.menu.raw_data # the decoded objednavky response, untouched
strava.menu.parse_warnings # rows the parser could not useA row with an unreadable date or a shape the parser does not recognise is skipped and
recorded in parse_warnings rather than taking the whole fetch down. If you see
warnings, the API has probably changed — please
open an issue.