From 885c5d3223a952fbad9a9e9dbe044b5f7fc54a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?GOLDERWEB=20=E2=80=93=20Jonathan=20Golder?= Date: Fri, 19 Feb 2016 13:59:23 +0100 Subject: [PATCH 1/3] Add a wrapper function for pywikibot output functions to add a timestamp to each message --- __init__.py | 27 +++++++++++++++++++++++++++ jogobot.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 __init__.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..5731896 --- /dev/null +++ b/__init__.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# __init__.py +# +# Copyright 2015 GOLDERWEB – Jonathan Golder +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# +# +""" +Scripts for our redundances bot +""" +from jogobot.jogobot import output # noqa diff --git a/jogobot.py b/jogobot.py index bb99d6f..6a00f90 100644 --- a/jogobot.py +++ b/jogobot.py @@ -23,11 +23,46 @@ # import os +from datetime import datetime from email.mime.text import MIMEText from subprocess import Popen, PIPE, TimeoutExpired import pywikibot +from pywikibot.bot import( + DEBUG, INFO, WARNING, ERROR, CRITICAL, STDOUT, VERBOSE, logoutput ) + + +def output( text, level="STDOUT", decoder=None, newline=True, + layer=None, **kwargs ): + """ + Wrapper for pywikibot output functions + """ + + text = datetime.utcnow().strftime( "%Y-%m-%d %H:%M:%S (UTC) " ) + text + + if ( level.upper() == "STDOUT" ): + _level = STDOUT + elif( level.upper() == "INFO" ): + _level = INFO + elif( level.upper() == "WARNING" ): + _level = WARNING + elif( level.upper() == "ERROR" ): + _level = ERROR + elif( level.upper() == "LOG" or level.upper() == "VERBOSE" ): + _level = VERBOSE + elif( level.upper() == "CRITICAL" ): + _level = CRITICAL + elif( level.upper() == "DEBUG" ): + _level = DEBUG + else: + pass + + if ( level == DEBUG ): + logoutput(text, decoder, newline, _level, layer, **kwargs) + else: + logoutput(text, decoder, newline, _level, **kwargs) + class JogoBot: """ From 3721683a2883dab1416822bdc4cf3e85bd246410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?GOLDERWEB=20=E2=80=93=20Jonathan=20Golder?= Date: Fri, 19 Feb 2016 17:02:19 +0100 Subject: [PATCH 2/3] Since we like to have timestamps in Output for logging, we replace pywikibot.output with jogobot.output via monkey patching --- jogobot.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/jogobot.py b/jogobot.py index 6a00f90..cf4e102 100644 --- a/jogobot.py +++ b/jogobot.py @@ -33,7 +33,7 @@ from pywikibot.bot import( DEBUG, INFO, WARNING, ERROR, CRITICAL, STDOUT, VERBOSE, logoutput ) -def output( text, level="STDOUT", decoder=None, newline=True, +def output( text, level="INFO", decoder=None, newline=True, layer=None, **kwargs ): """ Wrapper for pywikibot output functions @@ -64,6 +64,41 @@ def output( text, level="STDOUT", decoder=None, newline=True, logoutput(text, decoder, newline, _level, **kwargs) +# Since we like to have timestamps in Output for logging, we replace +# pywikibot.output with jogobot.output via monkey patching +def pywikibot_output( text, decoder=None, newline=True, + toStdout=False, **kwargs ): + r"""Output a message to the user via the userinterface. + + Works like print, but uses the encoding used by the user's console + (console_encoding in the configuration file) instead of ASCII. + + If decoder is None, text should be a unicode string. Otherwise it + should be encoded in the given encoding. + + If newline is True, a line feed will be added after printing the text. + + If toStdout is True, the text will be sent to standard output, + so that it can be piped to another process. All other text will + be sent to stderr. See: https://en.wikipedia.org/wiki/Pipeline_%28Unix%29 + + text can contain special sequences to create colored output. These + consist of the escape character \03 and the color name in curly braces, + e. g. \03{lightpurple}. \03{default} resets the color. + + Other keyword arguments are passed unchanged to the logger; so far, the + only argument that is useful is "exc_info=True", which causes the + log message to include an exception traceback. + + """ + if toStdout: # maintained for backwards-compatibity only + output(text, "STDOUT", decoder, newline, **kwargs) + else: + output(text, "INFO", decoder, newline, **kwargs) + +pywikibot.output = pywikibot_output + + class JogoBot: """ Basic bot framework From 800cc465742f87025500b415b85101c1dbafe1a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?GOLDERWEB=20=E2=80=93=20Jonathan=20Golder?= Date: Mon, 22 Feb 2016 11:13:14 +0100 Subject: [PATCH 3/3] Move sendmail function out of class since it doesn't need any data from it an it was a static method anyway --- __init__.py | 3 +- jogobot.py | 116 ++++++++++++++++++++++++++-------------------------- 2 files changed, 60 insertions(+), 59 deletions(-) diff --git a/__init__.py b/__init__.py index 5731896..1586217 100644 --- a/__init__.py +++ b/__init__.py @@ -24,4 +24,5 @@ """ Scripts for our redundances bot """ -from jogobot.jogobot import output # noqa +# noqa needed to prevent pyflakes from warning about unused imports +from jogobot.jogobot import ( output, sendmail ) # noqa diff --git a/jogobot.py b/jogobot.py index cf4e102..a4cb6a2 100644 --- a/jogobot.py +++ b/jogobot.py @@ -99,6 +99,64 @@ def pywikibot_output( text, decoder=None, newline=True, pywikibot.output = pywikibot_output +def sendmail( Subject, Body, To=None, CC=None, BCC=None, + From="JogoBot " ): + """ + Provides a simple wrapper for exim (MTA) on tool labs + Params should be formated according related fields in RFC 5322 + + @param subject Mail subject + @type subject str + @param body Mail body as (formated) string + @type body unicode-str + @param to Mail-Recipiends (comma-separeded) + @type str + @param from Mail-Sender + @type str + """ + + # Create mail body as MIME-Object + msg = MIMEText(Body) + + # Set up mail header + msg['Subject'] = Subject + + msg['From'] = From + + if To: + msg['To'] = To + + if CC: + msg['CC'] = CC + + if BCC: + msg['BCC'] = BCC + + msg['Content-Type'] = 'text/plain; charset=utf-8' + + # Make sure we have a recipient + if not( To or CC or BCC): + raise JogoBotMailError( "No recipient was provided!" ) + + # Send the message via exim + with Popen( ["/usr/sbin/exim", "-odf", "-i", "-t"], + stdin=PIPE, universal_newlines=True) as MTA: + MTA.communicate(msg.as_string()) + + # Try to get returncode of MTA + # Process is not terminated until timeout, set returncode to None + try: + returncode = MTA.wait(timeout=30) + except TimeoutExpired: + returncode = None + + # Catch MTA errors + if returncode: + raise JogoBotMailError( "/usr/sbin/exim terminated with " + + "returncode != 0. Returncode was " + + str( returncode ) ) + + class JogoBot: """ Basic bot framework @@ -205,64 +263,6 @@ class JogoBot: with open(disable_file, 'a'): pass - @staticmethod - def sendmail( Subject, Body, To=None, CC=None, BCC=None, - From="JogoBot " ): - """ - Provides a simple wrapper for exim (MTA) on tool labs - Params should be formated according related fields in RFC 5322 - - @param subject Mail subject - @type subject str - @param body Mail body as (formated) string - @type body unicode-str - @param to Mail-Recipiends (comma-separeded) - @type str - @param from Mail-Sender - @type str - """ - - # Create mail body as MIME-Object - msg = MIMEText(Body) - - # Set up mail header - msg['Subject'] = Subject - - msg['From'] = From - - if To: - msg['To'] = To - - if CC: - msg['CC'] = CC - - if BCC: - msg['BCC'] = BCC - - msg['Content-Type'] = 'text/plain; charset=utf-8' - - # Make sure we have a recipient - if not( To or CC or BCC): - raise JogoBotMailError( "No recipient was provided!" ) - - # Send the message via exim - with Popen( ["/usr/sbin/exim", "-odf", "-i", "-t"], - stdin=PIPE, universal_newlines=True) as MTA: - MTA.communicate(msg.as_string()) - - # Try to get returncode of MTA - # Process is not terminated until timeout, set returncode to None - try: - returncode = MTA.wait(timeout=30) - except TimeoutExpired: - returncode = None - - # Catch MTA errors - if returncode: - raise JogoBotMailError( "/usr/sbin/exim terminated with " + - "returncode != 0. Returncode was " + - str( returncode ) ) - class JogoBotMailError( Exception ): """