Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 64 additions & 26 deletions web_programming/current_weather.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,88 @@
import os
import requests

Check failure on line 2 in web_programming/current_weather.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F401)

web_programming/current_weather.py:2:8: F401 `requests` imported but unused
import asyncio
import aiohttp
import json

Check failure on line 5 in web_programming/current_weather.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F401)

web_programming/current_weather.py:5:8: F401 `json` imported but unused
from pprint import pprint
from datetime import datetime, timedelta

# Put your API key(s) here
OPENWEATHERMAP_API_KEY = ""
WEATHERSTACK_API_KEY = ""
# Load API keys from environment variables

Check failure on line 9 in web_programming/current_weather.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

web_programming/current_weather.py:1:1: I001 Import block is un-sorted or un-formatted
OPENWEATHERMAP_API_KEY = os.getenv("OPENWEATHERMAP_API_KEY")
WEATHERSTACK_API_KEY = os.getenv("WEATHERSTACK_API_KEY")

# Define the URL for the APIs with placeholders
# Define the URL for the APIs
OPENWEATHERMAP_URL_BASE = "https://api.openweathermap.org/data/2.5/weather"
WEATHERSTACK_URL_BASE = "http://api.weatherstack.com/current"

# Cache to store recent responses
cache = {}
CACHE_DURATION = timedelta(minutes=5) # Cache duration

def current_weather(location: str) -> list[dict]:

async def fetch_weather(session, url, params):
async with session.get(url, params=params) as response:
response.raise_for_status() # Raises an error for bad responses
return await response.json()


async def current_weather(location: str) -> list[dict]:
"""
>>> current_weather("location")
Traceback (most recent call last):
...
ValueError: No API keys provided or no valid data returned.
Fetch current weather data from OpenWeatherMap and WeatherStack asynchronously.

Check failure on line 31 in web_programming/current_weather.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W293)

web_programming/current_weather.py:31:1: W293 Blank line contains whitespace
Raises:
ValueError: If no API keys are provided or no valid data is returned.

Check failure on line 34 in web_programming/current_weather.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W293)

web_programming/current_weather.py:34:1: W293 Blank line contains whitespace
Returns:
A list of dictionaries containing weather data.
"""
if not OPENWEATHERMAP_API_KEY and not WEATHERSTACK_API_KEY:
raise ValueError("No API keys provided.")

if location in cache and datetime.now() < cache[location]['expires']:

Check failure on line 41 in web_programming/current_weather.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (DTZ005)

web_programming/current_weather.py:41:30: DTZ005 `datetime.datetime.now()` called without a `tz` argument
return cache[location]['data']

weather_data = []
if OPENWEATHERMAP_API_KEY:
params_openweathermap = {"q": location, "appid": OPENWEATHERMAP_API_KEY}
response_openweathermap = requests.get(
OPENWEATHERMAP_URL_BASE, params=params_openweathermap, timeout=10
)
weather_data.append({"OpenWeatherMap": response_openweathermap.json()})
if WEATHERSTACK_API_KEY:
params_weatherstack = {"query": location, "access_key": WEATHERSTACK_API_KEY}
response_weatherstack = requests.get(
WEATHERSTACK_URL_BASE, params=params_weatherstack, timeout=10
)
weather_data.append({"Weatherstack": response_weatherstack.json()})
async with aiohttp.ClientSession() as session:
tasks = []

if OPENWEATHERMAP_API_KEY:
params_openweathermap = {"q": location, "appid": OPENWEATHERMAP_API_KEY}
tasks.append(fetch_weather(session, OPENWEATHERMAP_URL_BASE, params_openweathermap))

Check failure on line 50 in web_programming/current_weather.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E501)

web_programming/current_weather.py:50:89: E501 Line too long (96 > 88)

if WEATHERSTACK_API_KEY:
params_weatherstack = {"query": location, "access_key": WEATHERSTACK_API_KEY}

Check failure on line 53 in web_programming/current_weather.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E501)

web_programming/current_weather.py:53:89: E501 Line too long (89 > 88)
tasks.append(fetch_weather(session, WEATHERSTACK_URL_BASE, params_weatherstack))

Check failure on line 54 in web_programming/current_weather.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E501)

web_programming/current_weather.py:54:89: E501 Line too long (92 > 88)

responses = await asyncio.gather(*tasks, return_exceptions=True)

for i, response in enumerate(responses):

Check failure on line 58 in web_programming/current_weather.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (B007)

web_programming/current_weather.py:58:13: B007 Loop control variable `i` not used within loop body
if isinstance(response, Exception):
print(f"Error fetching data: {response}")
continue
weather_data.append(response)

if not weather_data:
raise ValueError("No API keys provided or no valid data returned.")
raise ValueError("No valid data returned.")

# Cache the response
cache[location] = {
'data': weather_data,
'expires': datetime.now() + CACHE_DURATION
}

return weather_data


if __name__ == "__main__":
from pprint import pprint

location = "to be determined..."
while location:
location = input("Enter a location (city name or latitude,longitude): ").strip()
if location:
try:
weather_data = current_weather(location)
weather_data = asyncio.run(current_weather(location))
for forecast in weather_data:
pprint(forecast)
except ValueError as e:
print(repr(e))
location = ""
except Exception as e:
print(f"An unexpected error occurred: {repr(e)}")
Loading