Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'fs#84-standardized-bot-wrapper' into test-v1
- Loading branch information
Showing
2 changed files
with
281 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,279 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: utf-8 -*- | ||
# | ||
# bot.py | ||
# | ||
# Copyright 2016 GOLDERWEB – Jonathan Golder <jonathan@golderweb.de> | ||
# | ||
# 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. | ||
# | ||
# | ||
""" | ||
Wrapper functions to invoke bot tasks | ||
""" | ||
|
||
import sys | ||
|
||
from pywikibot import pagegenerators | ||
|
||
import jogobot | ||
|
||
|
||
def active(task_slug): | ||
""" | ||
Checks up if bot with given task_slug is active via jogobot.framework | ||
@param task_slug Task slug to check | ||
@type task_slug str | ||
@return True if active, otherwise False | ||
@rtype bool | ||
""" | ||
|
||
try: | ||
# Will throw Exception if disabled/blocked | ||
jogobot.is_active( task_slug ) | ||
|
||
except jogobot.jogobot.Blocked: | ||
(type, value, traceback) = sys.exc_info() | ||
jogobot.output( "\03{lightpurple} %s (%s)" % (value, type ), | ||
"CRITICAL" ) | ||
return False | ||
|
||
except jogobot.jogobot.Disabled: | ||
(type, value, traceback) = sys.exc_info() | ||
jogobot.output( "\03{red} %s (%s)" % (value, type ), | ||
"ERROR" ) | ||
return False | ||
|
||
# Bot/Task is active | ||
else: | ||
return True | ||
|
||
|
||
def parse_local_args( local_args, callback=None ): | ||
""" | ||
Parses local cmd args which are not parsed by pywikibot | ||
@param local_args Local args returned by pywikibot.handle_args(args) | ||
@type iterable | ||
@param callback A callback method could be provided. It will get a single | ||
arg and the related value as params: | ||
callback( arg, value ) | ||
The method should return a tuple of key, value which can | ||
be directly appended to the kwargs dict. | ||
Or if arg is not relevant, return None or False. Then the | ||
arg will be passed to genFactory.handleArg() | ||
@type callable | ||
@returns The following tuple | ||
@return 1 Slug of given subtask (Arg "-task") | ||
@rtype str | ||
@return 2 GenFactory with parsed pagegenerator args | ||
@rtype pagegenerators.GeneratorFactory | ||
@return 3 Additional args for subtasks | ||
@rtype dict | ||
@rtype tuple | ||
""" | ||
|
||
# This factory is responsible for processing command line arguments | ||
# that are also used by other scripts and that determine on which pages | ||
# to work on. | ||
genFactory = pagegenerators.GeneratorFactory() | ||
|
||
# If always is True, bot won't ask for confirmation of edit (automode) | ||
# always = False | ||
|
||
# If force_reload is True, bot will always parse Countrylist regardless | ||
# if parsing is needed or not | ||
# force_reload = False | ||
|
||
# Subtask selects the specific bot to run | ||
# Default is reddiscparser | ||
subtask = None | ||
|
||
# kwargs are passed to selected bot as **kwargs | ||
kwargs = dict() | ||
|
||
# Parse command line arguments | ||
for arg in local_args: | ||
|
||
# Split args | ||
argkey, sep, value = arg.partition(':') | ||
|
||
if argkey.startswith("-always"): | ||
kwargs['always'] = True | ||
elif argkey.startswith("-task"): | ||
subtask = value | ||
|
||
# Must be the last but one entry | ||
elif callable(callback): | ||
ret_val = callback( argkey, value ) | ||
|
||
# Was relevant for callback | ||
if ret_val: | ||
kwargs[ret_val[0]] = ret_val[1] | ||
# Otherwise pass to genFactory.handleArg(arg) | ||
else: | ||
genFactory.handleArg(arg) | ||
else: | ||
genFactory.handleArg(arg) | ||
|
||
# Return Tuple | ||
return ( subtask, genFactory, kwargs ) | ||
|
||
|
||
# In current version it does not realy make sense to use this method, | ||
# as it just proxies the callback | ||
def prepare_bot( task_slug, subtask, genFactory, subtask_args, callback ): | ||
""" | ||
Handles importing subtask Bot class and prepares specific args | ||
Throws exception if bot not exists | ||
@param task_slug Task slug, needed for logging | ||
@type task_slug str | ||
@param subtask Slug of given subtask | ||
@type subtask str | ||
@param genFactory GenFactory with parsed pagegenerator args | ||
@type genFactory pagegenerators.GeneratorFactory | ||
@param subtask_args Additional args for subtasks | ||
@type subtask_args dict | ||
@param callback A reference to a callback method which gets the arg | ||
of this method (except the callback) and should | ||
return the same as this function | ||
@returns The following tuple | ||
@return 1 Subtask slug (replaced None for default) | ||
@rtype str | ||
@return 2 Botclass of given subtask (Arg "-task") | ||
@rtype Class | ||
@return 3 GenFactory with parsed pagegenerator args | ||
@rtype pagegenerators.GeneratorFactory | ||
@return 4 Additional args for subtasks | ||
@rtype dict | ||
@rtype tuple | ||
""" | ||
# kwargs are passed to selected bot as **kwargs | ||
kwargs = dict() | ||
|
||
if callable( callback ): | ||
( subtask, Bot, genFactory, subtask_args ) = callback( | ||
task_slug, subtask, genFactory, subtask_args ) | ||
# Subtask error | ||
else: | ||
jogobot.output( ( | ||
"\03{{red}} Given prepare_bot_callback from \"{task_slug}\" " + | ||
"is not callable!" ).format(task_slug=task_slug), "ERROR" ) | ||
raise Exception | ||
|
||
return ( subtask, Bot, genFactory, kwargs ) | ||
|
||
|
||
def init_bot( task_slug, subtask, Bot, genFactory, **kwargs ): | ||
""" | ||
Initiates Bot-Object with Class given in Bot and passes params genFactory | ||
and kwargs to it | ||
Passes through exception generated by Bot.__init__() after logging. | ||
@param task_slug Task slug, needed for logging | ||
@type task_slug str | ||
@param subtask Slug of given subtask | ||
@type subtask str | ||
@param Bot Bot class to build bot-object from | ||
@type Class | ||
@param genFactory GenFactory with parsed pagegenerator args | ||
@type genFactory pagegenerators.GeneratorFactory | ||
@param **kwargs Additional args for Bot() | ||
@type **kwargs dict | ||
@returns bot-object | ||
@type type(Bot()) | ||
""" | ||
# Bot gets prepared genFactory as first param and possible kwargs dict | ||
# It has to threw an exception if something does not work properly | ||
try: | ||
# Init bot with genFactory and **kwargs | ||
bot = Bot( genFactory, **kwargs ) | ||
|
||
except: | ||
# Catch Errors while initiation | ||
jogobot.output( ( | ||
"\03{{red}} Error while trying to init " + | ||
"subtask \"{task_slug}-{subtask}\"!" ). | ||
format( task_slug=task_slug, subtask=subtask ), "ERROR" ) | ||
raise | ||
else: | ||
# Init successfull | ||
jogobot.output( ( | ||
"Subtask \"{task_slug}-{subtask}\" was " + | ||
"initiated successfully" ). | ||
format(task_slug=task_slug, subtask=subtask) ) | ||
return bot | ||
|
||
|
||
def run_bot( task_slug, subtask, bot ): | ||
""" | ||
Calls the run()-method of bot-object | ||
Passes through exceptions generated by Bot.__init__() after logging. | ||
Catches Errors caused by missing run(0-method. | ||
@param task_slug Task slug, needed for logging | ||
@type task_slug str | ||
@param subtask Slug of given subtask | ||
@type subtask str | ||
@param bot Bot object to call run()-method on | ||
@type object with method run | ||
""" | ||
|
||
# Fire up Bot | ||
# Bot must have implemented a run()-method | ||
# It has to threw an exception if something does not work properly | ||
try: | ||
# Call run method on Bot | ||
bot.run() | ||
|
||
# Special event on AttributeError to catch missing run()-method | ||
except AttributeError: | ||
(type, value, traceback) = sys.exc_info() | ||
|
||
# Catch missing run()-method | ||
if "has no attribute 'run'" in value: | ||
jogobot.output( ( | ||
"\03{{red}} Error while trying to run " + | ||
"subtask \"{task_slug}-{subtask} \": +" | ||
"Run-method is missing! "). | ||
format( task_slug=task_slug, subtask=subtask ), "ERROR" ) | ||
|
||
# Pass through other AttributeError | ||
else: | ||
raise | ||
|
||
except: | ||
jogobot.output( ( | ||
"\03{{red}} Error while trying to run " + | ||
"subtask \"{task_slug}-{subtask} \"!" ). | ||
format( task_slug=task_slug, subtask=subtask ), "ERROR" ) | ||
raise | ||
|
||
else: | ||
# Run successfull | ||
jogobot.output( ( | ||
"Subtask \"{task_slug}-{subtask}\" was finished successfully"). | ||
format(task_slug=task_slug, subtask=subtask) ) |