diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d9655556800..3c826ab6ef5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: - run: shopt -s globstar && pyupgrade --py36-plus **/*.py - run: safety check - run: | - pylint terminal.py gamestonk_terminal discordbot tests + pylint terminal.py gamestonk_terminal bots tests test: name: Base Tests - Ubuntu-latest - Python 3.9 needs: linting diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b599f9d892c..08e54f06d45 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -53,7 +53,7 @@ repos: hooks: - id: pylint name: pylint - entry: pylint discordbot gamestonk_terminal terminal.py tests + entry: pylint bots gamestonk_terminal terminal.py tests language: system types: [python] - repo: https://github.com/Yelp/detect-secrets diff --git a/bots/etf/whatetf.py b/bots/etf/whatetf.py index c9ca57914ed..52300cc3f8a 100755 --- a/bots/etf/whatetf.py +++ b/bots/etf/whatetf.py @@ -1,10 +1,12 @@ import logging import os +import re import time import bs4 import df2img import disnake +import natsort import pandas as pd import undetected_chromedriver.v2 as uc from selenium.webdriver.common.by import By @@ -17,9 +19,28 @@ from gamestonk_terminal.decorators import log_start_end logger = logging.getLogger(__name__) +conversion_mapping = { + "K": 1_000, + "M": 1_000_000, +} + +all_units = "|".join(conversion_mapping.keys()) +float_re = natsort.numeric_regex_chooser(natsort.ns.FLOAT | natsort.ns.SIGNED) +unit_finder = re.compile(rf"({float_re})\s*({all_units})", re.IGNORECASE) + + +def unit_replacer(matchobj): + """ + Given a regex match object, return a replacement string where units are modified + """ + number = matchobj.group(1) + unit = matchobj.group(2) + new_number = float(number) * conversion_mapping[unit] + return f"{new_number} in" + @log_start_end(log=logger) -def by_ticker_command(ticker="", num: int = 15): +def by_ticker_command(ticker="", sort="fund_percent", num: int = 15): """Display ETF Holdings. [Source: StockAnalysis]""" # Debug @@ -31,7 +52,6 @@ def by_ticker_command(ticker="", num: int = 15): options.headless = True options.add_argument("--headless") options.add_argument("--incognito") - global browser driver = uc.Chrome(options=options, version_main=98) driver.set_window_size(1920, 1080) driver.get(f"http://etf.com/stock/{ticker.upper()}/") @@ -57,7 +77,7 @@ def by_ticker_command(ticker="", num: int = 15): .findNext("td") .text ) - + driver.quit() df = pd.DataFrame( { "Ticker": r_ticker, @@ -70,8 +90,18 @@ def by_ticker_command(ticker="", num: int = 15): if df.empty: raise Exception("No company holdings found!\n") + if sort == "mkt_value": + # [unit_finder.sub(unit_replacer, x) for x in df["Market Value"]] + key = natsort.index_natsorted( + df["Market Value"], + key=lambda x: unit_finder.sub(unit_replacer, x), + reverse=True, + ) + df = df.reindex(key) + df = df.iloc[:num] df.set_index("Ticker", inplace=True) + title = f"ETF's Holding {ticker.upper()}" dindex = len(df.index) if dindex > 15: @@ -84,7 +114,7 @@ def by_ticker_command(ticker="", num: int = 15): df_pg.append(df_pg) fig = df2img.plot_dataframe( df_pg, - fig_size=(900, (40 * dindex)), + fig_size=(800, (40 * dindex)), col_width=[0.6, 3.5, 0.65, 1.1], tbl_header=cfg.PLT_TBL_HEADER, tbl_cells=cfg.PLT_TBL_CELLS, @@ -155,7 +185,7 @@ def by_ticker_command(ticker="", num: int = 15): else: fig = df2img.plot_dataframe( df, - fig_size=(900, (40 * dindex)), + fig_size=(800, (40 * dindex)), col_width=[0.6, 3.5, 0.65, 1.1], tbl_header=cfg.PLT_TBL_HEADER, tbl_cells=cfg.PLT_TBL_CELLS, diff --git a/bots/groupme/groupme_helpers.py b/bots/groupme/groupme_helpers.py index 7fca239dd1c..cddfd429fa3 100644 --- a/bots/groupme/groupme_helpers.py +++ b/bots/groupme/groupme_helpers.py @@ -53,9 +53,7 @@ def send_message(message: str, group_id: str) -> requests.Response: return requests.post(url=f"{base+mid}?bot_id={bot_id}&text={cleaned}") -def send_image( - image: str, group_id: str, text: str = None, local: bool = False -) -> requests.Response: +def send_image(image: str, group_id: str, text: str = None) -> requests.Response: if "http" in image: response = upload_image(image, False) else: diff --git a/bots/helpers.py b/bots/helpers.py index 5586229d391..04113a38340 100644 --- a/bots/helpers.py +++ b/bots/helpers.py @@ -403,16 +403,16 @@ class ShowView: await inter.send(embed=embed, delete_after=30.0) - def groupme(self, func, group_id, name, *args, **kwargs): + def groupme(self, func, group_id, name, *args, **kwargs): # pylint: disable=W0613 data = func(*args, **kwargs) if "imagefile" in data: imagefile = cfg.IMG_DIR / data["imagefile"] - send_image(imagefile, group_id, data.get("description", ""), True) + send_image(imagefile, group_id, data.get("description", "")) elif "embeds_img" in data: imagefiles = data["images_list"] for img in imagefiles: imagefile = cfg.IMG_DIR / img - send_image(imagefile, group_id, data.get("description", ""), True) + send_image(imagefile, group_id, data.get("description", "")) elif "description" in data: title = data.get("title", "") # TODO: Allow navigation through pages @@ -462,7 +462,7 @@ class ShowView: } client.chat_postMessage(**payload) title = "" - if N < len(data["titles"]) and not 0: + if N < len(data["titles"]) and N != 0: title = data["titles"][N] client.files_upload( file=imagefile, @@ -483,7 +483,9 @@ class ShowView: payload = {"channel": channel_id, "username": user_id, "text": message} client.chat_postMessage(**payload) - def telegram(self, func, message, bot, cmd, *args, **kwargs): + def telegram( + self, func, message, bot, cmd, *args, **kwargs + ): # pylint: disable=W0613 data = func(*args, **kwargs) if "imagefile" in data: imagefile = cfg.IMG_DIR / data["imagefile"] @@ -513,7 +515,7 @@ class ShowView: res = f"{title}\n{description}" bot.reply_to(message, res) title = "" - if N < len(data["titles"]) and not 0: + if N < len(data["titles"]) and N != 0: title = data["titles"][N] with open(imagefile, "rb") as image: bot.reply_to(message, title) diff --git a/bots/stocks/options/cc_hist.py b/bots/stocks/options/cc_hist.py index 6c8d0abdf34..e86bf15ed95 100644 --- a/bots/stocks/options/cc_hist.py +++ b/bots/stocks/options/cc_hist.py @@ -32,7 +32,7 @@ def cc_hist_command( # Debug if cfg.DEBUG: - logger.info(f"opt hist {ticker} {strike} {opt_type} {expiry}") + logger.info("opt hist %s, %s, %s, %s", ticker, strike, opt_type, expiry) # Check for argument if ticker is None: diff --git a/bots/stocks/options/hist.py b/bots/stocks/options/hist.py index 8f69dd2a6b5..7e9ec5ac355 100644 --- a/bots/stocks/options/hist.py +++ b/bots/stocks/options/hist.py @@ -36,7 +36,9 @@ def hist_command( # Debug if cfg.DEBUG: - logger.info(f"opt grhist {ticker} {strike} {opt_type} {expiry} {greek}") + logger.info( + "opt grhist %s %s %s %s %s", ticker, strike, opt_type, expiry, greek + ) # Check for argument if ticker is None: diff --git a/bots/stocks/options/overview.py b/bots/stocks/options/overview.py index de60fdc8967..e5c10d32323 100644 --- a/bots/stocks/options/overview.py +++ b/bots/stocks/options/overview.py @@ -10,15 +10,15 @@ import numpy as np import pandas as pd import plotly.graph_objects as go import yfinance as yf - -import bots.config_discordbot as cfg from bots import helpers from bots.config_discordbot import gst_imgur +import bots.config_discordbot as cfg from bots.menus.menu import Menu from gamestonk_terminal.decorators import log_start_end from gamestonk_terminal.stocks.options import op_helpers, yfinance_model from gamestonk_terminal.stocks.options.barchart_model import get_options_info +# pylint: disable=W0640,W0631 logger = logging.getLogger(__name__) @@ -154,9 +154,7 @@ def options_run( formats = {"iv": "{:.2f}"} for col, f in formats.items(): - calls_df[col] = calls_df[col].map( - lambda x: f.format(x) # pylint: disable=W0640 - ) + calls_df[col] = calls_df[col].map(lambda x: f.format(x)) calls_df = calls_df.fillna("") calls_df.set_index("strike", inplace=True) diff --git a/bots/stocks/technical_analysis/ad.py b/bots/stocks/technical_analysis/ad.py index b70d7bd74d2..10448ec9077 100644 --- a/bots/stocks/technical_analysis/ad.py +++ b/bots/stocks/technical_analysis/ad.py @@ -1,12 +1,13 @@ import logging import plotly.graph_objects as go - -import bots.config_discordbot as cfg from bots import helpers, load_candle +import bots.config_discordbot as cfg from gamestonk_terminal.common.technical_analysis import volume_model from gamestonk_terminal.decorators import log_start_end +# pylint: disable=R0913 + logger = logging.getLogger(__name__) diff --git a/bots/stocks/technical_analysis/adosc.py b/bots/stocks/technical_analysis/adosc.py index 810262c3f27..51675bba3d1 100644 --- a/bots/stocks/technical_analysis/adosc.py +++ b/bots/stocks/technical_analysis/adosc.py @@ -7,6 +7,7 @@ from bots import helpers, load_candle from gamestonk_terminal.common.technical_analysis import volume_model from gamestonk_terminal.decorators import log_start_end +# pylint: disable=R0913 logger = logging.getLogger(__name__) diff --git a/bots/stocks/technical_analysis/aroon.py b/bots/stocks/technical_analysis/aroon.py index ac62ee54c94..e636784cc98 100644 --- a/bots/stocks/technical_analysis/aroon.py +++ b/bots/stocks/technical_analysis/aroon.py @@ -7,6 +7,8 @@ from bots import helpers, load_candle from gamestonk_terminal.common.technical_analysis import trend_indicators_model from gamestonk_terminal.decorators import log_start_end +# pylint: disable=R0913 + logger = logging.getLogger(__name__) @@ -28,7 +30,7 @@ def aroon_command( # Debug if cfg.DEBUG: logger.debug( - "ta aroon %s %s %s %s %s", + "ta aroon %s %s %s %s %s, %s, %s, %s, %s, %s", ticker, interval, past_days, diff --git a/bots/stocks/technical_analysis/bbands.py b/bots/stocks/technical_analysis/bbands.py index 81934301726..c7394932633 100644 --- a/bots/stocks/technical_analysis/bbands.py +++ b/bots/stocks/technical_analysis/bbands.py @@ -31,7 +31,7 @@ def bbands_command( if cfg.DEBUG: # pylint: disable=logging-too-many-args logger.debug( - "ta bbands %s %s %s %s %s %s %s %s %s %s %s", + "ta bbands %s %s %s %s %s %s %s %s %s %s", ticker, past_days, length, diff --git a/bots/stocks/technical_analysis/cci.py b/bots/stocks/technical_analysis/cci.py index 2e0fdd7ebe8..750f6054282 100644 --- a/bots/stocks/technical_analysis/cci.py +++ b/bots/stocks/technical_analysis/cci.py @@ -1,12 +1,12 @@ import logging import plotly.graph_objects as go - -import bots.config_discordbot as cfg from bots import helpers, load_candle +import bots.config_discordbot as cfg from gamestonk_terminal.common.technical_analysis import momentum_model from gamestonk_terminal.decorators import log_start_end +# pylint: disable=R0913 logger = logging.getLogger(__name__) @@ -28,7 +28,7 @@ def cci_command( # Debug if cfg.DEBUG: logger.debug( - "ta cci %s %s %s %s %s %s %s %s %s %s %s", + "ta cci %s %s %s %s %s %s %s %s %s %s", ticker, interval, past_days, diff --git a/bots/stocks/technical_analysis/fisher.py b/bots/stocks/technical_analysis/fisher.py index 30fe15aaa8e..49de9968896 100644 --- a/bots/stocks/technical_analysis/fisher.py +++ b/bots/stocks/technical_analysis/fisher.py @@ -7,6 +7,7 @@ from bots import helpers, load_candle from gamestonk_terminal.common.technical_analysis import momentum_model from gamestonk_terminal.decorators import log_start_end +# pylint: disable=R0913 logger = logging.getLogger(__name__) diff --git a/bots/stocks/technical_analysis/kc.py b/bots/stocks/technical_analysis/kc.py index 4bceb1f36fc..df7a2ebe755 100644 --- a/bots/stocks/technical_analysis/kc.py +++ b/bots/stocks/technical_analysis/kc.py @@ -7,6 +7,7 @@ from bots import helpers, load_candle from gamestonk_terminal.common.technical_analysis import volatility_model from gamestonk_terminal.decorators import log_start_end +# pylint: disable=R0913 logger = logging.getLogger(__name__) diff --git a/bots/stocks/technical_analysis/obv.py b/bots/stocks/technical_analysis/obv.py index f73adcf6eba..7ba6d154b45 100644 --- a/bots/stocks/technical_analysis/obv.py +++ b/bots/stocks/technical_analysis/obv.py @@ -26,7 +26,7 @@ def obv_command( # Debug if cfg.DEBUG: logger.debug( - "ta obv %s %s %s", + "ta obv %s %s %s %s %s %s %s", ticker, past_days, start, diff --git a/bots/stocks/technical_analysis/rsi.py b/bots/stocks/technical_analysis/rsi.py index 731f3ee089e..cd9faa5db36 100644 --- a/bots/stocks/technical_analysis/rsi.py +++ b/bots/stocks/technical_analysis/rsi.py @@ -1,12 +1,12 @@ import logging import plotly.graph_objects as go - import bots.config_discordbot as cfg from bots import helpers, load_candle from gamestonk_terminal.common.technical_analysis import momentum_model from gamestonk_terminal.decorators import log_start_end +# pylint: disable=R0913 logger = logging.getLogger(__name__) diff --git a/bots/stocks/technical_analysis/stoch.py b/bots/stocks/technical_analysis/stoch.py index 3ef9f64b92b..fa5226b2892 100644 --- a/bots/stocks/technical_analysis/stoch.py +++ b/bots/stocks/technical_analysis/stoch.py @@ -7,6 +7,7 @@ from bots import helpers, load_candle from gamestonk_terminal.common.technical_analysis import momentum_model from gamestonk_terminal.decorators import log_start_end +# pylint: disable=R0913 logger = logging.getLogger(__name__) @@ -29,7 +30,7 @@ def stoch_command( # Debug if cfg.DEBUG: logger.debug( - "ta stoch %s %s %s %s %s %s", + "ta stoch %s %s %s %s %s %s %s %s %s %s %s", ticker, interval, past_days, diff --git a/bots/telegram/run_telegram.py b/bots/telegram/run_telegram.py index d1bdaaaa1e3..8fde724b1d6 100644 --- a/bots/telegram/run_telegram.py +++ b/bots/telegram/run_telegram.py @@ -2,11 +2,11 @@ import logging import os import telebot +from dotenv import load_dotenv from bots.common.commands_dict import commands from bots.common.helpers import non_slash from bots.helpers import ShowView -from dotenv import load_dotenv load_dotenv() @@ -17,11 +17,11 @@ bot_commands = [ telebot.types.BotCommand("/about", "Bot information"), telebot.types.BotCommand("/cmds", "List of commands"), ] -for command in commands: +for key, value in commands.items(): bot_commands.append( telebot.types.BotCommand( - command.replace("-", "_"), - commands[command]["function"].__doc__.split("Parameters")[0][:256].strip(), + key.replace("-", "_"), + value["function"].__doc__.split("Parameters")[0][:256].strip(), ) ) bot.set_my_commands(commands=bot_commands)