|
| 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