An orchestrator starts your pipeline on a schedule. A daily schedule makes one run per day, and each run is for one day: its run date (Airflow calls it the logical date). The run for May 3 starts after May 3 is over, early on May 4, because only then are all of May 3's orders in. Every task gets that date as run_date, so extract_orders reads orders/2026-05-03.csv whenever the run really happens. A task that used today's date instead would read the wrong file each time a run is late or is run again after a bug fix.
Counting days: run dates are text like "2026-05-01", and text can't count days. Python's datetime module can. date.fromisoformat(text) turns the text into a date. timedelta(days=1) is one day: adding it to a date gives the next day, across the end of a month too. Dates compare like numbers, the earlier day being the smaller one, and isoformat() gives the text back.
from datetime import date, timedelta
d = date.fromisoformat("2026-01-30")
d = d + timedelta(days=2)
print(d.isoformat()) # 2026-02-01
print(d <= date.fromisoformat("2026-02-03")) # True
The starting code has the five tasks, which all take run_date, and run_pipeline(run_date), which runs them in order for one date. daily_run_dates(start, end) should return every date from start to end as text, both days included, oldest first. For now it returns an empty list, so nothing runs. Once it works, the program prints this (the check adds the last two lines):
Run dates: ['2026-05-01', '2026-05-02', '2026-05-03']
Run for 2026-05-01
extract_orders reads orders/2026-05-01.csv
extract_customers done
clean_orders done
build_report writes report_2026-05-01.csv
send_email done
Run for 2026-05-02
… (the same five tasks, for 2026-05-02)
Run for 2026-05-03
… (the same five tasks, for 2026-05-03)
April 29 to May 2: ['2026-04-29', '2026-04-30', '2026-05-01', '2026-05-02']
One day: ['2026-05-04']
In Airflow you write schedule="@daily" and its scheduler makes these runs by itself. Here you build the list of run dates by hand.
Your task: in daily_run_dates, turn start and end into dates, loop while day is not after last, add each day to run_dates as text, and move day one day forward on every turn.
Assignment
Follow the Coding Tutorial to fill in daily_run_dates with date.fromisoformat, a while loop, isoformat() and timedelta(days=1).
Hint
Compare with <=, not <: the last day gets its run too. You type the line that moves day forward before the append line above it, because a loop whose day never moves on never ends.
Free plan: 30 tutor messages. PRO is unlimited.
