replacing urllib.request with requests

This commit is contained in:
Mark McIntyre 2022-09-17 16:59:25 -04:00
parent 62586e2de6
commit 74a5f5a710

View File

@ -1,49 +1,109 @@
import json import json
import urllib import requests
import re import re
import datetime import datetime
import dateutil.parser as dp
class WeatherApi: class WeatherApi:
def __init__(self): def __init__(self, nick):
self.nick = nick
self.weather_api_url = "https://api.weatherapi.com/v1" self.weather_api_url = "https://api.weatherapi.com/v1"
self.api_key_filename = "./weather_api_key.txt" self.api_key_filename = "./weather_api_key.txt"
read_api_key() self.user_preferences_filename = "./weather_user_preferences.json"
self.read_api_key()
self.unit_suffices = {
'metric': {
'temp': 'c',
'rate': 'kph',
'volume': 'mm',
'baro': 'mb',
'distance': 'km'
},
'imperial': {
'temp': 'f',
'rate': 'mph',
'volume': 'in',
'baro': 'in',
'distance': 'miles'
}
}
def read_api_key(self): def read_api_key(self):
with open(self.api_key_filename) as fp: with open(self.api_key_filename) as fp:
self.api_key = fp.read() api_key = fp.read()
self.api_key = api_key.strip()
def get_current_conditions(self, nick, location=None, units='metric'):
user_preferences = self.get_user_preferences(nick)
if not location:
location = user_preferences[nick]['location']
def get_current_conditions(self, units='metric'):
# URL for current conditions # URL for current conditions
current_url = f"{self.weather_api_url}/current.json?key={self.api_key}&q={location}&qai=no" current_url = f"{self.weather_api_url}/current.json?key={self.api_key}&q={location}&qai=no"
# Make the request and get the results # Make the request and get the results
current_request = urllib.request.urlopen(current_url) current_request = requests.get(current_url)
current_data = current_request.read() current_data = current_request.content
current_json = json.loads(current_data.decode('utf-8')) current_json = json.loads(current_data.decode('utf-8'))
# Different formats for different units # Different formats for different units
current_output_format = {} current = current_json['current']
current_output_format['metric'] = f"{location['name']}, {location['region']}, {location['country']} | {current['temp_c']}°C | {current['humidity']}% | {current['condition']['text']} | {current['wind_dir']} {current['wind_degree']}° {current['wind_kph']} kph" location = current_json['location']
current_output_format['imperial'] = f"{location['name']}, {location['region']}, {location['country']} | {current['temp_f']}°F | {current['humidity']}% | {current['condition']['text']} | {current['wind_dir']} {current['wind_degree']}° {current['wind_mph']} mph"
return current_output_format[units] current_output_location = f"{location['name']}, {location['region']}, {location['country']}"
temp = current[f"temp_{self.unit_suffices[units]['temp']}"]
wind_speed = current[f"wind_{self.unit_suffices[units]['rate']}"]
current_output_format = f"{current_output_location} | {temp}°{self.unit_suffices[units]['temp'].upper()} | {current['humidity']}% | {current['condition']['text']} | {current['wind_dir']} {current['wind_degree']}° {wind_speed} {self.unit_suffices[units]['rate']}"
return current_output_format
def get_user_preferences(self, nick): def get_user_preferences(self, nick):
# Read SQLite DB for default location and units for the nick provided try:
with open(self.user_preferences_filename) as fp:
user_preferences = json.load(fp)
except FileNotFoundError:
user_preferences = {
nick: {
'location': None,
'units': 'metric'
},
}
def set_user_preferences(self, nick, location=None, units='metric'): return user_preferences
# Set the default location and units for the nick in a SQLite DB
def set_user_preferences(self, nick, location=None, units=None):
user_preferences = self.get_user_preferences(nick)
# Only acceptable units are 'imperial' or 'metric' (no kelvin for now)
if not units or (units and units not in ['metric', 'imperial']):
units = 'metric'
user_preferences[nick]['units'] = units
if location:
user_preferences[nick]['location'] = location
with open(self.user_preferences_filename, 'w') as fp:
json.dump(user_preferences, fp)
def get_forecast(self, nick, location=None, days=5, units='metric'):
user_preferences = self.get_user_preferences(nick)
if not location:
location = user_preferences[nick]['location']
def get_forecast(self, days=4, units='metric'):
# URL for current conditions # URL for current conditions
forecast_url = f"{self.weather_api_url}/forecast.json?key={self.api_key}&q={location}&days={days}&qai=no" forecast_url = f"{self.weather_api_url}/forecast.json?key={self.api_key}&q={location}&days={days}&qai=no"
# Make the request and get the results # Make the request and get the results
forecast_request = urllib.request.urlopen(forecast_url) forecast_request = requests.get(forecast_url)
forecast_data = forecast_request.read() forecast_data = forecast_request.content
forecast_json = json.loads(forecast_data.decode('utf-8')) forecast_json = json.loads(forecast_data.decode('utf-8'))
location = forecast_json['location'] location = forecast_json['location']
forecast = forecast_json['forecast']['forecastday'] forecast = forecast_json['forecast']['forecastday']
@ -55,15 +115,16 @@ class WeatherApi:
# Set the initial high and low values to absurd values # Set the initial high and low values to absurd values
daily_temp_range = { daily_temp_range = {
'day': day['date'], 'day': day['date'],
'high': 10000.0, 'day_of_week': datetime.datetime.strftime(dp.parse(day['date']), '%a'),
'low': -10000.0, 'high': -10000.0,
'low': 10000.0,
'conditions': '' 'conditions': ''
}} }
for hour in day['hour']: for hour in day['hour']:
temp = day['hour']['temp_c'] if units == 'metric' else day['hour']['temp_f'] temp = hour[f"temp_{self.unit_suffices[units]['temp']}"]
if temp > daily_temp_range['high']: if temp >= daily_temp_range['high']:
daily_temp_range['high'] = temp daily_temp_range['high'] = temp
# We only want the conditions for when the temp is the highest # We only want the conditions for when the temp is the highest
daily_temp_range['conditions'] = hour['condition']['text'] daily_temp_range['conditions'] = hour['condition']['text']
@ -71,12 +132,17 @@ class WeatherApi:
if temp < daily_temp_range['low']: if temp < daily_temp_range['low']:
daily_temp_range['low'] = temp daily_temp_range['low'] = temp
forecast_temps.append(daily_temp_range)
# Different formats for different units # Different formats for different units
forecast_output_format = {} forecast_output_location = f"{location['name']}, {location['region']}, {location['country']}"
forecast_output_format['metric'] = f"{location['name']}, {location['region']}, {location['country']} | {current['temp_c']}°C | {current['humidity']}% | {current['condition']['text']} | {current['wind_dir']} {current['wind_degree']}° {current['wind_kph']} kph" forecast_days = ""
forecast_output_format['imperial'] = f"{location['name']}, {location['region']}, {location['country']} | {current['temp_f']}°F | {current['humidity']}% | {current['condition']['text']} | {current['wind_dir']} {current['wind_degree']}° {current['wind_mph']} mph"
return current_output_format[units] for forecast_temp in forecast_temps:
forecast_days += f" | {forecast_temp['day_of_week']} - {forecast_temp['high']}°{self.unit_suffices[units]['temp'].upper()}/{forecast_temp['low']}°{self.unit_suffices[units]['temp'].upper()} - {forecast_temp['conditions']}"
forecast_output_format = f"{forecast_output_location}{forecast_days}"
return forecast_output_format