Weather applications have become essential tools for quickly checking current conditions and forecasts.
In this article, we will build a simple yet powerful weather application that leverages two open-source technologies: PySide6 for the graphical user interface (GUI) and Open-Meteo for weather data retrieval.
Our application allows users to enter a city name, automatically fetches the corresponding geographic coordinates using a geocoding API, and then retrieves detailed weather parameters—all without needing an API key!
The full source code is available at the end of the article.
What Is PySide6?
PySide6 is the official set of Python bindings for the Qt framework.
Qt is widely known for its ability to create cross-platform, native-looking GUIs. With PySide6, developers can easily build interactive applications with:
- Widgets: Buttons, labels, input fields, and more.
- Layouts: Arrange widgets in a structured, responsive manner.
- Signals and Slots: A robust event-handling system for responding to user actions.
PySide6 empowers Python developers to create modern desktop applications with ease and flexibility.
What Is Open-Meteo.com?
Open-Meteo is an open-source weather API that provides free real-time and forecast weather data without requiring an API key.
This accessibility makes it an excellent choice for developers looking to integrate weather data into their applications.
Open-Meteo offers a variety of parameters such as temperature, apparent temperature, surface pressure, wind speed, wind direction, and weather codes—all of which we will utilize in our application.
Building the Code: Architecture Overview
Our application is structured into several key components:
- Imports: We import the necessary libraries for our GUI and API calls.
- Get Weather Description: A helper function that translates numerical weather codes into human-readable descriptions.
- WeatherApp Class and Setup UI: This class encapsulates the entire application, building the UI and handling events.
- Search City: A method that uses the Open-Meteo Geocoding API to convert a city name into geographic coordinates.
- Fetch Weather: A method that retrieves current weather data from Open-Meteo based on the provided coordinates.
- Main Function: The entry point of our application, responsible for initializing and running the GUI.
Let’s now go through each section of the code in detail.
Imports
We start by importing the required modules after we have installed them:
pip install requests pyside6
The requests
library handles HTTP requests, while PySide6 provides all the tools needed for GUI creation.
import sys
import requests
from PySide6.QtWidgets import (
QApplication,
QWidget,
QVBoxLayout,
QHBoxLayout,
QLabel,
QLineEdit,
QPushButton,
QMessageBox,
)
from PySide6.QtCore import Qt
- sys: Used to access command-line arguments and exit the application.
- requests: For making HTTP calls to the Open-Meteo and geocoding APIs.
- PySide6 Modules: These modules provide widgets, layouts, and message boxes for our GUI.
Get Weather Description
The helper function get_weather_description
translates numeric weather codes from Open-Meteo into descriptive text.
This makes the output more understandable for the user.
def get_weather_description(code: int) -> str:
"""Convert Open-Meteo weather code to a textual description."""
if code == 0:
return "Clear sky"
elif code in (1, 2, 3):
return "Mainly clear/partly cloudy/overcast"
elif code in (45, 48):
return "Fog"
elif code in (51, 53, 55):
return "Drizzle"
elif code in (56, 57):
return "Freezing Drizzle"
elif code in (61, 63, 65):
return "Rain"
elif code in (66, 67):
return "Freezing Rain"
elif code in (71, 73, 75):
return "Snow fall"
elif code == 77:
return "Snow grains"
elif code in (80, 81, 82):
return "Rain showers"
elif code in (85, 86):
return "Snow showers"
elif code == 95:
return "Thunderstorm"
elif code in (96, 99):
return "Thunderstorm with hail"
else:
return "Unknown weather"
This function checks the input weather code against known values and returns a descriptive string.
Class WeatherApp and Setup UI
The core of our application is encapsulated in the WeatherApp
class, which inherits from QWidget
.
The constructor sets the window title and initializes the user interface by calling the setup_ui
method.
class WeatherApp(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Weather Application")
self.setup_ui()
Setup UI
The setup_ui
method constructs the user interface, dividing it into logical sections.
def setup_ui(self):
layout = QVBoxLayout()
# --- City Search Section ---
city_layout = QHBoxLayout()
self.city_input = QLineEdit()
self.city_input.setPlaceholderText("Enter city name (e.g., Berlin)")
city_layout.addWidget(self.city_input)
self.search_button = QPushButton("Search City")
self.search_button.clicked.connect(self.search_city)
city_layout.addWidget(self.search_button)
layout.addLayout(city_layout)
# --- Coordinates Input Section ---
coords_layout = QHBoxLayout()
self.lat_input = QLineEdit()
self.lat_input.setPlaceholderText("Latitude (e.g., 52.52)")
coords_layout.addWidget(self.lat_input)
self.lon_input = QLineEdit()
self.lon_input.setPlaceholderText("Longitude (e.g., 13.41)")
coords_layout.addWidget(self.lon_input)
layout.addLayout(coords_layout)
# --- Weather Fetch Button ---
self.fetch_button = QPushButton("Get Weather")
self.fetch_button.clicked.connect(self.fetch_weather)
layout.addWidget(self.fetch_button)
# --- Weather Display Section ---
self.weather_label = QLabel("Weather information will appear here.")
self.weather_label.setAlignment(Qt.AlignCenter)
layout.addWidget(self.weather_label)
self.setLayout(layout)
The method organizes various UI components using layouts to create a structured and interactive interface. Here's a detailed breakdown:
- Layout Initialization:
- A vertical layout (
QVBoxLayout
) is created to arrange the main sections of the UI vertically.
- A vertical layout (
- City Search Section:
- A horizontal layout (
QHBoxLayout
) is created to hold the city search components. - A
QLineEdit
widget (self.city_input
) is added for entering the city name, with a placeholder text "Enter city name (e.g., Berlin)". - A
QPushButton
widget (self.search_button
) labeled "Search City" is added. Clicking this button triggers thesearch_city
method. - Both the input field and the button are added to the horizontal layout, which is then added to the main vertical layout.
- A horizontal layout (
- Coordinates Input Section:
- Another horizontal layout (
QHBoxLayout
) is created to hold the coordinates input components. - Two
QLineEdit
widgets (self.lat_input
andself.lon_input
) are added for entering latitude and longitude, with placeholder texts "Latitude (e.g., 52.52)" and "Longitude (e.g., 13.41)", respectively. - Both input fields are added to the horizontal layout, which is then added to the main vertical layout.
- Another horizontal layout (
- Weather Fetch Button:
- A
QPushButton
widget (self.fetch_button
) labeled "Get Weather" is added. Clicking this button triggers thefetch_weather
method. - The button is added directly to the main vertical layout.
- A
- Weather Display Section:
- A
QLabel
widget (self.weather_label
) is added to display weather information. It initially shows the text "Weather information will appear here." and is centered usingQt.AlignCenter
. - The label is added to the main vertical layout.
- A
- Final Layout Setting:
- The main vertical layout (
layout
) is set as the layout for the widget usingself.setLayout(layout)
.
- The main vertical layout (
Search City (Using Geocoding API)
The search_city
method enables the conversion of a city name into geographic coordinates using the Open-Meteo Geocoding API.
This is crucial because the weather API requires latitude and longitude.
def search_city(self):
"""
Searches for the city coordinates using the Open-Meteo Geocoding API
and fills in the latitude and longitude fields if a match is found.
"""
city_name = self.city_input.text().strip()
if not city_name:
QMessageBox.warning(self, "Input Error", "Please enter a city name.")
return
geocoding_url = f"https://geocoding-api.open-meteo.com/v1/search?name={city_name}&count=1"
try:
response = requests.get(geocoding_url, timeout=10)
response.raise_for_status()
data = response.json()
if "results" in data and data["results"]:
result = data["results"][0]
lat = result.get("latitude")
lon = result.get("longitude")
name = result.get("name")
country = result.get("country")
# Update the coordinate input fields.
self.lat_input.setText(str(lat))
self.lon_input.setText(str(lon))
QMessageBox.information(
self,
"City Found",
f"Found {name}, {country}.\nCoordinates set to {lat}, {lon}.",
)
else:
QMessageBox.information(self, "No Results", "No matching city was found.")
except requests.RequestException as e:
QMessageBox.critical(self, "Network Error", f"An error occurred: {e}")
The primary purpose of this method is to search for the coordinates of a city using the Open-Meteo Geocoding API and update the application's latitude and longitude fields if a match is found.
- Input Validation:
- The method begins by retrieving the text from a
city_input
widget, which is expected to be aQLineEdit
field where the user enters a city name. - It checks if the
city_name
is empty. If so, it displays a warning message box prompting the user to enter a city name and returns early, preventing further execution.
- The method begins by retrieving the text from a
- API Request:
- The method constructs a URL for the Open-Meteo Geocoding API, including the city name as a query parameter.
- It makes an HTTP GET request to this URL with a timeout of 10 seconds using the
requests
library. - The method handles potential network errors by catching
requests.RequestException
and displaying a critical message box with the error details if an exception occurs.
- Processing the Response:
- If the API request is successful, the method parses the JSON response.
- It checks if the response contains a "results" key and if this key has any data.
- If a match is found, it extracts the latitude, longitude, name, and country from the first result.
- The method then updates the
lat_input
andlon_input
widgets with the retrieved coordinates and displays an information message box confirming the city and its coordinates. - If no matching city is found, it displays an information message box indicating that no results were found.
Fetch Weather
The fetch_weather
method retrieves current weather data for the specified coordinates from Open-Meteo.
The API call requests parameters such as temperature, apparent temperature, surface pressure, wind speed, wind direction, and a weather code.
This article is for subscribers only
To continue reading this article, just register your email and we will send you access.
Subscribe NowAlready have an account? Sign In