From 15767674a472bf585882bdf912441d2aa542bd35 Mon Sep 17 00:00:00 2001 From: dgw Date: Sat, 22 Jun 2024 14:24:28 -0500 Subject: [PATCH 1/3] Major overhaul for Sopel 8 and Python 3-only * Converted to entry-point plugin * Package name is now `sopel-stocks` * Supports minimum Python 3.8 * Supports minimum Sopel 8.0 * Updated imports * Updated README * Created changelog in NEWS file * Added .gitignore file I was able to test the plugin successfully with a free API key from Finnhub. Linting with flake8 shows nothing more serious than "line too long" errors. --- .gitignore | 57 +++++++++++ MANIFEST.in | 3 +- NEWS | 99 +++++++++++++++++++ README.md | 53 +++++----- pyproject.toml | 59 +++++++++++ requirements.txt | 1 - setup.py | 44 --------- sopel_modules/__init__.py | 1 - sopel_modules/stocks/__init__.py | 11 --- .../providers => sopel_stocks}/__init__.py | 0 .../stocks.py => sopel_stocks/plugin.py | 23 ++--- sopel_stocks/providers/__init__.py | 0 .../providers/alphavantage.py | 2 +- .../providers/finnhub.py | 4 +- .../providers/iexcloud.py | 2 +- 15 files changed, 257 insertions(+), 102 deletions(-) create mode 100644 .gitignore create mode 100644 pyproject.toml delete mode 100644 requirements.txt delete mode 100755 setup.py delete mode 100644 sopel_modules/__init__.py delete mode 100644 sopel_modules/stocks/__init__.py rename {sopel_modules/stocks/providers => sopel_stocks}/__init__.py (100%) mode change 100755 => 100644 rename sopel_modules/stocks/stocks.py => sopel_stocks/plugin.py (90%) create mode 100755 sopel_stocks/providers/__init__.py rename {sopel_modules/stocks => sopel_stocks}/providers/alphavantage.py (94%) rename {sopel_modules/stocks => sopel_stocks}/providers/finnhub.py (87%) rename {sopel_modules/stocks => sopel_stocks}/providers/iexcloud.py (87%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba74660 --- /dev/null +++ b/.gitignore @@ -0,0 +1,57 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ diff --git a/MANIFEST.in b/MANIFEST.in index 60ca266..091f062 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,6 @@ include NEWS -include COPYING +include LICENSE include README.md -include *requirements.txt recursive-include tests * recursive-exclude * __pycache__ diff --git a/NEWS b/NEWS index e69de29..5040501 100644 --- a/NEWS +++ b/NEWS @@ -0,0 +1,99 @@ +## Changelog + +### 1.3.0 + +First release as `sopel-stocks`, replacing `sopel_modules.stocks`. + + +### 1.2.3 + +Added: +* Finnhub data provider + +Fixed: +* Alpha Vantage API endpoint (yet again) + + +### 1.2.2 + +Changed: +* Further Alpha Vantage API updates + + +### 1.2.1 + +Fixed: +* Move away from premium Alpha Vantage endpoint + +Meta: +* More packaging workflow updates + + +### 1.2.0 + +Added: +* Help message for `.stock` command +* Multi-symbol lookup + +Meta: +* Project moved to Sopel's GitHub org, and docs/workflows updated + + +### 1.1.3 + +Fixed: +* Bug with newly IPO'd stocks + + +### 1.1.2 + +Fixed: +* Handling input of foreign ticker symbols + +Meta: +* Additional installation documentation + + +### 1.1.1 + +Fixed: +* Presentation bug when using IEX Cloud data + +Meta: +* Fixed packaging workflow + + +### 1.1.0 + +Added: +* IEX Cloud data provider +* New configuration to select data provider + + +### 1.0.4 + +Improved documentation and error handling + + +### 1.0.3 + +Fixed handling stocks with no prior history, i.e. new symbols + + +### 1.0.2 + +Fixed: +* Formatting for penny stocks + +Meta: +* Additional packaging tweaks + + +### 1.0.1 + +Style/packaging fixes (no corresponding release) + + +### 1.0.0 + +Initial release of `sopel_modules.stocks` module, using Alpha Vantage for data. diff --git a/README.md b/README.md index 4e01068..bf2bb99 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,45 @@ +# sopel-stocks + +A stock lookup plugin for Sopel IRC bots + [![Python Tests](https://github.com/sopel-irc/sopel-stocks/actions/workflows/python-tests.yml/badge.svg?branch=master)](https://github.com/sopel-irc/sopel-stocks/actions/workflows/python-tests.yml) -[![PyPI version](https://badge.fury.io/py/sopel-modules.stocks.svg)](https://badge.fury.io/py/sopel-modules.stocks) -[![Total alerts](https://img.shields.io/lgtm/alerts/g/sopel-irc/sopel-stocks.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/sopel-irc/sopel-stocks/alerts/) -[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/sopel-irc/sopel-stocks.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/sopel-irc/sopel-stocks/context:python) +[![PyPI version](https://badge.fury.io/py/sopel-stocks.svg)](https://badge.fury.io/py/sopel-stocks) **Maintainer:** [@RustyBower](https://github.com/rustybower) -# sopel-stocks -sopel-stocks is an stock lookup plugin for Sopel ## Installing -If possible, use `pip` to install this plugin. Below are example commands; you -might need to add `sudo` and/or call a different `pip` (e.g. `pip3`) depending -on your system and environment. Do not use `setup.py install`; Sopel won't be -able to load the plugin correctly. -#### Published release +Releases are hosted on PyPI, so after installing Sopel, all you need is `pip`: - pip install sopel-modules.stocks +```shell +$ pip install sopel-stocks +``` -#### From source +### Requirements - # Clone the repo, then run this in /path/to/sopel-stocks - pip install . +This release of `sopel-stocks` requires Python 3.8+ and Sopel 8.0 or higher. -## Configuring -You can automatically configure this plugin using the `sopel configure --plugins` command. +You will need an API key from one of the following providers: -However, if you want or need to configure this plugin manually, you will need to define the following in `~/.sopel/default.cfg` +* [Alpha Vantage](https://www.alphavantage.co/support/#api-key) +* [Finnhub](https://finnhub.io/dashboard) (recommended) +* [IEX Cloud](https://iexcloud.io/console/tokens) - [stocks] - api_key = API_KEY - provider = finnhub (or alphavantage/iexcloud) -## Requirements -#### API Key (from 1 of the following providers) +### Configuring + +The easiest way to configure `sopel-stocks` is via Sopel's +configuration wizard—simply run `sopel-plugins configure stocks` +and enter the values for which it prompts you. - https://www.alphavantage.co/support/#api-key - https://iexcloud.io/console/tokens - https://finnhub.io/dashboard (recommended) +However, if you want or need to configure this plugin manually, you will need to +define the following in `~/.sopel/default.cfg` -#### Python Requirements + [stocks] + api_key = API_KEY + provider = finnhub (or alphavantage/iexcloud) - requests - sopel ## Usage diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..86a73c9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,59 @@ +[build-system] +requires = ["setuptools>=63.0", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.setuptools] +platforms = ["Linux x86, x86-64"] + +[tool.setuptools.packages.find] +include = ["sopel_stocks", "sopel_stocks.*"] +namespaces = false + +[tool.setuptools.dynamic] +readme = { file=["README.md", "NEWS"], content-type="text/markdown" } + +[project] +name = "sopel-stocks" +version = "1.3.0.dev0" +description = "Stock lookup plugin for Sopel IRC bots" + +authors = [ + { name="Rusty Bower", email="rusty@rustybower.com" }, +] + +license = { text="MIT License" } +dynamic = ["readme"] + +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: System Administrators", + "License :: Eiffel Forum License (EFL)", + "License :: OSI Approved :: Eiffel Forum License", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Communications :: Chat :: Internet Relay Chat", +] +keywords = [ + "sopel", + "plugin", + "bot", + "irc", +] + +requires-python = ">=3.8, <4" +dependencies = [ + "sopel>=8.0", + "requests", # Sopel also requires this, but it's better to be explicit +] + +[project.urls] +"Homepage" = "https://github.com/sopel-irc/sopel-stocks" +"Bug Tracker" = "https://github.com/sopel-irc/sopel-stocks/issues" + +[project.entry-points."sopel.plugins"] +"stocks" = "sopel_stocks.plugin" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index f229360..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -requests diff --git a/setup.py b/setup.py deleted file mode 100755 index 4fb228e..0000000 --- a/setup.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import print_function -import os -import sys -from setuptools import setup, find_packages - - -if __name__ == '__main__': - print('Sopel does not correctly load modules installed with setup.py ' - 'directly. Please use "pip install .", or add {}/sopel_modules to ' - 'core.extra in your config.'.format( - os.path.dirname(os.path.abspath(__file__))), - file=sys.stderr) - -with open('README.md') as readme_file: - readme = readme_file.read() - -with open('NEWS') as history_file: - history = history_file.read() - -with open('requirements.txt') as requirements_file: - requirements = [req for req in requirements_file.readlines()] - -with open('tests/requirements.txt') as dev_requirements_file: - dev_requirements = [req for req in dev_requirements_file.readlines()] - - -setup( - name='sopel_modules.stocks', - version='1.2.3', - description='Sopel Stocks Plugin', - long_description=readme + '\n\n' + history, - long_description_content_type='text/markdown', # This is important! - author='Rusty Bower', - author_email='rusty@rustybower.com', - url='http://github.com/rustybower/sopel-stocks', - packages=find_packages('.'), - namespace_packages=['sopel_modules'], - include_package_data=True, - install_requires=requirements, - tests_require=dev_requirements, - test_suite='tests', - license='MIT License', -) diff --git a/sopel_modules/__init__.py b/sopel_modules/__init__.py deleted file mode 100644 index de40ea7..0000000 --- a/sopel_modules/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__import__('pkg_resources').declare_namespace(__name__) diff --git a/sopel_modules/stocks/__init__.py b/sopel_modules/stocks/__init__.py deleted file mode 100644 index 6bb81b1..0000000 --- a/sopel_modules/stocks/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# coding=utf8 -""" -stocks.py - Sopel Stocks Plugin -""" -from __future__ import unicode_literals, absolute_import, division, print_function - -from .stocks import configure, get_price, setup, stock - -__author__ = 'Rusty Bower' -__email__ = 'rusty@rustybower.com' -__version__ = '1.2.3' diff --git a/sopel_modules/stocks/providers/__init__.py b/sopel_stocks/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from sopel_modules/stocks/providers/__init__.py rename to sopel_stocks/__init__.py diff --git a/sopel_modules/stocks/stocks.py b/sopel_stocks/plugin.py similarity index 90% rename from sopel_modules/stocks/stocks.py rename to sopel_stocks/plugin.py index 8753a01..1146701 100644 --- a/sopel_modules/stocks/stocks.py +++ b/sopel_stocks/plugin.py @@ -1,19 +1,19 @@ -# coding=utf-8 -""" -stocks.py - Sopel Stocks Plugin -""" +"""Stock lookup plugin for Sopel IRC bots""" +from __future__ import annotations + import re -from datetime import datetime, timedelta + from sopel.config.types import NO_DEFAULT, ChoiceAttribute, StaticSection, ValidatedAttribute from sopel.formatting import color, colors -from sopel.logger import get_logger -from sopel.module import commands, example +from sopel.plugin import command, example +from sopel.tools import get_logger from .providers.alphavantage import alphavantage from .providers.iexcloud import iexcloud from .providers.finnhub import finnhub -logger = get_logger(__name__) + +logger = get_logger('stocks') STOCK_PROVIDERS = [ @@ -28,7 +28,7 @@ class StocksSection(StaticSection): provider = ChoiceAttribute( 'provider', STOCK_PROVIDERS, - default=NO_DEFAULT + default=NO_DEFAULT, ) api_key = ValidatedAttribute('api_key', default=NO_DEFAULT) @@ -67,13 +67,14 @@ def get_price(bot, symbol): raise Exception('Error: Unsupported Provider') -@commands('stock') +@command('stock') @example('.stock msft') @example('.stock amzn msft goog') def stock(bot, trigger): - """Get the current price for given stock(s).""" + """Get the current price for given stock symbol(s).""" # If the user types .stock with no arguments, let them know proper usage if not trigger.group(2): + bot.reply("I need at least one stock symbol to look up.") return else: # Get symbol diff --git a/sopel_stocks/providers/__init__.py b/sopel_stocks/providers/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/sopel_modules/stocks/providers/alphavantage.py b/sopel_stocks/providers/alphavantage.py similarity index 94% rename from sopel_modules/stocks/providers/alphavantage.py rename to sopel_stocks/providers/alphavantage.py index 9dce69a..51a3f83 100755 --- a/sopel_modules/stocks/providers/alphavantage.py +++ b/sopel_stocks/providers/alphavantage.py @@ -1,4 +1,4 @@ -# coding=utf-8 +"""Alpha Vantage data provider for Sopel stocks plugin""" import requests diff --git a/sopel_modules/stocks/providers/finnhub.py b/sopel_stocks/providers/finnhub.py similarity index 87% rename from sopel_modules/stocks/providers/finnhub.py rename to sopel_stocks/providers/finnhub.py index 9d07a75..4a5f546 100644 --- a/sopel_modules/stocks/providers/finnhub.py +++ b/sopel_stocks/providers/finnhub.py @@ -1,4 +1,4 @@ -# coding=utf-8 +"""Finnhub data provider for Sopel stocks plugin""" import requests @@ -11,7 +11,7 @@ def finnhub(bot, symbol): if not r.json(): raise Exception("An error occurred.") - + close = r.json()['c'] # prevclose = r.json()['pc'] change = r.json()['d'] diff --git a/sopel_modules/stocks/providers/iexcloud.py b/sopel_stocks/providers/iexcloud.py similarity index 87% rename from sopel_modules/stocks/providers/iexcloud.py rename to sopel_stocks/providers/iexcloud.py index 4614e5c..dd7ac89 100755 --- a/sopel_modules/stocks/providers/iexcloud.py +++ b/sopel_stocks/providers/iexcloud.py @@ -1,4 +1,4 @@ -# coding=utf-8 +"""IEX Cloud data provider for Sopel stocks plugin""" import requests From a7ef24e5f2a7b94d252c9e4735ab9e6a0abcaccf Mon Sep 17 00:00:00 2001 From: dgw Date: Sat, 22 Jun 2024 14:30:48 -0500 Subject: [PATCH 2/3] providers: fix line endings --- sopel_stocks/providers/alphavantage.py | 100 ++++++++++++------------- sopel_stocks/providers/finnhub.py | 42 +++++------ sopel_stocks/providers/iexcloud.py | 32 ++++---- 3 files changed, 87 insertions(+), 87 deletions(-) diff --git a/sopel_stocks/providers/alphavantage.py b/sopel_stocks/providers/alphavantage.py index 51a3f83..f60c6ca 100755 --- a/sopel_stocks/providers/alphavantage.py +++ b/sopel_stocks/providers/alphavantage.py @@ -1,50 +1,50 @@ -"""Alpha Vantage data provider for Sopel stocks plugin""" -import requests - - -def alphavantage(bot, symbol): - r = requests.get( - "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol={symbol}&apikey={api_key}".format( - symbol=symbol, api_key=bot.config.stocks.api_key - ) - ) - - if not r.json(): - raise Exception("An error occurred.") - - if "Information" in r.json().keys(): - raise Exception(r.json()["Information"]) - - if "Error Message" in r.json().keys(): - raise Exception(r.json()["Error Message"]) - - days = sorted(r.json()["Time Series (Daily)"].keys(), reverse=True) - - # Only 1 day of history, likely this is a new stock on the market - if len(days) == 1: - today = days[0] - close = r.json()["Time Series (Daily)"][today]["4. close"] - prevclose = r.json()["Time Series (Daily)"][today]["1. open"] - else: - # Get today's entry - today = days[0] - prevdate = days[1] - - # dict_keys(['1. open', '2. high', '3. low', '4. close', '5. volume']) - # open = r.json()['Time Series (Daily)'][today]['1. open'] - # high = r.json()['Time Series (Daily)'][today]['2. high'] - # low = r.json()['Time Series (Daily)'][today]['3. low'] - close = r.json()["Time Series (Daily)"][today]["4. close"] - # volume = r.json()['Time Series (Daily)'][today]['5. volume'] - - # Get yesterday's close - prevclose = r.json()["Time Series (Daily)"][prevdate]["4. close"] - - # Calculate change - change = float(close) - float(prevclose) - - # Calculate percentage change - percentchange = float(change) / float(prevclose) * 100 - - data = {"close": close, "change": change, "percentchange": percentchange} - return data +"""Alpha Vantage data provider for Sopel stocks plugin""" +import requests + + +def alphavantage(bot, symbol): + r = requests.get( + "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol={symbol}&apikey={api_key}".format( + symbol=symbol, api_key=bot.config.stocks.api_key + ) + ) + + if not r.json(): + raise Exception("An error occurred.") + + if "Information" in r.json().keys(): + raise Exception(r.json()["Information"]) + + if "Error Message" in r.json().keys(): + raise Exception(r.json()["Error Message"]) + + days = sorted(r.json()["Time Series (Daily)"].keys(), reverse=True) + + # Only 1 day of history, likely this is a new stock on the market + if len(days) == 1: + today = days[0] + close = r.json()["Time Series (Daily)"][today]["4. close"] + prevclose = r.json()["Time Series (Daily)"][today]["1. open"] + else: + # Get today's entry + today = days[0] + prevdate = days[1] + + # dict_keys(['1. open', '2. high', '3. low', '4. close', '5. volume']) + # open = r.json()['Time Series (Daily)'][today]['1. open'] + # high = r.json()['Time Series (Daily)'][today]['2. high'] + # low = r.json()['Time Series (Daily)'][today]['3. low'] + close = r.json()["Time Series (Daily)"][today]["4. close"] + # volume = r.json()['Time Series (Daily)'][today]['5. volume'] + + # Get yesterday's close + prevclose = r.json()["Time Series (Daily)"][prevdate]["4. close"] + + # Calculate change + change = float(close) - float(prevclose) + + # Calculate percentage change + percentchange = float(change) / float(prevclose) * 100 + + data = {"close": close, "change": change, "percentchange": percentchange} + return data diff --git a/sopel_stocks/providers/finnhub.py b/sopel_stocks/providers/finnhub.py index 4a5f546..6e5fc32 100644 --- a/sopel_stocks/providers/finnhub.py +++ b/sopel_stocks/providers/finnhub.py @@ -1,21 +1,21 @@ -"""Finnhub data provider for Sopel stocks plugin""" -import requests - - -def finnhub(bot, symbol): - r = requests.get( - "https://finnhub.io/api/v1/quote?symbol={symbol}&token={api_key}".format( - symbol=symbol, api_key=bot.config.stocks.api_key - ) - ) - - if not r.json(): - raise Exception("An error occurred.") - - close = r.json()['c'] - # prevclose = r.json()['pc'] - change = r.json()['d'] - percentchange = r.json()['dp'] - - data = {"close": close, "change": change, "percentchange": percentchange} - return data +"""Finnhub data provider for Sopel stocks plugin""" +import requests + + +def finnhub(bot, symbol): + r = requests.get( + "https://finnhub.io/api/v1/quote?symbol={symbol}&token={api_key}".format( + symbol=symbol, api_key=bot.config.stocks.api_key + ) + ) + + if not r.json(): + raise Exception("An error occurred.") + + close = r.json()['c'] + # prevclose = r.json()['pc'] + change = r.json()['d'] + percentchange = r.json()['dp'] + + data = {"close": close, "change": change, "percentchange": percentchange} + return data diff --git a/sopel_stocks/providers/iexcloud.py b/sopel_stocks/providers/iexcloud.py index dd7ac89..4ac29a8 100755 --- a/sopel_stocks/providers/iexcloud.py +++ b/sopel_stocks/providers/iexcloud.py @@ -1,16 +1,16 @@ -"""IEX Cloud data provider for Sopel stocks plugin""" -import requests - - -def iexcloud(bot, symbol): - r = requests.get('https://cloud.iexapis.com/stable/stock/{symbol}/quote?token={api_key}&displayPercent=true'.format(symbol=symbol, api_key=bot.config.stocks.api_key)) - # Catch errors - if r.status_code != 200: - raise Exception('Error: {}'.format(r.text)) - - data = { - 'close': r.json()['latestPrice'], - 'change': r.json()['change'], - 'percentchange': r.json()['changePercent'] - } - return data +"""IEX Cloud data provider for Sopel stocks plugin""" +import requests + + +def iexcloud(bot, symbol): + r = requests.get('https://cloud.iexapis.com/stable/stock/{symbol}/quote?token={api_key}&displayPercent=true'.format(symbol=symbol, api_key=bot.config.stocks.api_key)) + # Catch errors + if r.status_code != 200: + raise Exception('Error: {}'.format(r.text)) + + data = { + 'close': r.json()['latestPrice'], + 'change': r.json()['change'], + 'percentchange': r.json()['changePercent'] + } + return data From b04b59db6c8fa07f96ff2c0526c65f47e5a754b7 Mon Sep 17 00:00:00 2001 From: dgw Date: Sat, 22 Jun 2024 14:35:24 -0500 Subject: [PATCH 3/3] meta: split lines longer than 127 cols --- sopel_stocks/plugin.py | 5 ++++- sopel_stocks/providers/iexcloud.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/sopel_stocks/plugin.py b/sopel_stocks/plugin.py index 1146701..efeefa0 100644 --- a/sopel_stocks/plugin.py +++ b/sopel_stocks/plugin.py @@ -81,7 +81,10 @@ def stock(bot, trigger): symbols = trigger.group(2).split() # Do regex checking on symbol to ensure it's valid - symbols = [symbol for symbol in symbols if re.match('^([a-zA-Z0-9]{1,10}:[a-zA-Z0-9]{1,10}|[a-zA-Z0-9]{1,10})$', symbol)] + symbols = [ + symbol for symbol in symbols + if re.match('^([a-zA-Z0-9]{1,10}:[a-zA-Z0-9]{1,10}|[a-zA-Z0-9]{1,10})$', symbol) + ] # Get data from API for symbol in symbols: diff --git a/sopel_stocks/providers/iexcloud.py b/sopel_stocks/providers/iexcloud.py index 4ac29a8..16537ff 100755 --- a/sopel_stocks/providers/iexcloud.py +++ b/sopel_stocks/providers/iexcloud.py @@ -3,7 +3,10 @@ def iexcloud(bot, symbol): - r = requests.get('https://cloud.iexapis.com/stable/stock/{symbol}/quote?token={api_key}&displayPercent=true'.format(symbol=symbol, api_key=bot.config.stocks.api_key)) + r = requests.get( + 'https://cloud.iexapis.com/stable/stock/{symbol}/quote?token={api_key}&displayPercent=true' + .format(symbol=symbol, api_key=bot.config.stocks.api_key) + ) # Catch errors if r.status_code != 200: raise Exception('Error: {}'.format(r.text))