def weather(text, reply): """weather <location> -- Gets weather data for <location>.""" if not wunder_key: return "This command requires a Weather Underground API key." if not dev_key: return "This command requires a Google Developers Console API key." # use find_location to get location data from the user input try: location_data = find_location(text) except APIError as e: return e formatted_location = "{lat},{lng}".format(**location_data) url = wunder_api.format(wunder_key, formatted_location) response = requests.get(url).json() if response['response'].get('error'): return "{}".format(response['response']['error']['description']) forecast_today = response["forecast"]["simpleforecast"]["forecastday"][0] forecast_tomorrow = response["forecast"]["simpleforecast"]["forecastday"][1] # put all the stuff we want to use in a dictionary for easy formatting of the output weather_data = { "place" : response['current_observation']['display_location']['full'], "conditions" : response['current_observation']['weather'], "temp_f" : response['current_observation']['temp_f'], "temp_c" : response['current_observation']['temp_c'], "humidity" : response['current_observation']['relative_humidity'], "wind_kph" : response['current_observation']['wind_kph'], "wind_mph" : response['current_observation']['wind_mph'], "wind_direction" : response['current_observation']['wind_dir'], "today_conditions" : forecast_today['conditions'], "today_high_f" : forecast_today['high']['fahrenheit'], "today_high_c" : forecast_today['high']['celsius'], "today_low_f" : forecast_today['low']['fahrenheit'], "today_low_c" : forecast_today['low']['celsius'], "tomorrow_conditions": forecast_tomorrow['conditions'], "tomorrow_high_f" : forecast_tomorrow['high']['fahrenheit'], "tomorrow_high_c" : forecast_tomorrow['high']['celsius'], "tomorrow_low_f" : forecast_tomorrow['low']['fahrenheit'], "tomorrow_low_c" : forecast_tomorrow['low']['celsius'] } # Get the more accurate URL if available, if not, get the generic one. if "?query=," in response["current_observation"]['ob_url']: weather_data['url'] = web.shorten(response["current_observation"]['forecast_url']) else: weather_data['url'] = web.shorten(response["current_observation"]['ob_url']) reply("{place} - \x02Current:\x02 {conditions}, {temp_f}F/{temp_c}C, {humidity}, " "Wind: {wind_mph}MPH/{wind_kph}KPH {wind_direction}, \x02Today:\x02 {today_conditions}, " "High: {today_high_f}F/{today_high_c}C, Low: {today_low_f}F/{today_low_c}C. " "\x02Tomorrow:\x02 {tomorrow_conditions}, High: {tomorrow_high_f}F/{tomorrow_high_c}C, " "Low: {tomorrow_low_f}F/{tomorrow_low_c}C - {url}".format(**weather_data))
def test_isgd_errors(mock_requests): mock_requests.add(mock_requests.GET, 'http://is.gd/create.php', status=429) from cloudbot.util import web with pytest.raises(web.ServiceHTTPError): web.shorten('https://example.com', service='is.gd') mock_requests.reset() with pytest.raises(web.ServiceError): web.shorten('https://example.com', service='is.gd')
def weather(text, reply): """weather <location> -- Gets weather data for <location>.""" if not wunder_key: return "This command requires a Weather Underground API key." if not dev_key: return "This command requires a Google Developers Console API key." # use find_location to get location data from the user input try: location_data = find_location(text) except APIError as e: return e formatted_location = "{lat},{lng}".format(**location_data) url = wunder_api.format(wunder_key, formatted_location) response = requests.get(url).json() if response['response'].get('error'): return "{}".format(response['response']['error']['description']) forecast_today = response["forecast"]["simpleforecast"]["forecastday"][0] forecast_tomorrow = response["forecast"]["simpleforecast"]["forecastday"][1] # put all the stuff we want to use in a dictionary for easy formatting of the output weather_data = { "place": response['current_observation']['display_location']['full'], "conditions": response['current_observation']['weather'], "temp_f": response['current_observation']['temp_f'], "temp_c": response['current_observation']['temp_c'], "humidity": response['current_observation']['relative_humidity'], "wind_kph": response['current_observation']['wind_kph'], "wind_mph": response['current_observation']['wind_mph'], "wind_direction": response['current_observation']['wind_dir'], "today_conditions": forecast_today['conditions'], "today_high_f": forecast_today['high']['fahrenheit'], "today_high_c": forecast_today['high']['celsius'], "today_low_f": forecast_today['low']['fahrenheit'], "today_low_c": forecast_today['low']['celsius'], "tomorrow_conditions": forecast_tomorrow['conditions'], "tomorrow_high_f": forecast_tomorrow['high']['fahrenheit'], "tomorrow_high_c": forecast_tomorrow['high']['celsius'], "tomorrow_low_f": forecast_tomorrow['low']['fahrenheit'], "tomorrow_low_c": forecast_tomorrow['low']['celsius'] } # Get the more accurate URL if available, if not, get the generic one. if "?query=," in response["current_observation"]['ob_url']: weather_data['url'] = web.shorten(response["current_observation"]['forecast_url']) else: weather_data['url'] = web.shorten(response["current_observation"]['ob_url']) reply("{place} - \x02Current:\x02 {conditions}, {temp_f}F/{temp_c}C, {humidity}, " "Wind: {wind_kph}KPH/{wind_mph}MPH {wind_direction}, \x02Today:\x02 {today_conditions}, " "High: {today_high_f}F/{today_high_c}C, Low: {today_low_f}F/{today_low_c}C. " "\x02Tomorrow:\x02 {tomorrow_conditions}, High: {tomorrow_high_f}F/{tomorrow_high_c}C, " "Low: {tomorrow_low_f}F/{tomorrow_low_c}C - {url}".format(**weather_data))
def shorten(text): """<url> [custom] - shortens a url with [custom] as an optional custom shortlink""" args = text.split() url = args[0] custom = args[1] if len(args) > 1 else None try: return web.shorten(url, custom=custom) except web.ServiceError as e: return e.message
def books(text): """books <query> -- Searches Google Books for <query>.""" if not dev_key: return "This command requires a Google Developers Console API key." json = requests.get(book_search_api, params={ "q": text, "key": dev_key, "country": "US" }).json() if json.get('error'): if json['error']['code'] == 403: print(json['error']['message']) return "The Books API is off in the Google Developers Console (or check the console)." else: return 'Error performing search.' if json['totalItems'] == 0: return 'No results found.' book = json['items'][0]['volumeInfo'] title = book['title'] try: author = book['authors'][0] except KeyError: try: author = book['publisher'] except KeyError: author = "Unknown Author" try: description = formatting.truncate_str(book['description'], 130) except KeyError: description = "No description available." try: year = book['publishedDate'][:4] except KeyError: year = "No Year" try: page_count = book['pageCount'] pages = ' - \x02{:,}\x02 page{}'.format(page_count, "s"[page_count == 1:]) except KeyError: pages = '' link = web.shorten(book['infoLink'], service="goo.gl", key=dev_key) return "\x02{}\x02 by \x02{}\x02 ({}){} - {} - {}".format( title, author, year, pages, description, link)
def isgd(text): """<url> [custom] - shortens a url using is.gd with [custom] as an optional custom shortlink, or unshortens <url> if already short""" args = text.split() url = args[0] custom = args[1] if len(args) > 1 else None try: if 'is.gd' in url: return web.expand(url, 'is.gd') else: return web.shorten(url, custom, 'is.gd') except web.ServiceError as e: return e.message
def gitio(text): """<url> [custom] - shortens a github URL <url> using git.io with [custom] as an optional custom shortlink, or unshortens <url> if already short""" args = text.split() url = args[0] custom = args[1] if len(args) > 1 else None try: if 'git.io' in url: return web.expand(url, 'git.io') else: return web.shorten(url, custom, 'git.io') except web.ServiceError as e: return e.message
def weather(text, reply): """weather <location> -- Gets weather data for <location>.""" if not wunder_key: return "This command requires a Weather Underground API key." if not dev_key: return "This command requires a Google Developers Console API key." # use find_location to get location data from the user input try: location_data = find_location(text) except APIError as e: return e formatted_location = "{lat},{lng}".format(**location_data) url = wunder_api.format(wunder_key, formatted_location) response = requests.get(url).json() if response['response'].get('error'): return "{}".format(response['response']['error']['description']) #forecast_today = response["forecast"]["simpleforecast"]["forecastday"][0] #forecast_tomorrow = response["forecast"]["simpleforecast"]["forecastday"][1] # put all the stuff we want to use in a dictionary for easy formatting of the output weather_data = { "place": response['current_observation']['display_location']['full'], "conditions": response['current_observation']['weather'], "temp_f": response['current_observation']['temp_f'], "temp_c": response['current_observation']['temp_c'] } # Get the more accurate URL if available, if not, get the generic one. if "?query=," in response["current_observation"]['ob_url']: weather_data['url'] = web.shorten(response["current_observation"]['forecast_url']) else: weather_data['url'] = web.shorten(response["current_observation"]['ob_url']) reply("{place} - \x02Current:\x02 {conditions}, {temp_f}F/{temp_c}C".format(**weather_data))
def googl(text, reply): """<url> [custom] - shorten <url> using goo.gl with [custom] as an option custom shortlink, or unshortens <url> if already short""" args = text.split() url = args[0] custom = args[1] if len(args) > 1 else None try: if 'goo.gl' in url: return web.expand(url, 'goo.gl') else: return web.shorten(url, custom, 'goo.gl') except web.ServiceError as e: reply(e.message) raise
def books(text): """books <query> -- Searches Google Books for <query>.""" if not dev_key: return "This command requires a Google Developers Console API key." json = requests.get(book_search_api, params={"q": text, "key": dev_key, "country": "US"}).json() if json.get('error'): if json['error']['code'] == 403: print(json['error']['message']) return "The Books API is off in the Google Developers Console (or check the console)." else: return 'Error performing search.' if json['totalItems'] == 0: return 'No results found.' book = json['items'][0]['volumeInfo'] title = book['title'] try: author = book['authors'][0] except KeyError: try: author = book['publisher'] except KeyError: author = "Unknown Author" try: description = formatting.truncate_str(book['description'], 130) except KeyError: description = "No description available." try: year = book['publishedDate'][:4] except KeyError: year = "No Year" try: page_count = book['pageCount'] pages = ' - \x02{:,}\x02 page{}'.format(page_count, "s"[page_count == 1:]) except KeyError: pages = '' link = web.shorten(book['infoLink'], service="goo.gl", key=dev_key) return "\x02{}\x02 by \x02{}\x02 ({}){} - {} - {}".format(title, author, year, pages, description, link)
def malmsearch(text, reply, bot): text = urllib.parse.quote(text) try: user = bot.config.get("api_keys", {}).get("mal_user", None) password = bot.config.get("api_keys", {}).get("mal_pass", None) except: reply("No api key found.") url = 'https://myanimelist.net/api/manga/search.xml?q={}'.format(text) try: request = requests.get(url, auth=(user, password)) except Exception as c: reply('Error: {}'.format(c)) soup = BeautifulSoup(request.text) title = http.strip_html(soup.find('title')) chapters = http.strip_html(soup.find('chapters')) mtype = http.strip_html(soup.find('type')) score = http.strip_html(soup.find('score')) status = http.strip_html(soup.find('status')) start_date = http.strip_html(soup.find('start_date')) end_date = http.strip_html(soup.find('end_date')) if end_date == '0000-00-00' and status is not 'Publishing': end_date = 'has not ended' elif status == 'Publishing': end_date = 'will end on {}'.format(end_date) else: end_date = 'ended {}'.format(end_date) id = http.strip_html(soup.find('id')) url = web.shorten( 'https://' + urllib.parse.quote('myanimelist.net/manga/{}/{}'.format(id, title))) reply('{}, {}, {}, {} chapters. {}, started {}, {}. {}'.format( title, mtype, score, chapters, status, start_date, end_date, url))
def wow_armoury_format(data, link): """Format armoury data into a human readable string""" if data.status_code != 200 and data.status_code != 404: # The page returns 404 if the character or realm is not found. try: data.raise_for_status() except Exception as e: return 'An error occurred while trying to fetch the data. ({})'.format(str(e)) data = data.json() if len(data) == 0: return 'Could not find any results.' if 'reason' in data: # Something went wrong (i.e. realm does not exist, character does not exist, or page not found). return data['reason'] if 'name' in data: niceurl = link.replace('/api/wow/', '/wow/en/') + '/simple' try: return '{0} is a level \x0307{1}\x0F {2} {3} on {4} with \x0307{5}\x0F achievement points and \x0307{6}' \ '\x0F honourable kills. Armoury Profile: {7}' \ .format(data['name'], data['level'], wow_get_gender(data['gender']), wow_get_class(data['class'], True), data['realm'], data['achievementPoints'], data['totalHonorableKills'], web.shorten(niceurl)) except Exception as e: return 'Unable to fetch information for {}. Does the realm or character exist? ({})'.format(niceurl, str(e)) return 'An unexpected error occurred.'
def weather(text, reply, db, nick, bot, notice): """weather <location> [dontsave] -- Gets weather data for <location> from Wunderground.""" api_key = bot.config.get("api_keys", {}).get("wunderground") if not api_key: return "Error: No wunderground API details." # initialise weather DB db.execute("create table if not exists weather(nick primary key, loc)") # if there is no input, try getting the users last location from the DB if not text: location = db.execute("select loc from weather where nick=lower(:nick)", {"nick": nick}).fetchone() print(location) if not location: # no location saved in the database, send the user help text notice(weather.__doc__) return loc = location[0] # no need to save a location, we already have it dontsave = True else: # see if the input ends with "dontsave" dontsave = text.endswith(" dontsave") # remove "dontsave" from the input string after checking for it if dontsave: loc = text[:-9].strip().lower() else: loc = text location = http.quote_plus(loc) request_url = base_url.format(api_key, "geolookup/forecast/conditions", location) response = http.get_json(request_url) if 'location' not in response: try: location_id = response['response']['results'][0]['zmw'] except KeyError: return "Could not get weather for that location." # get the weather again, using the closest match request_url = base_url.format(api_key, "geolookup/forecast/conditions", "zmw:" + location_id) response = http.get_json(request_url) if response['location']['state']: place_name = "\x02{}\x02, \x02{}\x02 (\x02{}\x02)".format(response['location']['city'], response['location']['state'], response['location']['country']) else: place_name = "\x02{}\x02 (\x02{}\x02)".format(response['location']['city'], response['location']['country']) forecast_today = response["forecast"]["simpleforecast"]["forecastday"][0] forecast_tomorrow = response["forecast"]["simpleforecast"]["forecastday"][1] # put all the stuff we want to use in a dictionary for easy formatting of the output weather_data = { "place": place_name, "conditions": response['current_observation']['weather'], "temp_f": response['current_observation']['temp_f'], "temp_c": response['current_observation']['temp_c'], "humidity": response['current_observation']['relative_humidity'], "wind_kph": response['current_observation']['wind_kph'], "wind_mph": response['current_observation']['wind_mph'], "wind_direction": response['current_observation']['wind_dir'], "today_conditions": forecast_today['conditions'], "today_high_f": forecast_today['high']['fahrenheit'], "today_high_c": forecast_today['high']['celsius'], "today_low_f": forecast_today['low']['fahrenheit'], "today_low_c": forecast_today['low']['celsius'], "tomorrow_conditions": forecast_tomorrow['conditions'], "tomorrow_high_f": forecast_tomorrow['high']['fahrenheit'], "tomorrow_high_c": forecast_tomorrow['high']['celsius'], "tomorrow_low_f": forecast_tomorrow['low']['fahrenheit'], "tomorrow_low_c": forecast_tomorrow['low']['celsius'], "url": web.shorten(response["current_observation"]['forecast_url'] + "?apiref=e535207ff4757b18") } reply("{place} - \x02Current:\x02 {conditions}, {temp_f}F/{temp_c}C, {humidity}, " "Wind: {wind_kph}KPH/{wind_mph}MPH {wind_direction}, \x02Today:\x02 {today_conditions}, " "High: {today_high_f}F/{today_high_c}C, Low: {today_low_f}F/{today_low_c}C. " "\x02Tomorrow:\x02 {tomorrow_conditions}, High: {tomorrow_high_f}F/{tomorrow_high_c}C, " "Low: {tomorrow_low_f}F/{tomorrow_low_c}C - {url}".format(**weather_data)) if location and not dontsave: db.execute("insert or replace into weather(nick, loc) values (:nick, :loc)", {"nick": nick.lower(), "loc": loc}) db.commit()
def weather(text, reply, db, nick, bot, notice): """weather <location> -- Gets weather data for <location>.""" if not wunder_key: return "This command requires a Weather Underground API key." if not dev_key: return "This command requires a Google Developers Console API key." # initialise weather DB db.execute("create table if not exists weather(nick primary key, loc)") # if there is no input, try getting the users last location from the DB if not text: location = db.execute("select loc from weather where nick=lower(:nick)", {"nick": nick}).fetchone() if not location: # no location saved in the database, send the user help text notice(weather.__doc__) return loc = location[0] # no need to save a location, we already have it dontsave = True else: # see if the input ends with "dontsave" dontsave = text.endswith(" dontsave") # remove "dontsave" from the input string after checking for it if dontsave: loc = text[:-9].strip().lower() else: loc = text # use find_location to get location data from the user input try: location_data = find_location(loc) except APIError as e: return e formatted_location = "{lat},{lng}".format(**location_data) url = wunder_api.format(wunder_key, formatted_location) response = requests.get(url).json() if response['response'].get('error'): return "{}".format(response['response']['error']['description']) forecast_today = response["forecast"]["simpleforecast"]["forecastday"][0] forecast_tomorrow = response["forecast"]["simpleforecast"]["forecastday"][1] # put all the stuff we want to use in a dictionary for easy formatting of the output weather_data = { "place": response['current_observation']['display_location']['full'], "conditions": response['current_observation']['weather'], "temp_f": response['current_observation']['temp_f'], "temp_c": response['current_observation']['temp_c'], "humidity": response['current_observation']['relative_humidity'], "wind_kph": response['current_observation']['wind_kph'], "wind_mph": response['current_observation']['wind_mph'], "wind_direction": response['current_observation']['wind_dir'], "today_conditions": forecast_today['conditions'], "today_high_f": forecast_today['high']['fahrenheit'], "today_high_c": forecast_today['high']['celsius'], "today_low_f": forecast_today['low']['fahrenheit'], "today_low_c": forecast_today['low']['celsius'], "tomorrow_conditions": forecast_tomorrow['conditions'], "tomorrow_high_f": forecast_tomorrow['high']['fahrenheit'], "tomorrow_high_c": forecast_tomorrow['high']['celsius'], "tomorrow_low_f": forecast_tomorrow['low']['fahrenheit'], "tomorrow_low_c": forecast_tomorrow['low']['celsius'] } # Get the more accurate URL if available, if not, get the generic one. if "?query=," in response["current_observation"]['ob_url']: weather_data['url'] = web.shorten(response["current_observation"]['forecast_url']) else: weather_data['url'] = web.shorten(response["current_observation"]['ob_url']) if loc and not dontsave: db.execute("insert or replace into weather(nick, loc) values (:nick, :loc)", {"nick": nick.lower(), "loc": loc}) db.commit() reply("{place} - \x02Current:\x02 {conditions}, {temp_f}F/{temp_c}C, {humidity}, " "Wind: {wind_mph}MPH/{wind_kph}KPH {wind_direction}, \x02Today:\x02 {today_conditions}, " "High: {today_high_f}F/{today_high_c}C, Low: {today_low_f}F/{today_low_c}C. " "\x02Tomorrow:\x02 {tomorrow_conditions}, High: {tomorrow_high_f}F/{tomorrow_high_c}C, " "Low: {tomorrow_low_f}F/{tomorrow_low_c}C - {url}".format(**weather_data))
def test_shorten(mock_requests): mock_requests.add(mock_requests.GET, 'http://is.gd/create.php', json={'shorturl': 'https://is.gd/foobar'}) from cloudbot.util import web assert web.shorten('https://example.com', service='is.gd') == 'https://is.gd/foobar' assert web.Shortener().shorten( 'https://example.com') == 'https://example.com' with pytest.raises(web.ServiceError): web.shorten('https://example.com', service='goo.gl') mock_requests.add(mock_requests.POST, 'https://www.googleapis.com/urlshortener/v1/url', json={}, status=requests.codes.bad_request) with pytest.raises(web.ServiceHTTPError): web.shorten('https://example.com', service='goo.gl') mock_requests.replace(mock_requests.POST, 'https://www.googleapis.com/urlshortener/v1/url', json={'error': { 'message': 'Error' }}) with pytest.raises(web.ServiceHTTPError): web.shorten('https://example.com', service='goo.gl') mock_requests.replace(mock_requests.POST, 'https://www.googleapis.com/urlshortener/v1/url', json={'id': 'https://goo.gl/foobar'}) assert web.shorten('https://example.com', service='goo.gl') == 'https://goo.gl/foobar' with pytest.raises(web.ServiceError): web.shorten('https://example.com', service='git.io') mock_requests.add( mock_requests.POST, 'http://git.io', status=400, ) with pytest.raises(web.ServiceHTTPError): web.shorten('https://example.com', service='git.io') mock_requests.replace(mock_requests.POST, 'http://git.io', body='error') with pytest.raises(web.ServiceHTTPError): web.shorten('https://example.com', service='git.io') mock_requests.replace(mock_requests.POST, 'http://git.io', body='error') with pytest.raises(web.ServiceHTTPError): web.shorten('https://example.com', service='git.io') mock_requests.replace(mock_requests.POST, 'http://git.io', headers={'Location': 'http://git.io/foobar123'}, status=requests.codes.created) assert web.shorten('https://example.com', service='git.io') == 'http://git.io/foobar123' with pytest.raises(web.ServiceHTTPError): web.shorten('https://example.com', service='git.io', custom='test')
def weather(text, reply, db, nick, bot, notice): """weather <location> [dontsave] -- Gets weather data for <location> from Wunderground.""" api_key = bot.config.get("api_keys", {}).get("wunderground") if not api_key: return "Error: No wunderground API details." # initialise weather DB db.execute("create table if not exists weather(nick primary key, loc)") # if there is no input, try getting the users last location from the DB if not text: location = db.execute("select loc from weather where nick=lower(:nick)", {"nick": nick}).fetchone() if not location: # no location saved in the database, send the user help text notice(weather.__doc__) return loc = location[0] # no need to save a location, we already have it dontsave = True else: # see if the input ends with "dontsave" dontsave = text.endswith(" dontsave") # remove "dontsave" from the input string after checking for it if dontsave: loc = text[:-9].strip().lower() else: loc = text location = requests.utils.quote(loc) request_url = base_url.format(api_key, "geolookup/forecast/conditions", location) try: request = requests.get(request_url) request.raise_for_status() except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError) as e: return "Could not get weather data: {}".format(e) response = request.json() if 'location' not in response: try: location_id = response['response']['results'][0]['zmw'] except KeyError: return "Could not get weather for that location." # get the weather again, using the closest match request_url = base_url.format(api_key, "geolookup/forecast/conditions", "zmw:" + location_id) response = requests.get(request_url).json() if response['location']['state']: place_name = "\x02{}\x02, \x02{}\x02 (\x02{}\x02)".format(response['location']['city'], response['location']['state'], response['location']['country']) else: place_name = "\x02{}\x02 (\x02{}\x02)".format(response['location']['city'], response['location']['country']) forecast_today = response["forecast"]["simpleforecast"]["forecastday"][0] forecast_tomorrow = response["forecast"]["simpleforecast"]["forecastday"][1] # put all the stuff we want to use in a dictionary for easy formatting of the output weather_data = { "place": place_name, "conditions": response['current_observation']['weather'], "temp_f": response['current_observation']['temp_f'], "temp_c": response['current_observation']['temp_c'], "humidity": response['current_observation']['relative_humidity'], "wind_kph": response['current_observation']['wind_kph'], "wind_mph": response['current_observation']['wind_mph'], "wind_direction": response['current_observation']['wind_dir'], "today_conditions": forecast_today['conditions'], "today_high_f": forecast_today['high']['fahrenheit'], "today_high_c": forecast_today['high']['celsius'], "today_low_f": forecast_today['low']['fahrenheit'], "today_low_c": forecast_today['low']['celsius'], "tomorrow_conditions": forecast_tomorrow['conditions'], "tomorrow_high_f": forecast_tomorrow['high']['fahrenheit'], "tomorrow_high_c": forecast_tomorrow['high']['celsius'], "tomorrow_low_f": forecast_tomorrow['low']['fahrenheit'], "tomorrow_low_c": forecast_tomorrow['low']['celsius'], "url": web.shorten(response["current_observation"]['forecast_url'] + "?apiref=e535207ff4757b18") } reply("{place} - \x02Current:\x02 {conditions}, {temp_f}F/{temp_c}C, {humidity}, " "Wind: {wind_kph}KPH/{wind_mph}MPH {wind_direction}, \x02Today:\x02 {today_conditions}, " "High: {today_high_f}F/{today_high_c}C, Low: {today_low_f}F/{today_low_c}C. " "\x02Tomorrow:\x02 {tomorrow_conditions}, High: {tomorrow_high_f}F/{tomorrow_high_c}C, " "Low: {tomorrow_low_f}F/{tomorrow_low_c}C - {url}".format(**weather_data)) if location and not dontsave: db.execute("insert or replace into weather(nick, loc) values (:nick, :loc)", {"nick": nick.lower(), "loc": loc}) db.commit()
def test_shorten(mock_requests): mock_requests.add( mock_requests.GET, "http://is.gd/create.php", json={"shorturl": "https://is.gd/foobar"}, ) from cloudbot.util import web assert (web.shorten("https://example.com", service="is.gd") == "https://is.gd/foobar") assert (web.Shortener().shorten("https://example.com") == "https://example.com") with pytest.raises(web.ServiceError): web.shorten("https://example.com", service="goo.gl") mock_requests.add( mock_requests.POST, "https://www.googleapis.com/urlshortener/v1/url", json={}, status=requests.codes.bad_request, ) with pytest.raises(web.ServiceHTTPError): web.shorten("https://example.com", service="goo.gl") mock_requests.replace( mock_requests.POST, "https://www.googleapis.com/urlshortener/v1/url", json={"error": { "message": "Error" }}, ) with pytest.raises(web.ServiceHTTPError): web.shorten("https://example.com", service="goo.gl") mock_requests.replace( mock_requests.POST, "https://www.googleapis.com/urlshortener/v1/url", json={"id": "https://goo.gl/foobar"}, ) assert (web.shorten("https://example.com", service="goo.gl") == "https://goo.gl/foobar") with pytest.raises(web.ServiceError): web.shorten("https://example.com", service="git.io") mock_requests.add( mock_requests.POST, "http://git.io", status=400, ) with pytest.raises(web.ServiceHTTPError): web.shorten("https://example.com", service="git.io") mock_requests.replace(mock_requests.POST, "http://git.io", body="error") with pytest.raises(web.ServiceHTTPError): web.shorten("https://example.com", service="git.io") mock_requests.replace(mock_requests.POST, "http://git.io", body="error") with pytest.raises(web.ServiceHTTPError): web.shorten("https://example.com", service="git.io") mock_requests.replace( mock_requests.POST, "http://git.io", headers={"Location": "http://git.io/foobar123"}, status=requests.codes.created, ) assert (web.shorten("https://example.com", service="git.io") == "http://git.io/foobar123") with pytest.raises(web.ServiceHTTPError): web.shorten("https://example.com", service="git.io", custom="test")
def wolframalpha(text, message): """<query> -- Computes <query> using Wolfram Alpha.""" if not api_key: return "Missing API key" params = {'input': text, 'format': "plaintext", 'appid': api_key} request = requests.get(api_url, params=params) url = query_url.format(urllib.parse.quote_plus(text)) try: request.raise_for_status() except HTTPError as e: message("Error getting query: {}".format(e.response.status_code)) raise if request.status_code != requests.codes.ok: return "WA error: {} [div] {}".format(request.status_code, url) result = etree.fromstring(request.content, parser=parser) pod_texts = {} for pod in result.xpath("//pod"): primary = "primary" in pod.attrib.keys() pid = pod.attrib["id"] title = pod.attrib["title"] # Ignore pods we don't care about if not primary and (not pid in list(show_pods) or not show_pods[pid]): # Sometimes Result will have a different id if not title in list(show_pods) or not show_pods[title]: continue results = [] # Format subpods #for subpod in pod.xpath('subpod/plaintext/text()'): for subpod in pod.xpath('subpod'): podinfo = "[h2]{}[/h2] ".format( subpod.attrib['title']) if subpod.attrib['title'] else "" podresults = [] for subinfo in subpod.xpath('plaintext/text()'): # Itemize units (separate lines) values = [] for item in subinfo.split('\n'): # Format "key | value" item = re.sub(r"^([\w\s]+)\s+\|\s+", "[h4]\\1:[/h4] ", item) # Replace inner '|' (eg weather forecast) item = re.sub(r"(\))\s+\|\s+", "\\1 [h2]-[/h2] ", item) # Colorize "(extra info)", preceeded with whitespace item = re.sub(r"\s+(\([^()]+\))", " [h3]\\1[/h3]", item) # Remove extra spaces item = re.sub(r'\s{2,}', ' ', item) # Add values.append(item.strip()) # Put 'em back together subinfo = " [div] ".join(values) if subinfo: podresults.append(subinfo) podinfo += ''.join(podresults) results.append(podinfo) if results: info = " [div] ".join(results) if pid == "Input": # Strip verbose "Input interp/info" title = title.replace(" interpretation", "").replace(" information", "") # Strip open/closing parentheses around input if pid in ["AdditionalConversion", "UnitConversion"]: # Reduce verbosity (just print "Conversions") title = "C" + title[title.index("conv") + 1:] title = "[h1]{}[/h1] ".format(title) pod_texts[pid] = title + info # NOTHING?? if not pod_texts: return "WA ain't found shit! [div] " + url # Sometimes input will be the only pod from filtering if "Input" in pod_texts and len(pod_texts) == 1: return "Extra info filtered [div] " + url # get the URL for a user to view this query in a browser try: short_url = " [div] [h1]Web[/h1] " + web.shorten(url) except: short_url = None if short_url: pod_texts['Input'] += short_url # Append input to result if "Input" in pod_texts and "Result" in pod_texts: pod_texts['Result'] = "{} [div] {}".format(pod_texts['Result'], pod_texts['Input']) del pod_texts['Input'] # Print result/input first if "Input" in pod_texts: message(pod_texts['Input']) del pod_texts['Input'] if "Result" in pod_texts: message(pod_texts['Result']) del pod_texts['Result'] # Print remaining info for key in pod_texts: message(pod_texts[key])
def malsearch(text, reply, bot): text = urllib.parse.quote(text) #grab our mal login try: user = bot.config.get("api_keys", {}).get("mal_user", None) password = bot.config.get("api_keys", {}).get("mal_pass", None) except: reply("No api key found.") url = 'https://myanimelist.net/api/anime/search.xml?q={}'.format(text) #try to request anime, reply if failed try: request = requests.get(url, auth=(user, password)) except Exception as e: reply('Error: {}'.format(e)) soup = BeautifulSoup(request.text) #a whole bunch of sorting title = http.strip_html(soup.find('title')) episodes = http.strip_html(soup.find('episodes')) if episodes == '0': episodes = '?' status = http.strip_html(soup.find('status')) score = http.strip_html(soup.find('score')) airtype = http.strip_html(soup.find('type')) start_date = http.strip_html(soup.find('start_date')) end_date = http.strip_html(soup.find('end_date')) #Has the anime ended? Yes. if end_date == '0000-00-00' and status is not 'Currently Airing': end_date = 'has not ended' #no but I know when. elif status == 'Currently Airing': end_date = 'will end {}'.format(http.strip_html(soup.find('end_date'))) #no I don't know when. else: print(status, end_date) end_date = 'ended {}'.format(http.strip_html(soup.find('end_date'))) #in case we want to ever output synopsis to irc synopsis = http.strip_html(http.strip_html(soup.find('synopsis'))) length = len(synopsis) if length > 432 and length < 888: synopsis_1, synopsis_2 = textwrap.wrap(synopsis, 432) elif length > 864: synopsis_1, synopsis_2, synopsis_3 = textwrap.wrap(synopsis, 432) id = http.strip_html(soup.find('id')) url = web.shorten( 'https://' + urllib.parse.quote('myanimelist.net/anime/{}/{}'.format(id, title))) reply('{}, {}, {}, {} episodes. {}, started {}, {}. {}'.format( title, airtype, score, episodes, status, start_date, end_date, url)) #more stuff we can add later for synopsis //its really spammy """if synopsis_1 is not None and synopsis_2 is not None and synopsis_3 is None:
def wow_armoury_format(data, link): """Format armoury data into a human readable string""" if data.status_code != 200 and data.status_code != 404: # The page returns 404 if the character or realm is not found. try: data.raise_for_status() except Exception as e: return 'An error occurred while trying to fetch the data. ({})'.format( str(e)) data = data.json() if len(data) == 0: return 'Could not find any results.' if 'reason' in data: # Something went wrong (i.e. realm does not exist, character does not exist, or page not found). return data['reason'] if 'name' in data: nice_url = link.replace('/api/wow/', '/wow/en/') + '/simple' try: return '{} is a level \x0307{}\x0F {} {} on {} with \x0307{}\x0F achievement points and \x0307{}' \ '\x0F honourable kills. Armoury Profile: {}' \ .format(data['name'], data['level'], wow_get_gender(data['gender']), wow_get_class(data['class'], True), data['realm'], data['achievementPoints'], data['totalHonorableKills'], web.shorten(nice_url)) except Exception as e: return 'Unable to fetch information for {}. Does the realm or ' \ 'character exist? ({})'.format(nice_url, str(e)) return 'An unexpected error occurred.'