|
| 1 | +import os |
1 | 2 | import requests
|
| 3 | +import asyncio |
| 4 | +import aiohttp |
| 5 | +import json |
| 6 | +from pprint import pprint |
| 7 | +from datetime import datetime, timedelta |
2 | 8 |
|
3 |
| -# Put your API key(s) here |
4 |
| -OPENWEATHERMAP_API_KEY = "" |
5 |
| -WEATHERSTACK_API_KEY = "" |
| 9 | +# Load API keys from environment variables |
| 10 | +OPENWEATHERMAP_API_KEY = os.getenv("OPENWEATHERMAP_API_KEY") |
| 11 | +WEATHERSTACK_API_KEY = os.getenv("WEATHERSTACK_API_KEY") |
6 | 12 |
|
7 |
| -# Define the URL for the APIs with placeholders |
| 13 | +# Define the URL for the APIs |
8 | 14 | OPENWEATHERMAP_URL_BASE = "https://api.openweathermap.org/data/2.5/weather"
|
9 | 15 | WEATHERSTACK_URL_BASE = "http://api.weatherstack.com/current"
|
10 | 16 |
|
| 17 | +# Cache to store recent responses |
| 18 | +cache = {} |
| 19 | +CACHE_DURATION = timedelta(minutes=5) # Cache duration |
11 | 20 |
|
12 |
| -def current_weather(location: str) -> list[dict]: |
| 21 | + |
| 22 | +async def fetch_weather(session, url, params): |
| 23 | + async with session.get(url, params=params) as response: |
| 24 | + response.raise_for_status() # Raises an error for bad responses |
| 25 | + return await response.json() |
| 26 | + |
| 27 | + |
| 28 | +async def current_weather(location: str) -> list[dict]: |
13 | 29 | """
|
14 |
| - >>> current_weather("location") |
15 |
| - Traceback (most recent call last): |
16 |
| - ... |
17 |
| - ValueError: No API keys provided or no valid data returned. |
| 30 | + Fetch current weather data from OpenWeatherMap and WeatherStack asynchronously. |
| 31 | + |
| 32 | + Raises: |
| 33 | + ValueError: If no API keys are provided or no valid data is returned. |
| 34 | + |
| 35 | + Returns: |
| 36 | + A list of dictionaries containing weather data. |
18 | 37 | """
|
| 38 | + if not OPENWEATHERMAP_API_KEY and not WEATHERSTACK_API_KEY: |
| 39 | + raise ValueError("No API keys provided.") |
| 40 | + |
| 41 | + if location in cache and datetime.now() < cache[location]['expires']: |
| 42 | + return cache[location]['data'] |
| 43 | + |
19 | 44 | weather_data = []
|
20 |
| - if OPENWEATHERMAP_API_KEY: |
21 |
| - params_openweathermap = {"q": location, "appid": OPENWEATHERMAP_API_KEY} |
22 |
| - response_openweathermap = requests.get( |
23 |
| - OPENWEATHERMAP_URL_BASE, params=params_openweathermap, timeout=10 |
24 |
| - ) |
25 |
| - weather_data.append({"OpenWeatherMap": response_openweathermap.json()}) |
26 |
| - if WEATHERSTACK_API_KEY: |
27 |
| - params_weatherstack = {"query": location, "access_key": WEATHERSTACK_API_KEY} |
28 |
| - response_weatherstack = requests.get( |
29 |
| - WEATHERSTACK_URL_BASE, params=params_weatherstack, timeout=10 |
30 |
| - ) |
31 |
| - weather_data.append({"Weatherstack": response_weatherstack.json()}) |
| 45 | + async with aiohttp.ClientSession() as session: |
| 46 | + tasks = [] |
| 47 | + |
| 48 | + if OPENWEATHERMAP_API_KEY: |
| 49 | + params_openweathermap = {"q": location, "appid": OPENWEATHERMAP_API_KEY} |
| 50 | + tasks.append(fetch_weather(session, OPENWEATHERMAP_URL_BASE, params_openweathermap)) |
| 51 | + |
| 52 | + if WEATHERSTACK_API_KEY: |
| 53 | + params_weatherstack = {"query": location, "access_key": WEATHERSTACK_API_KEY} |
| 54 | + tasks.append(fetch_weather(session, WEATHERSTACK_URL_BASE, params_weatherstack)) |
| 55 | + |
| 56 | + responses = await asyncio.gather(*tasks, return_exceptions=True) |
| 57 | + |
| 58 | + for i, response in enumerate(responses): |
| 59 | + if isinstance(response, Exception): |
| 60 | + print(f"Error fetching data: {response}") |
| 61 | + continue |
| 62 | + weather_data.append(response) |
| 63 | + |
32 | 64 | if not weather_data:
|
33 |
| - raise ValueError("No API keys provided or no valid data returned.") |
| 65 | + raise ValueError("No valid data returned.") |
| 66 | + |
| 67 | + # Cache the response |
| 68 | + cache[location] = { |
| 69 | + 'data': weather_data, |
| 70 | + 'expires': datetime.now() + CACHE_DURATION |
| 71 | + } |
| 72 | + |
34 | 73 | return weather_data
|
35 | 74 |
|
36 | 75 |
|
37 | 76 | if __name__ == "__main__":
|
38 |
| - from pprint import pprint |
39 |
| - |
40 | 77 | location = "to be determined..."
|
41 | 78 | while location:
|
42 | 79 | location = input("Enter a location (city name or latitude,longitude): ").strip()
|
43 | 80 | if location:
|
44 | 81 | try:
|
45 |
| - weather_data = current_weather(location) |
| 82 | + weather_data = asyncio.run(current_weather(location)) |
46 | 83 | for forecast in weather_data:
|
47 | 84 | pprint(forecast)
|
48 | 85 | except ValueError as e:
|
49 | 86 | print(repr(e))
|
50 |
| - location = "" |
| 87 | + except Exception as e: |
| 88 | + print(f"An unexpected error occurred: {repr(e)}") |
0 commit comments