From b72e7e244b66cbac6319751d45a53062bb6e7018 Mon Sep 17 00:00:00 2001 From: Collin Rapp Date: Sun, 10 May 2020 20:08:52 -0700 Subject: [PATCH] Improved logging & single-file executable --- .gitignore | 1 + CHANGELOG.md | 3 ++- freeze.cmd | 9 +++++++++ pointsbot/bot.py | 39 ++++++++++++++++++++++++--------------- pointsbot/config.py | 1 + pointsbot/reply.py | 6 ++++++ 6 files changed, 43 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 3117056..858f68a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ __pycache__ build/ dist/ +releases/ *.html *.out diff --git a/CHANGELOG.md b/CHANGELOG.md index f1b2c89..f2d665e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ ## 2020/05/10 Features: -1. Adding basic initial logging to a file +1. Adding basic initial logging + * Logs both to a file and to the command prompt Fixes: N/A diff --git a/freeze.cmd b/freeze.cmd index d7ed219..251dfe9 100644 --- a/freeze.cmd +++ b/freeze.cmd @@ -1,5 +1,7 @@ @echo off +set dest=".\dist\" + REM The below is an alternative to using a custom hook for praw REM FOR /F "tokens=* USEBACKQ" %%F IN (`pipenv --venv`) DO ( REM SET pipenvdir=%%F @@ -12,3 +14,10 @@ pyinstaller ^ --onefile ^ --additional-hooks-dir .\pyinstaller-hooks\ ^ PointsBot.py + +copy ".\README.md" %dest% +copy ".\LICENSE.md" %dest% +copy ".\CHANGELOG.md" %dest% + +mkdir .\releases\ +powershell Compress-Archive -Force .\dist\* .\releases\PointsBot_Windows_x64.zip diff --git a/pointsbot/bot.py b/pointsbot/bot.py index 187ed68..80ed039 100644 --- a/pointsbot/bot.py +++ b/pointsbot/bot.py @@ -2,6 +2,7 @@ import logging import os import os.path import re +import sys import praw import prawcore @@ -29,7 +30,12 @@ def run(): print_welcome_message() cfg = config.load() - logging.basicConfig(filename=cfg.log_path, + + file_handler = logging.FileHandler(cfg.log_path, 'w', 'utf-8') + console_handler = logging.StreamHandler(sys.stderr) + console_handler.setLevel(logging.INFO) + # logging.basicConfig(filename=cfg.log_path, + logging.basicConfig(handlers=[file_handler, console_handler], level=logging.DEBUG, format='%(asctime)s %(levelname)s:%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S') @@ -57,16 +63,20 @@ def run(): else: logging.warning('Is NOT moderator for monitored subreddit') - monitor_comments(subreddit, db, levels) + monitor_comments(subreddit, db, levels, cfg) # Ignoring other potential exceptions for now, since we may not be able # to recover from them as well as from this one except prawcore.exceptions.RequestException as e: - log.error('Unable to connect; attempting again....') + logging.error('Unable to connect to Reddit') + logging.error('Error message: %s', e) + logging.error('Trying again') except prawcore.exceptions.ServerError as e: - log.error('Lost connection to Reddit; attempting to reconnect....') + logging.error('Lost connection to Reddit') + logging.error('Error message: %s', e) + logging.error('Attempting to reconnect') -def monitor_comments(subreddit, db, levels): +def monitor_comments(subreddit, db, levels, cfg): """Monitor new comments in the subreddit, looking for confirmed solutions.""" # Passing pause_after=0 will bypass the internal exponential delay, but have # to check if any comments are returned with each query @@ -76,7 +86,8 @@ def monitor_comments(subreddit, db, levels): logging.info('Received comment') # TODO more debug info about comment, eg author - logging.debug('Comment text: "%s"', comm.body) + logging.debug('Comment author: "%s"', comm.author.name) + # logging.debug('Comment text: "%s"', comm.body) if not marks_as_solved(comm): logging.info('Comment does not mark issue as solved') @@ -103,17 +114,15 @@ def monitor_comments(subreddit, db, levels): level_info = level.user_level_info(points, levels) # Reply to the comment marking the submission as solved - reply_body = reply.make( - solver, - points, - level_info, - feedback_url=cfg.feedback_url, - scoreboard_url=cfg.scoreboard_url - ) + reply_body = reply.make(solver, + points, + level_info, + feedback_url=cfg.feedback_url, + scoreboard_url=cfg.scoreboard_url) try: comm.reply(reply_body) logging.info('Replied to the comment') - logging.debug('Reply body: %s', reply_body) + # logging.debug('Reply body: %s', reply_body) except praw.exceptions.APIException as e: logging.error('Unable to reply to comment: %s', e) db.remove_point(solver) @@ -211,7 +220,7 @@ def log_solution_info(comm): logging.debug('Solution comment:') logging.debug('Author: %s', comm.parent().author.name) logging.debug('Body: %s', comm.parent().body) - logging.debug('"Solved" comment:') + logging.debug('Comment marking solution as solved:') logging.debug('Author: %s', comm.author.name) logging.debug('Body: %s', comm.body) diff --git a/pointsbot/config.py b/pointsbot/config.py index 51fbe09..c8cc3cd 100644 --- a/pointsbot/config.py +++ b/pointsbot/config.py @@ -128,6 +128,7 @@ class Config: def interactive_config(dest): configvals = { 'core': {}, + 'links': {}, 'filepaths': {}, 'credentials': {}, 'levels': [], diff --git a/pointsbot/reply.py b/pointsbot/reply.py index 6b47a80..ce54ee5 100644 --- a/pointsbot/reply.py +++ b/pointsbot/reply.py @@ -12,6 +12,12 @@ EXCESS_POINTS = 100 # TODO move this to level and/or config? EXCESS_SYMBOL = '\u2605' # A star character EXCESS_SYMBOL_TITLE = 'a star' # Used in comment body +### +# TODO make this a ReplyFactory? pass in feedback & scoreboard URLs to the +# ReplyFactory constructor, then pass in redditor, points, level_info each time +# making a comment, ie probably make `make` or `build` a method of the factory +### + ### Main Functions ###