From b4cac6fdbbd77aeaf49030e4ff2b488a2a2cf8df Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 15:01:22 +0000 Subject: [PATCH 01/17] Add update_players() function --- FPLbot/utils.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 FPLbot/utils.py diff --git a/FPLbot/utils.py b/FPLbot/utils.py new file mode 100644 index 0000000..8c5833c --- /dev/null +++ b/FPLbot/utils.py @@ -0,0 +1,21 @@ +import asyncio + +import aiohttp +from fpl import FPL +from pymongo import MongoClient, ReplaceOne + +client = MongoClient() +database = client.fpl + + +async def update_players(): + async with aiohttp.ClientSession() as session: + fpl = FPL(session) + players = await fpl.get_players(include_summary=True, return_json=True) + + requests = [ReplaceOne({"id": player["id"]}, player, upsert=True) + for player in players] + database.players.bulk_write(requests) + +if __name__ == "__main__": + asyncio.run(update_players()) From dc6cba0c90dd1e94df570669080a632a05c816eb Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 15:31:57 +0000 Subject: [PATCH 02/17] Create FPLbot class, add get_price_changers() --- FPLbot/bot.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 FPLbot/bot.py diff --git a/FPLbot/bot.py b/FPLbot/bot.py new file mode 100644 index 0000000..0365bce --- /dev/null +++ b/FPLbot/bot.py @@ -0,0 +1,34 @@ +import asyncio + +import aiohttp +from fpl import FPL +from pymongo import MongoClient + + +class FPLBot: + def __init__(self, config, session): + self.client = MongoClient() + self.config = config + self.fpl = FPL(session) + + async def get_price_changers(self): + """Returns a list of players whose price has changed since the last + time the database was updated. + """ + new_players = await self.fpl.get_players(include_summary=True) + old_players = self.client.fpl.players.find() + + risers = [] + fallers = [] + + for new_player in new_players: + old_player = next(player for player in old_players + if player["id"] == new_player.id) + + if old_player["cost_change_event"] > new_player.cost_change_event: + if old_player["now_cost"] > new_player.now_cost: + fallers.append(new_player) + else: + risers.append(new_player) + + return risers, fallers From 0c7d4d105af5f871af6d74bf2863721da4f02e71 Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 15:32:21 +0000 Subject: [PATCH 03/17] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 894a44c..346fbc2 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,5 @@ venv.bak/ # mypy .mypy_cache/ + +.vscode/ From f99d5f14bb260c55df0a58362a4d4e05f7d76145 Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 17:14:03 +0000 Subject: [PATCH 04/17] Add get_player_table() --- FPLbot/utils.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/FPLbot/utils.py b/FPLbot/utils.py index 8c5833c..c1f027c 100644 --- a/FPLbot/utils.py +++ b/FPLbot/utils.py @@ -2,6 +2,7 @@ import aiohttp from fpl import FPL +from fpl.utils import team_converter, position_converter from pymongo import MongoClient, ReplaceOne client = MongoClient() @@ -17,5 +18,24 @@ async def update_players(): for player in players] database.players.bulk_write(requests) + +def get_player_table(players, risers=True): + """Returns the table used in the player price change posts on Reddit.""" + table_header = ("|Name|Team|Position|Ownership|Price|∆|Form|\n" + "|:-|:-|:-|:-:|:-:|:-:|:-:|\n") + + table_body = "\n".join([ + f"|{player.web_name}|" + f"{team_converter(player.team)}|" + f"{position_converter(player.element_type)}|" + f"{player.selected_by_percent}%|" + f"£{player.now_cost / 10.0:.1f}|" + f"{'+' if risers else '-'}£{abs(player.cost_change_event / 10.0):.1f}|" + f"{sum([fixture['total_points'] for fixture in player.history[-5:]])}|" + for player in players]) + + return table_header + table_body + + if __name__ == "__main__": asyncio.run(update_players()) From 4331334725f3d96a3d13915035eaa4644bfdf7c0 Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 17:23:29 +0000 Subject: [PATCH 05/17] Update .gitignore for config.json --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 346fbc2..2bb111d 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,4 @@ venv.bak/ .mypy_cache/ .vscode/ +config.json From d48b12d9a24ff640210dfe847e32a8d4ea3054ec Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 17:23:40 +0000 Subject: [PATCH 06/17] Add config.json.example --- config.json.example | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 config.json.example diff --git a/config.json.example b/config.json.example new file mode 100644 index 0000000..0a205ba --- /dev/null +++ b/config.json.example @@ -0,0 +1,7 @@ +{ + "USERNAME": "", + "PASSWORD": "", + "CLIENT_ID": "", + "CLIENT_SECRET": "", + "USER_AGENT": "" +} From c0d47a10d63a637867a67ce288640bda12173864 Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 17:56:14 +0000 Subject: [PATCH 07/17] Add post_price_changes() for Reddit --- FPLbot/bot.py | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/FPLbot/bot.py b/FPLbot/bot.py index 0365bce..73895b0 100644 --- a/FPLbot/bot.py +++ b/FPLbot/bot.py @@ -1,15 +1,30 @@ import asyncio +import json +import os +from datetime import datetime import aiohttp +import praw from fpl import FPL +from fpl.utils import position_converter from pymongo import MongoClient +from utils import get_player_table + +dirname = os.path.dirname(os.path.realpath(__file__)) + class FPLBot: def __init__(self, config, session): self.client = MongoClient() - self.config = config self.fpl = FPL(session) + self.reddit = praw.Reddit( + client_id=config.get("CLIENT_ID"), + client_secret=config.get("CLIENT_SECRET"), + password=config.get("PASSWORD"), + user_agent=config.get("USER_AGENT"), + username=config.get("USERNAME")) + self.subreddit = self.reddit.subreddit(config.get("SUBREDDIT")) async def get_price_changers(self): """Returns a list of players whose price has changed since the last @@ -32,3 +47,33 @@ async def get_price_changers(self): risers.append(new_player) return risers, fallers + + async def post_price_changes(self): + risers, fallers = await self.get_price_changers() + risers_table = get_player_table(risers, True) + fallers_table = get_player_table(fallers, False) + + post_template = open(f"{dirname}/../post_template.md").read() + post_body = post_template.format( + risers_number=len(risers), + risers_table=risers_table, + fallers_number=len(fallers), + fallers_table=fallers_table + ) + + today = datetime.now() + current_date = f"({today:%B} {today.day}, {today.year})" + post_title = f"Player Price Changes {current_date}" + self.subreddit.submit(post_title, selftext=post_body) + + +async def main(config): + async with aiohttp.ClientSession() as session: + fpl_bot = FPLBot(config, session) + + await fpl_bot.post_price_changes() + + +if __name__ == "__main__": + config = json.loads(open(f"{dirname}/../config.json").read()) + asyncio.run(main(config)) From 6460fdfe0454612dca7b4a97e055df6ce79a5d1f Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 18:00:02 +0000 Subject: [PATCH 08/17] Add comments utils.py & bot.py --- FPLbot/bot.py | 3 +++ FPLbot/utils.py | 1 + 2 files changed, 4 insertions(+) diff --git a/FPLbot/bot.py b/FPLbot/bot.py index 73895b0..0a9bc79 100644 --- a/FPLbot/bot.py +++ b/FPLbot/bot.py @@ -40,6 +40,7 @@ async def get_price_changers(self): old_player = next(player for player in old_players if player["id"] == new_player.id) + # Player has changed price in the last day if old_player["cost_change_event"] > new_player.cost_change_event: if old_player["now_cost"] > new_player.now_cost: fallers.append(new_player) @@ -49,6 +50,7 @@ async def get_price_changers(self): return risers, fallers async def post_price_changes(self): + """Posts the price changes to Reddit.""" risers, fallers = await self.get_price_changers() risers_table = get_player_table(risers, True) fallers_table = get_player_table(fallers, False) @@ -64,6 +66,7 @@ async def post_price_changes(self): today = datetime.now() current_date = f"({today:%B} {today.day}, {today.year})" post_title = f"Player Price Changes {current_date}" + self.subreddit.submit(post_title, selftext=post_body) diff --git a/FPLbot/utils.py b/FPLbot/utils.py index c1f027c..9f24d08 100644 --- a/FPLbot/utils.py +++ b/FPLbot/utils.py @@ -10,6 +10,7 @@ async def update_players(): + """Updates all players in the database.""" async with aiohttp.ClientSession() as session: fpl = FPL(session) players = await fpl.get_players(include_summary=True, return_json=True) From 4df424f29f22f18e7b397b9454d4296d8184bdcf Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 18:00:13 +0000 Subject: [PATCH 09/17] Update config.json.example with SUBREDDIT --- config.json.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.json.example b/config.json.example index 0a205ba..368f5f6 100644 --- a/config.json.example +++ b/config.json.example @@ -3,5 +3,6 @@ "PASSWORD": "", "CLIENT_ID": "", "CLIENT_SECRET": "", - "USER_AGENT": "" + "USER_AGENT": "", + "SUBREDDIT": "", } From 547cafc65d8e3ad28356d1d5afa5a98335b90c9b Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 18:00:28 +0000 Subject: [PATCH 10/17] Add post_template.md --- post_template.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 post_template.md diff --git a/post_template.md b/post_template.md new file mode 100644 index 0000000..675160c --- /dev/null +++ b/post_template.md @@ -0,0 +1,13 @@ +### Risers ({risers_number}) +{risers_table} +  + +### Fallers ({fallers_number}) +{fallers_table} +  + +^∆ ^= ^price ^change ^this ^gameweek. ^Form ^= ^points ^last ^5 ^gameweeks. + +--- + +^Made ^by ^/u/esoemah. ^Source: ^https://github.com/amosbastian/FPLbot From 926de975a163a0126bcfda2a2e4cac17c4a2f0a6 Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 18:31:01 +0000 Subject: [PATCH 11/17] Add requirements.txt --- requirements.txt | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..80a427e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,28 @@ +aiohttp==3.5.4 +appdirs==1.4.3 +async-timeout==3.0.1 +atomicwrites==1.2.1 +attrs==18.2.0 +certifi==2018.11.29 +chardet==3.0.4 +Click==7.0 +colorama==0.4.1 +fpl==0.6.1 +idna==2.8 +more-itertools==5.0.0 +multidict==4.5.2 +pep8==1.7.1 +pluggy==0.8.1 +praw==6.1.1 +prawcore==1.0.0 +PTable==0.9.2 +py==1.7.0 +pymongo==3.7.2 +pytest==4.2.0 +pytest-aiohttp==0.3.0 +requests==2.21.0 +six==1.12.0 +update-checker==0.16 +urllib3==1.24.1 +websocket-client==0.54.0 +yarl==1.3.0 From 9735fa884e3495820a751c6c3243d4b2a306ceb1 Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 18:31:27 +0000 Subject: [PATCH 12/17] Update README.md --- README.md | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0890852..3b07c42 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,35 @@ -# FantasyPL_bot -A bot for the FantasyPL subreddit +# FPLbot + +FPLbot is a bot made for the subreddit [/r/FantasyPL](https://www.reddit.com/r/FantasyPL/). +It can also be used for other subreddits by changing the values in the +configuration file. + +Its current features are: + +* Posting the price changes of Fantasy Premier League players + +## Installation + +FPLbot uses MongoDB to store players in a database, and so it is required to +have MongoDB installed. Other than that, it uses [fpl](https://github.com/amosbastian/fpl) +to retrieve information from Fantasy Premier League's API, and thus requires +Python 3.6+. + + git clone git@github.com:amosbastian/FPLbot.git + cd FPLbot + pip install -r requirements.txt + +Once installed you can schedule a cron job to run the bot whenever you want! + +## Configuration + +|Option|Value| +|:-|:-| +|USERNAME|The bot's username| +|PASSWORD|The bot's password| +|CLIENT_ID|The bot's client ID| +|CLIENT_SECRET|The bot's client secret| +|USER_AGENT|A unique identifier that helps Reddit determine the source of network requests| +|SUBREDDIT|The subreddit the bot will post to| + +For more information about how to set up a bot see [Reddit's guide](https://github.com/reddit-archive/reddit/wiki/OAuth2-Quick-Start-Example#first-steps). From d6c800875931c6329fb8ac7fb36441f55353fa21 Mon Sep 17 00:00:00 2001 From: amosbastian Date: Thu, 31 Jan 2019 18:35:16 +0000 Subject: [PATCH 13/17] Update config.json.example --- config.json.example | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config.json.example b/config.json.example index 368f5f6..5645674 100644 --- a/config.json.example +++ b/config.json.example @@ -1,8 +1,8 @@ { - "USERNAME": "", - "PASSWORD": "", - "CLIENT_ID": "", - "CLIENT_SECRET": "", - "USER_AGENT": "", - "SUBREDDIT": "", + "USERNAME": "bigluke575", + "PASSWORD": "baldfraud", + "CLIENT_ID": "p-jcoLKBynTLew", + "CLIENT_SECRET": "gko_LXELoV07ZBNUXrvWZfzE3aI", + "USER_AGENT": "The original FPLbot.", + "SUBREDDIT": "FantasyPL", } From ff9564c7399a85745489a5542fc5a87dcb52f255 Mon Sep 17 00:00:00 2001 From: amosbastian Date: Fri, 1 Feb 2019 18:46:32 +0000 Subject: [PATCH 14/17] Fix StopIteration exception --- FPLbot/bot.py | 18 +++++++++++------- post_template.md | 4 ++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/FPLbot/bot.py b/FPLbot/bot.py index 0a9bc79..05d5b47 100644 --- a/FPLbot/bot.py +++ b/FPLbot/bot.py @@ -9,7 +9,7 @@ from fpl.utils import position_converter from pymongo import MongoClient -from utils import get_player_table +from utils import get_player_table, update_players dirname = os.path.dirname(os.path.realpath(__file__)) @@ -31,17 +31,20 @@ async def get_price_changers(self): time the database was updated. """ new_players = await self.fpl.get_players(include_summary=True) - old_players = self.client.fpl.players.find() + old_players = [player for player in self.client.fpl.players.find()] risers = [] fallers = [] for new_player in new_players: - old_player = next(player for player in old_players - if player["id"] == new_player.id) - - # Player has changed price in the last day - if old_player["cost_change_event"] > new_player.cost_change_event: + try: + old_player = next(player for player in old_players + if player["id"] == new_player.id) + # New player has been added to the game + except StopIteration: + continue + + if old_player["cost_change_event"] != new_player.cost_change_event: if old_player["now_cost"] > new_player.now_cost: fallers.append(new_player) else: @@ -68,6 +71,7 @@ async def post_price_changes(self): post_title = f"Player Price Changes {current_date}" self.subreddit.submit(post_title, selftext=post_body) + update_players() async def main(config): diff --git a/post_template.md b/post_template.md index 675160c..4b1cfb6 100644 --- a/post_template.md +++ b/post_template.md @@ -1,9 +1,13 @@ ### Risers ({risers_number}) + {risers_table} +   ### Fallers ({fallers_number}) + {fallers_table} +   ^∆ ^= ^price ^change ^this ^gameweek. ^Form ^= ^points ^last ^5 ^gameweeks. From 45237e7708b559e3957a934e791c3dfb165245b1 Mon Sep 17 00:00:00 2001 From: amosbastian Date: Fri, 1 Feb 2019 19:01:13 +0000 Subject: [PATCH 15/17] Add logger to utils.py and bot.py --- FPLbot/bot.py | 7 +++++++ FPLbot/utils.py | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/FPLbot/bot.py b/FPLbot/bot.py index 05d5b47..d752813 100644 --- a/FPLbot/bot.py +++ b/FPLbot/bot.py @@ -1,5 +1,6 @@ import asyncio import json +import logging import os from datetime import datetime @@ -12,6 +13,9 @@ from utils import get_player_table, update_players dirname = os.path.dirname(os.path.realpath(__file__)) +logger = logging.getLogger("FPLbot - bot") +logger.setLevel(logging.DEBUG) +logger.basicConfig() class FPLBot: @@ -30,6 +34,7 @@ async def get_price_changers(self): """Returns a list of players whose price has changed since the last time the database was updated. """ + logger.info("Retrieving risers and fallers.") new_players = await self.fpl.get_players(include_summary=True) old_players = [player for player in self.client.fpl.players.find()] @@ -42,6 +47,7 @@ async def get_price_changers(self): if player["id"] == new_player.id) # New player has been added to the game except StopIteration: + logger.info(f"New player added: {new_player.web_name}.") continue if old_player["cost_change_event"] != new_player.cost_change_event: @@ -70,6 +76,7 @@ async def post_price_changes(self): current_date = f"({today:%B} {today.day}, {today.year})" post_title = f"Player Price Changes {current_date}" + logger.info("Posting price changes to Reddit.") self.subreddit.submit(post_title, selftext=post_body) update_players() diff --git a/FPLbot/utils.py b/FPLbot/utils.py index 9f24d08..5d627c5 100644 --- a/FPLbot/utils.py +++ b/FPLbot/utils.py @@ -7,7 +7,9 @@ client = MongoClient() database = client.fpl - +logger = logging.getLogger("FPLbot - utils") +logger.setLevel(logging.DEBUG) +logger.basicConfig() async def update_players(): """Updates all players in the database.""" @@ -17,6 +19,8 @@ async def update_players(): requests = [ReplaceOne({"id": player["id"]}, player, upsert=True) for player in players] + + logger.info("Updating players in database.") database.players.bulk_write(requests) From 17155f16edd15ddcea79fbded5f498f3137b2309 Mon Sep 17 00:00:00 2001 From: amosbastian Date: Sat, 2 Feb 2019 20:24:44 +0000 Subject: [PATCH 16/17] Fix logging and risers / fallers --- FPLbot/bot.py | 21 ++++++++++----------- FPLbot/utils.py | 7 ++++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/FPLbot/bot.py b/FPLbot/bot.py index d752813..2da37fd 100644 --- a/FPLbot/bot.py +++ b/FPLbot/bot.py @@ -13,9 +13,9 @@ from utils import get_player_table, update_players dirname = os.path.dirname(os.path.realpath(__file__)) -logger = logging.getLogger("FPLbot - bot") -logger.setLevel(logging.DEBUG) -logger.basicConfig() +logger = logging.getLogger("FPLbot") +logger.setLevel(logging.INFO) +logging.basicConfig() class FPLBot: @@ -47,14 +47,13 @@ async def get_price_changers(self): if player["id"] == new_player.id) # New player has been added to the game except StopIteration: - logger.info(f"New player added: {new_player.web_name}.") + logger.info(f"New player added: {new_player}.") continue - if old_player["cost_change_event"] != new_player.cost_change_event: - if old_player["now_cost"] > new_player.now_cost: - fallers.append(new_player) - else: - risers.append(new_player) + if old_player["now_cost"] > new_player.now_cost: + fallers.append(new_player) + elif old_player["now_cost"] < new_player.now_cost: + risers.append(new_player) return risers, fallers @@ -76,9 +75,9 @@ async def post_price_changes(self): current_date = f"({today:%B} {today.day}, {today.year})" post_title = f"Player Price Changes {current_date}" - logger.info("Posting price changes to Reddit.") + logger.info(f"Posting price changes to Reddit.\n\n{post_body}") self.subreddit.submit(post_title, selftext=post_body) - update_players() + await update_players() async def main(config): diff --git a/FPLbot/utils.py b/FPLbot/utils.py index 5d627c5..b58f61f 100644 --- a/FPLbot/utils.py +++ b/FPLbot/utils.py @@ -1,15 +1,16 @@ import asyncio +import logging import aiohttp from fpl import FPL -from fpl.utils import team_converter, position_converter +from fpl.utils import position_converter, team_converter from pymongo import MongoClient, ReplaceOne client = MongoClient() database = client.fpl -logger = logging.getLogger("FPLbot - utils") +logger = logging.getLogger("FPLbot") logger.setLevel(logging.DEBUG) -logger.basicConfig() +logging.basicConfig() async def update_players(): """Updates all players in the database.""" From ca5d0976d8ebd046a70cb6b9a0c84e7325a2710c Mon Sep 17 00:00:00 2001 From: amosbastian Date: Sun, 3 Feb 2019 21:25:44 +0000 Subject: [PATCH 17/17] Update logger handling & add create_logger Now uses a function to create a logger in bot.py, so that other files can use getLogger to get a reference to the same logger object. --- FPLbot/bot.py | 6 ++---- FPLbot/utils.py | 31 +++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/FPLbot/bot.py b/FPLbot/bot.py index 2da37fd..9fb7542 100644 --- a/FPLbot/bot.py +++ b/FPLbot/bot.py @@ -10,12 +10,10 @@ from fpl.utils import position_converter from pymongo import MongoClient -from utils import get_player_table, update_players +from utils import create_logger, get_player_table, update_players dirname = os.path.dirname(os.path.realpath(__file__)) -logger = logging.getLogger("FPLbot") -logger.setLevel(logging.INFO) -logging.basicConfig() +logger = create_logger() class FPLBot: diff --git a/FPLbot/utils.py b/FPLbot/utils.py index b58f61f..09b7c26 100644 --- a/FPLbot/utils.py +++ b/FPLbot/utils.py @@ -1,5 +1,6 @@ import asyncio import logging +import os import aiohttp from fpl import FPL @@ -9,8 +10,34 @@ client = MongoClient() database = client.fpl logger = logging.getLogger("FPLbot") -logger.setLevel(logging.DEBUG) -logging.basicConfig() + + +def create_logger(): + """Creates a logger object for use in logging across all files. + + See: https://docs.python.org/3/howto/logging-cookbook.html + """ + dirname = os.path.dirname(os.path.realpath(__file__)) + + logger = logging.getLogger("FPLbot") + logger.setLevel(logging.DEBUG) + + fh = logging.FileHandler(f"{dirname}/FPLbot.log") + fh.setLevel(logging.DEBUG) + + ch = logging.StreamHandler() + ch.setLevel(logging.ERROR) + + formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - " + "%(message)s") + + fh.setFormatter(formatter) + ch.setFormatter(formatter) + + logger.addHandler(fh) + logger.addHandler(ch) + return logger + async def update_players(): """Updates all players in the database."""