Ask a real weather service for the week's forecast, read the JSON it sends back, and fall back to a saved copy when there is no connection.
Weather apps do not measure the weather themselves: they ask an API. Your program can ask the same one.
Optional. This lesson needs the internet: if your school blocks the weather site, the program uses a saved copy instead, and everything still works. An API sends data to programs. Open-Meteo is a free weather API: you send an address with a place's latitude and longitude, and it replies with a forecast in JSON, which Python reads as dictionaries and lists. requests.get(...) asks; .json() turns the reply into Python. The saved copy is read with json.load(f), which does the same for a JSON file.
Make your prediction first. Help opens once you've locked it in.
reply = {"daily": {"time": ["Mon", "Tue"], "temperature_2m_max": [18.5, 22.1]}}
print(reply["daily"]["temperature_2m_max"][1])
A dictionary inside a dictionary, with a list inside that. Follow the square brackets from left to right.
Run it. The first line says whether the forecast is live or the saved copy. Then change the latitude and longitude to your own town (look them up on a map; south of the equator, latitude is negative) and run it again.
import json
import requests
URL = "https://api.open-meteo.com/v1/forecast"
canberra = {"latitude": -35.28, "longitude": 149.13, "timezone": "Australia/Sydney", "daily": "temperature_2m_max,temperature_2m_min"}
try:
reply = requests.get(URL, params=canberra, timeout=10).json()
print("Live forecast from Open-Meteo")
except requests.RequestException:
with open("weather.json") as f:
reply = json.load(f)
print("No connection: using the saved forecast")
days = reply["daily"]
for i in range(len(days["time"])):
print(days["time"][i] + ": " + str(days["temperature_2m_min"][i]) + " to " + str(days["temperature_2m_max"][i]) + " degrees")
print("Weather data by Open-Meteo.com (CC BY 4.0)")
import json
import requests
URL = "https://api.open-meteo.com/v1/forecast"
canberra = {"latitude": -35.28, "longitude": 149.13, "timezone": "Australia/Sydney", "daily": "temperature_2m_max,temperature_2m_min"}
try:
reply = requests.get(URL, params=canberra, timeout=10).json()
print("Live forecast from Open-Meteo")
except requests.RequestException:
with open("weather.json") as f:
reply = json.load(f)
print("No connection: using the saved forecast")
days = reply["daily"]
for i in range(len(days["time"])):
print(days["time"][i] + ": " + str(days["temperature_2m_min"][i]) + " to " + str(days["temperature_2m_max"][i]) + " degrees")
print("Weather data by Open-Meteo.com (CC BY 4.0)")
What params builds.
Why there is a saved copy.
A level that was skipped.
This should print each day's top temperature, but it stops with KeyError: 'temperature_2m_max'. Click the line that is wrong.
Find the hottest day of the week, and print it with its temperature.
The biggest-so-far pattern from Lesson 2: hottest = 0 (the first day's place in the list), then replace it when a day's top temperature is higher.
Ask the API for precipitation_sum (rain in mm) as well, and show it on rainy days. The saved copy has it already.
Add ,precipitation_sum to the "daily" text, then print days["precipitation_sum"][i] on days with rain.
Find and print the hottest day of the week.
Run your program. This ticks when your code does all of the above.
Ask for the rain too, and show it on the days it rains.
Run your program. This ticks when your code does all of the above.
Compare the week ahead in two places of your choice: which is warmer on average, and by how much? Catch a failed request so the program says so instead of crashing. (For a bigger challenge, put it behind a Gradio app with a dropdown of places.)
Compare the week ahead in two places, handling a failed request.
Run your program. This ticks when your code does all of the above.
The same requests code works in Python on any computer. Most big APIs (maps, music, sport) need a key and an account; Open-Meteo is one of the few that do not.
An optional lesson. Students ask the Open-Meteo weather API for a week's forecast with requests, read the nested JSON, fall back to a saved copy when there is no connection, then find the hottest day, add rain and compare two places. About 45 minutes.
Open the teacher guide: answers, solutions, slides and a worksheet.
Optional: not needed for completing the course. It needs api.open-meteo.com to be reachable from school devices (the Check your school page tests it); if it is blocked, except requests.RequestException: loads weather.json, an example reply in Open-Meteo's format (made up for these lessons, not a real forecast), so the lesson still works. Open-Meteo is free for non-commercial use with credit (CC BY 4.0), needs no key, and allows requests from web pages. In the playground, requests is a small stand-in (get, params, .json(), .status_code, .ok, .raise_for_status()) so the same code runs with the real requests on a computer. The reply is a dictionary; reply["daily"] holds lists (time, temperature_2m_max, ...) where place i in each list is the same day (the bug task skips the daily level). params= builds the query string, the other side of Flask's request.args.
Reading nested JSON. Ask students to print reply, then reply["daily"], one level at a time, instead of telling them the path.
Stretch: Put the two-place comparison behind a Gradio app with a dropdown of places, or ask Open-Meteo for hourly temperatures and chart today with text bars.
Support: Give students the hottest-day loop with the comparison line blank, and ask them to finish it.
Machine learning with Gradio uses data in the same way: tables in, answers out. Web apps with Flask builds the other side: an API of your own.