Menu mode
Running python3 weather.py opens a menu where I can save a location,
fetch the forecast, change the number of periods, or run one-time lookups.
This project turns the weather logic from my larger Flask seed tracking app into a standalone Python terminal tool. The app can get a forecast from Weather.gov, print the next few forecast periods, save a default location, and run from an interactive menu.
The first version was a simple command-line script. The upgraded version is more advanced: it works like a small terminal application with menu options, saved settings, one-time lookups, direct command-line mode, and better input validation.
I built a Python program called weather.py. It can be used two ways: as an
interactive menu app or as a direct command-line tool.
Running python3 weather.py opens a menu where I can save a location,
fetch the forecast, change the number of periods, or run one-time lookups.
Running the script with --zip or --coords skips the menu
and prints the forecast immediately.
The app saves a location and forecast-period count in weather_settings.json,
making it feel more like a real terminal utility.
The first version proved that the API request worked. This version adds application behavior around that working core.
The app can remember a saved location instead of requiring a ZIP code every time.
It works both as an interactive menu app and as a direct command-line tool.
The script checks ZIP codes, coordinate ranges, and forecast-period counts.
HTTP errors, network errors, missing data, and bad input are caught and printed cleanly.
This project is not random. It came from a real feature in my larger Flask seed tracking app. The larger app uses weather data for garden planning. This project pulls out the core weather API pattern and turns it into a smaller standalone learning project.
| Seed app pattern | Tiny terminal version | Why it matters |
|---|---|---|
fetch_json() |
Reusable helper for API requests. | Keeps headers, timeout, and JSON parsing in one place. |
User-Agent |
Set by WEATHER_USER_AGENT or a default string. |
Identifies the app when making Weather.gov requests. |
| ZIP lookup | Uses a ZIP code to find latitude and longitude. | Makes the app easier to run without manually entering coordinates. |
Weather.gov /points |
Finds the correct forecast URL for a location. | The first API call gives the app the next API endpoint to follow. |
| Forecast periods | Prints the next few periods in the terminal. | Turns nested JSON into useful readable output. |
The app follows a clean request chain. This is the important part of the project.
The user enters a ZIP code, coordinates, or uses a saved location.
If a ZIP code is used, the script turns it into latitude and longitude.
The script calls Weather.gov /points to find the forecast URL.
The script fetches forecast periods and prints them in a readable format.
Even with the menu, the script still works as a normal command-line tool. That matters because direct commands are easier to automate later.
# Open the interactive menu
python3 weather.py
# One-time ZIP code forecast
python3 weather.py --zip 11234
# One-time coordinate forecast
python3 weather.py --coords 40.7128 -74.0060
# Print more forecast periods
python3 weather.py --zip 11234 --count 5
The menu version creates a small JSON settings file so the app can remember the saved location and forecast-period count.
weather_settings.json
A saved location might look like this:
{
"location": {
"type": "zip",
"zip_code": "11234",
"latitude": "40.6215",
"longitude": "-73.9349",
"label": "Brooklyn, NY"
},
"count": 3
}
weather_settings.json to .gitignore.
echo "weather_settings.json" >> .gitignore
This version was built with AI assistance, but it was not created from nothing. I already had working weather logic in my Flask seed app, including the request helper, Weather.gov flow, ZIP-code idea, and forecast parsing pattern.
I provided the weather logic from my seed app and explained the goal: make a tiny standalone terminal weather project that could run with a ZIP code, coordinates, and an interactive menu.
AI helped simplify the larger Flask pattern into a smaller script, add the menu, structure the functions, keep direct command-line mode, and make the project easier to explain as a LaunchShell writeup.
The full script is longer because of the menu and error handling. These are the most important pieces.
This keeps the Weather.gov headers and JSON parsing in one place.
def fetch_json(url):
request_headers = {
"Accept": "application/geo+json, application/json",
"User-Agent": DEFAULT_USER_AGENT,
}
req = urllib.request.Request(url, headers=request_headers)
with urllib.request.urlopen(req, timeout=15) as response:
return json.loads(response.read().decode("utf-8"))
Weather.gov /points returns the correct forecast endpoint for the location.
def fetch_forecast_url(latitude, longitude):
points_url = f"https://api.weather.gov/points/{latitude},{longitude}"
data = fetch_json(points_url)
properties = data.get("properties", {})
forecast_url = properties.get("forecast")
if not forecast_url:
raise ValueError("Weather.gov did not return a forecast URL.")
return forecast_url
JSON makes the saved location simple and readable.
def load_settings():
if not os.path.exists(SETTINGS_PATH):
return {}
with open(SETTINGS_PATH, "r", encoding="utf-8") as file:
return json.load(file)
def save_settings(settings):
with open(SETTINGS_PATH, "w", encoding="utf-8") as file:
json.dump(settings, file, indent=2)
file.write("\n")
The app keeps showing the menu until the user chooses quit.
def interactive_menu():
settings = load_settings()
while True:
print_header()
print_menu(settings)
choice = input("Select Option > ").strip().lower()
if choice == "1":
show_forecast_for_location(settings["location"], settings.get("count", 3))
elif choice == "q":
print("Goodbye.")
break
I tested the script with ZIP code 11234. The exact forecast changes over time,
but this confirmed the API request chain worked.
python3 weather.py --zip 11234
Weather forecast for New York, NY
=================================
Overnight
---------
Temp: 54°F
Wind: 5 mph W
Short: Mostly Clear
Details: Mostly clear, with a low around 54. West wind around 5 mph.
Saturday
--------
Temp: 77°F
Wind: 3 to 17 mph SW
Short: Sunny
Details: Sunny. High near 77, with temperatures falling to around 72 in the afternoon. Southwest wind 3 to 17 mph.
Saturday Night
--------------
Temp: 62°F
Wind: 8 to 17 mph SW
Short: Partly Cloudy
Details: Partly cloudy. Low around 62, with temperatures rising to around 65 overnight. Southwest wind 8 to 17 mph.
New York, NY
even when the ZIP code is inside Brooklyn. The script can prefer the ZIP lookup label if I
want the displayed location to be more specific.
The finished project is still small.
tiny-terminal-weather/
├── weather.py
├── README.md
├── .gitignore
└── weather_settings.json # generated locally, optional/private
This project is useful because it starts with one API request and grows into a real command-line tool.
The first Weather.gov request gives the app a forecast URL. The app then follows that URL to get the actual forecast periods.
A simple one-shot script can become a menu app with saved settings, validation, error handling, and direct command-line support.
AI assistance was useful for turning existing working code into a smaller teaching project, but the important part was understanding, testing, and documenting the result.
The current version works, but there are natural upgrades that would make it even more useful.
--short output mode.This project shows how a small script becomes a real tool. The first version proved the Weather.gov API worked. The advanced version adds an interactive menu, saved settings, direct command-line mode, input validation, and cleaner error handling. It is still small, but it now feels like a reusable Linux terminal utility.