diff --git a/sopel/modules/currency.py b/sopel/modules/currency.py index 7b702d3544..43c77e3289 100644 --- a/sopel/modules/currency.py +++ b/sopel/modules/currency.py @@ -39,26 +39,45 @@ class CurrencySection(StaticSection): fixer_io_key = ValidatedAttribute('fixer_io_key', default=None) + """Optional API key for Fixer.io (increases currency support)""" auto_convert = ValidatedAttribute('auto_convert', parse=bool, default=False) + """Whether to convert currencies without an explicit command""" def configure(config): + """ + | name | example | purpose | + | ---- | ------- | ------- | + | auto\\_convert | False | Whether to convert currencies without an explicit command | + | fixer\\_io\\_key | 0123456789abcdef0123456789abcdef | Optional API key for Fixer.io (increases currency support) | + """ config.define_section('currency', CurrencySection, validate=False) config.currency.configure_setting('fixer_io_key', 'Optional API key for Fixer.io (leave blank to use exchangeratesapi.io):') - config.currency.configure_setting('auto_convert', 'Automatically respond to currency conversion lines?') + config.currency.configure_setting('auto_convert', 'Whether to convert currencies without an explicit command?') def setup(bot): bot.config.define_section('currency', CurrencySection) +class FixerError(Exception): + """A Fixer.io API Error Exception""" + def __init__(self, status): + super(FixerError, self).__init__("FixerError: {}".format(status)) + + +class UnsupportedCurrencyError(Exception): + """A currency is currently not supported by the API""" + def __init__(self, currency): + super(UnsupportedCurrencyError, self).__init__(currency) + + def update_rates(bot): global rates_fiat_json, rates_btc_json, rates_updated - # If we have data that are less than 24h old, return - if 'date' in rates_fiat_json: - if time.time() - rates_updated < 24 * 60 * 60: - return + # If we have data that is less than 24h old, return + if time.time() - rates_updated < 24 * 60 * 60: + return # Update crypto rates response = requests.get(CRYPTO_URL) @@ -69,8 +88,7 @@ def update_rates(bot): if bot.config.currency.fixer_io_key is not None: response = requests.get(FIXER_URL.format(bot.config.currency.fixer_io_key)) if not response.json()['success']: - LOGGER.error(str(response.json()['error'])) - return bot.reply('Sorry, something went wrong') + raise FixerError('Fixer.io request failed with error: {}'.format(response.json()['error'])) else: response = requests.get(FIAT_URL) @@ -86,7 +104,7 @@ def btc_rate(code, reverse=False): if search in rates_btc_json: rate = rates_btc_json[search]['averages']['day'] else: - return UNSUPPORTED_CURRENCY.format(code) + raise UnsupportedCurrencyError(code) if reverse: return 1 / rate @@ -98,21 +116,16 @@ def get_rate(of, to): of = of.upper() to = to.upper() - if of == 'BTC' or to == 'BTC': - if of == 'BTC': - code = to - reverse = False - else: - code = of - reverse = True - - return btc_rate(code, reverse) + if of == 'BTC': + return btc_rate(to, False) + elif to == 'BTC': + return btc_rate(of, True) if of not in rates_fiat_json['rates']: - return UNSUPPORTED_CURRENCY.format(of) + raise UnsupportedCurrencyError(of) if to not in rates_fiat_json['rates']: - return UNSUPPORTED_CURRENCY.format(to) + raise UnsupportedCurrencyError(to) return (1 / rates_fiat_json['rates'][of]) * rates_fiat_json['rates'][to] @@ -125,14 +138,18 @@ def exchange(bot, match): try: update_rates(bot) # Try and update rates. Rate-limiting is done in update_rates() - except requests.exceptions.RequestException as e: + except requests.exceptions.RequestException as err: bot.reply("Something went wrong while I was getting the exchange rate.") - LOGGER.error("Error in GET request: {}".format(e)) + LOGGER.error("Error in GET request: {}".format(err)) return NOLIMIT except ValueError: bot.reply("Error: Got malformed data.") LOGGER.error("Invalid json on update_rates") return NOLIMIT + except FixerError as err: + bot.reply('Sorry, something went wrong with Fixer') + LOGGER.error(err) + return NOLIMIT query = match.string @@ -151,11 +168,24 @@ def exchange(bot, match): except OverflowError: bot.reply("Sorry, input amount was out of range.") + if not amount: + bot.reply("Zero is zero, no matter what country you're in.") + return NOLIMIT + out_string = '{} {} is'.format(amount, of.upper()) + for to in others: try: - out_string = build_reply(bot, amount, of.upper(), to.upper(), out_string) + out_string = build_reply(amount, of.upper(), to.upper(), out_string) except ValueError: + LOGGER.error("Raw rate wasn't a float") + return NOLIMIT + except KeyError as err: + bot.reply("Error: Invalid rates") + LOGGER.error("No key: {} in json".format(err)) + return NOLIMIT + except UnsupportedCurrencyError as cur: + bot.reply(UNSUPPORTED_CURRENCY.format(cur)) return NOLIMIT bot.reply(out_string[0:-1]) @@ -183,18 +213,9 @@ def exchange_re(bot, trigger): exchange(bot, match) -def build_reply(bot, amount, of, to, out_string): - if not amount: - bot.reply("Zero is zero, no matter what country you're in.") - - rate_raw = '' - try: - rate_raw = get_rate(of, to) - rate = float(rate_raw) - except ValueError: - bot.reply(rate_raw) - raise - +def build_reply(amount, of, to, out_string): + rate_raw = get_rate(of, to) + rate = float(rate_raw) result = float(rate * amount) if to == 'BTC':