Revision: 8040 Author: russblau Date: 2010-03-26 18:29:19 +0000 (Fri, 26 Mar 2010)
Log Message: ----------- Refactor and provide better documentation of the user interface functions, hoping this will make it easier for others to contribute in this area.
Modified Paths: -------------- branches/rewrite/pywikibot/bot.py branches/rewrite/pywikibot/data/api.py branches/rewrite/pywikibot/page.py branches/rewrite/pywikibot/pagegenerators.py branches/rewrite/pywikibot/site.py branches/rewrite/pywikibot/userinterfaces/terminal_interface.py branches/rewrite/scripts/category.py branches/rewrite/scripts/upload.py branches/rewrite/tests/site_tests.py
Modified: branches/rewrite/pywikibot/bot.py =================================================================== --- branches/rewrite/pywikibot/bot.py 2010-03-23 16:28:30 UTC (rev 8039) +++ branches/rewrite/pywikibot/bot.py 2010-03-26 18:29:19 UTC (rev 8040) @@ -39,25 +39,9 @@ fromlist=['UI'] ) ui = uiModule.UI()
+ # Logging module configuration
-class MaxLevelFilter(logging.Filter): - """Filter that only passes records at or below a specific level. - - (setting handler level only passes records at or *above* a specified level, - so this provides the opposite functionality) - - """ - def __init__(self, level=None): - self.level = level - - def filter(self, record): - if self.level: - return record.levelno <= self.level - else: - return True - - class RotatingFileHandler(logging.handlers.RotatingFileHandler): """Strip trailing newlines before outputting text to file""" def format(self, record): @@ -66,6 +50,13 @@
class LoggingFormatter(logging.Formatter): + """Format LogRecords for output to file. + + This formatter *ignores* the 'newline' key of the LogRecord, because + every record written to a file must end with a newline, regardless of + whether the output to the user's console does. + + """ def formatException(self, ei): """ Make sure that the exception trace is converted to unicode: @@ -85,15 +76,118 @@ return strExc + '\n'
+# Initialize the handlers and formatters for the logging system. +# +# This relies on the global variable 'ui' which is a UserInterface object +# defined in the 'userinterface' subpackage. +# +# The UserInterface object must define its own init_handlers() method +# which takes the root logger as its only argument, and which adds to that +# logger whatever handlers and formatters are needed to process output and +# display it to the user. The default (terminal) interface sends level +# STDOUT to sys.stdout (as all interfaces should) and sends all other +# levels to sys.stderr; levels WARNING and above are labeled with the +# level name. +# +# UserInterface objects must also define methods input(), inputChoice(), +# editText(), and askForCaptcha(), all of which are documented in +# userinterfaces/terminal_interface.py + +_handlers_initialized = False + +def init_handlers(strm=None): + """Initialize logging system for terminal-based bots. + + This function must be called before using pywikibot.output(); and must + be called again if the destination stream is changed. + + @param strm: Output stream. If None, re-uses the last stream if one + was defined, otherwise uses sys.stderr + + """ + # Note: this function is called by handleArgs(), so it should normally + # not need to be called explicitly + + # All user output is routed through the logging module. + # Each type of output is handled by an appropriate handler object. + # This structure is used to permit eventual development of other + # user interfaces (GUIs) without modifying the core bot code. + # The following output levels are defined: + # DEBUG - only for file logging; debugging messages + # STDOUT - output that must be sent to sys.stdout (for bots that may + # have their output redirected to a file or other destination) + # VERBOSE - optional progress information for display to user + # INFO - normal (non-optional) progress information for display to user + # INPUT - prompts requiring user response + # WARN - user warning messages + # ERROR - user error messages + # CRITICAL - fatal error messages + # Accordingly, do ''not'' use print statements in bot code; instead, + # use pywikibot.output function. + + global _handlers_initialized + + moduleName = calledModuleName() + if not moduleName: + moduleName = "terminal-interface" + + logging.addLevelName(VERBOSE, "VERBOSE") + # for messages to be displayed on terminal at "verbose" setting + # use INFO for messages to be displayed even on non-verbose setting + logging.addLevelName(STDOUT, "STDOUT") + # for messages to be displayed to stdout + logging.addLevelName(INPUT, "INPUT") + # for prompts requiring user response + + root_logger = logging.getLogger("pywiki") + root_logger.setLevel(DEBUG+1) # all records except DEBUG go to logger + root_logger.handlers = [] # remove any old handlers + + # configure handler(s) for display to user interface + ui.init_handlers(root_logger) + + # if user has enabled file logging, configure file handler + if moduleName in config.log or '*' in config.log: + if config.logfilename: + logfile = config.datafilepath(config.logfilename) + else: + logfile = config.datafilepath("%s-bot.log" % moduleName) + file_handler = RotatingFileHandler( + filename=logfile, maxBytes=2 << 20, backupCount=5) + + file_handler.setLevel(DEBUG) + form = LoggingFormatter( + fmt="%(asctime)s %(caller_file)18s, %(caller_line)4s " + "in %(caller_name)18s: %(levelname)-8s %(message)s", + datefmt="%Y-%m-%d %H:%M:%S" + ) + file_handler.setFormatter(form) + root_logger.addHandler(file_handler) + # Turn on debugging for each component requested by user + # or for all components if nothing was specified + for component in config.debug_log: + if component: + debuglogger = logging.getLogger("pywiki."+component) + else: + debuglogger = logging.getLogger("pywiki") + debuglogger.setLevel(DEBUG) + debuglogger.addHandler(file_handler) + + _handlers_initialized = True + + # User output/logging functions
-# Five output functions are defined. Each requires a unicode or string +# Six output functions are defined. Each requires a unicode or string # argument. All of these functions generate a message to the log file if # logging is enabled ("-log" or "-debug" command line arguments).
-# The functions output(), warning(), and error() all display a message to the -# user through the logger object; the only difference is the priority level, -# which can be used by the application layer to alter the display. +# The functions output(), stdout(), warning(), and error() all display a +# message to the user through the logger object; the only difference is the +# priority level, which can be used by the application layer to alter the +# display. The stdout() function should be used only for data that is +# the "result" of a script, as opposed to information messages to the +# user.
# The function log() by default does not display a message to the user, but # this can be altered by using the "-verbose" command line option. @@ -108,39 +202,40 @@ try: raise Exception except: - # go back two levels, one for _fmtoutput and one for whatever called it + # go back two levels, one for logoutput and one for whatever called it return sys.exc_traceback.tb_frame.f_back.f_back
if hasattr(sys, '_getframe'): # less portable but more efficient currentframe = lambda: sys._getframe(3) - # frame0 is this lambda, frame1 is _fmtoutput() in this module, + # frame0 is this lambda, frame1 is logoutput() in this module, # frame2 is the convenience function (output(), etc.) # so frame3 is whatever called the convenience function
# done filching
-def _fmtoutput(text, decoder=None, newline=True, toStdout=False, - _level=INFO, _logger=""): +def logoutput(text, decoder=None, newline=True, _level=INFO, _logger="", + **kwargs): """Format output and send to the logging module.
Backend function used by all the user-output convenience functions.
""" if _logger: - path = "pywiki." + _logger + logger = logging.getLogger("pywiki." + _logger) else: - path = "pywiki" + logger = logging.getLogger("pywiki")
# make sure logging system has been initialized if not _handlers_initialized: - init_handlers(strm=ui.output_stream) + init_handlers()
frame = currentframe() module = os.path.basename(frame.f_code.co_filename) context = {'caller_name': frame.f_code.co_name, 'caller_file': module, - 'caller_line': frame.f_lineno} + 'caller_line': frame.f_lineno, + 'newline': ("\n" if newline else "")}
if decoder: text = unicode(text, decoder) @@ -155,18 +250,15 @@ text = unicode(text, 'utf-8') except UnicodeDecodeError: text = unicode(text, 'iso8859-1') - if newline: - text += "\n" - if toStdout: - _level = STDOUT - logger = logging.getLogger(path) - ui.output(text, logger, _level, context)
-def output(text, decoder=None, newline=True, toStdout=False): + logger.log(_level, text, extra=context, **kwargs) + +def output(text, decoder=None, newline=True, toStdout=False, **kwargs): """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.
@@ -180,22 +272,37 @@ 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. + """ - _fmtoutput(text, decoder, newline, toStdout, INFO) + if toStdout: # maintained for backwards-compatibity only + logoutput(text, decoder, newline, STDOUT, **kwargs) + else: + logoutput(text, decoder, newline, INFO, **kwargs)
-def warning(text, decoder=None, newline=True, toStdout=False): - _fmtoutput(text, decoder, newline, toStdout, WARNING) +def stdout(text, decoder=None, newline=True, **kwargs): + """Output script results to the user via the userinterface.""" + logoutput(text, decoder, newline, STDOUT, **kwargs)
-def error(text, decoder=None, newline=True, toStdout=False): - _fmtoutput(text, decoder, newline, toStdout, ERROR) +def warning(text, decoder=None, newline=True, **kwargs): + """Output a warning message to the user via the userinterface.""" + logoutput(text, decoder, newline, WARNING, **kwargs)
-def log(text, decoder=None, newline=True, toStdout=False): - _fmtoutput(text, decoder, newline, toStdout, VERBOSE) +def error(text, decoder=None, newline=True, **kwargs): + """Output an error message to the user via the userinterface.""" + logoutput(text, decoder, newline, ERROR, **kwargs)
-def debug(text, layer, decoder=None, newline=True, toStdout=False): - _fmtoutput(text, decoder, newline, toStdout, DEBUG, layer) +def log(text, decoder=None, newline=True, **kwargs): + """Output a record to the log file.""" + logoutput(text, decoder, newline, VERBOSE, **kwargs)
+def debug(text, layer, decoder=None, newline=True, **kwargs): + """Output a debug record to the log file.""" + logoutput(text, decoder, newline, DEBUG, layer, **kwargs)
+ # User input functions
def input(question, password=False): @@ -212,7 +319,7 @@ """ # make sure logging system has been initialized if not _handlers_initialized: - init_handlers(strm=ui.output_stream) + init_handlers()
data = ui.input(question, password) return data @@ -237,123 +344,12 @@ """ # make sure logging system has been initialized if not _handlers_initialized: - init_handlers(strm=ui.output_stream) + init_handlers()
data = ui.inputChoice(question, answers, hotkeys, default).lower() return data
-_handlers_initialized = False - -def init_handlers(strm=None): - """Initialize logging system for terminal-based bots. - - This function must be called before using pywikibot.output(); and must - be called again if the destination stream is changed. - - @param strm: Output stream. If None, re-uses the last stream if one - was defined, otherwise uses sys.stderr - - """ - # Note: this function is called by handleArgs(), so it should normally - # not need to be called explicitly - - # All user output is routed through the logging module. - # Each type of output is handled by an appropriate handler object. - # This structure is used to permit eventual development of other - # user interfaces (GUIs) without modifying the core bot code. - # The following output levels are defined: - # DEBUG - only for file logging; debugging messages - # STDOUT - output that must be sent to sys.stdout (for bots that may - # have their output redirected to a file or other destination) - # VERBOSE - optional progress information for display to user - # INFO - normal (non-optional) progress information for display to user - # INPUT - prompts requiring user response - # WARN - user warning messages - # ERROR - user error messages - # CRITICAL - fatal error messages - # Accordingly, do ''not'' use print statements in bot code; instead, - # use pywikibot.output function. - - global _handlers_initialized - - global _stream - if strm: - _stream = strm - else: - try: - _stream - except NameError: - _stream = sys.stderr - moduleName = calledModuleName() - if not moduleName: - moduleName = "terminal-interface" - - logging.addLevelName(VERBOSE, "VERBOSE") - # for messages to be displayed on terminal at "verbose" setting - # use INFO for messages to be displayed even on non-verbose setting - logging.addLevelName(STDOUT, "STDOUT") - # for messages to be displayed to stdout - logging.addLevelName(INPUT, "INPUT") - # for prompts requiring user response - - root_logger = logging.getLogger("pywiki") - root_logger.setLevel(DEBUG+1) # all records except DEBUG go to logger - root_logger.handlers = [] # remove any old handlers - - # configure default handler for display to user interface - default_handler = ui.OutputHandlerClass(strm=_stream) - if config.verbose_output: - default_handler.setLevel(VERBOSE) - else: - default_handler.setLevel(INFO) - default_handler.addFilter(MaxLevelFilter(INPUT)) - default_handler.setFormatter(LoggingFormatter(fmt="%(message)s")) - root_logger.addHandler(default_handler) - - # if user has enabled file logging, configure file handler - if moduleName in config.log or '*' in config.log: - if config.logfilename: - logfile = config.datafilepath(config.logfilename) - else: - logfile = config.datafilepath("%s-bot.log" % moduleName) - file_handler = RotatingFileHandler( - filename=logfile, maxBytes=2 << 20, backupCount=5) - - file_handler.setLevel(DEBUG) - form = LoggingFormatter( - fmt="%(asctime)s %(caller_file)18s, %(caller_line)4s " - "in %(caller_name)18s: %(levelname)-8s %(message)s", - datefmt="%Y-%m-%d %H:%M:%S" - ) - file_handler.setFormatter(form) - root_logger.addHandler(file_handler) - # Turn on debugging for each component requested by user - # or for all components if nothing was specified - for component in config.debug_log: - if component: - debuglogger = logging.getLogger("pywiki."+component) - else: - debuglogger = logging.getLogger("pywiki") - debuglogger.setLevel(DEBUG) - debuglogger.addHandler(file_handler) - - # handler for level STDOUT - output_handler = ui.OutputHandlerClass(strm=sys.stdout) - output_handler.setLevel(STDOUT) - output_handler.addFilter(MaxLevelFilter(STDOUT)) - output_handler.setFormatter(LoggingFormatter(fmt="%(message)s")) - root_logger.addHandler(output_handler) - - # handler for levels WARNING and higher - warning_handler = ui.OutputHandlerClass(strm=_stream) - warning_handler.setLevel(logging.WARNING) - warning_handler.setFormatter( - LoggingFormatter(fmt="%(levelname)s: %(message)s")) - root_logger.addHandler(warning_handler) - - _handlers_initialized = True - # Command line parsing and help
def calledModuleName(): @@ -487,7 +483,7 @@ if username: config.usernames[config.family][config.mylang] = username
- init_handlers(strm=ui.output_stream) + init_handlers()
if config.verbose_output: import re @@ -542,7 +538,7 @@ -nolog Disable the logfile (if it is enabled by default).
-debug:item Enable the logfile and include extensive debugging data --debug for component "item" (or all components if the second form +-debug for component "item" (for all components if the second form is used).
-putthrottle:n Set the minimum time (in seconds) the bot will wait between @@ -558,14 +554,14 @@ if hasattr(module, 'docuReplacements'): for key, value in module.docuReplacements.iteritems(): helpText = helpText.replace(key, value.strip('\n\r')) - pywikibot.output(helpText, toStdout=True) # output to STDOUT + pywikibot.stdout(helpText) # output to STDOUT except Exception: if modname: - pywikibot.output(u'Sorry, no help available for %s' % modname, - toStdout=True) - logger.exception('showHelp:') - pywikibot.output(globalHelp, toStdout=True) + pywikibot.stdout(u'Sorry, no help available for %s' % modname) +# pywikibot.log('showHelp: %%(exception)s') + pywikibot.stdout(globalHelp)
+ class Bot(object): """ Generic Bot to be subclassed
Modified: branches/rewrite/pywikibot/data/api.py =================================================================== --- branches/rewrite/pywikibot/data/api.py 2010-03-23 16:28:30 UTC (rev 8039) +++ branches/rewrite/pywikibot/data/api.py 2010-03-26 18:29:19 UTC (rev 8040) @@ -33,9 +33,6 @@
_modules = {} # cache for retrieved API parameter information
-##logger = logging.getLogger("pywiki.data.api") -##print "level =", logger.getEffectiveLevel() -## class APIError(pywikibot.Error): """The wiki site returned an error message.""" def __init__(self, code, info, **kwargs): @@ -195,7 +192,9 @@ self.params[key] = self.params[key].encode( self.site.encoding()) except Exception: - logger.exception("key=%s, params=%s\n" % (key, self.params[key])) + pywikibot.error( +u"http_params: Key '%s' could not be encoded to '%s'; params=%r" + % (key, self.site.encoding(), self.params[key])) return urllib.urlencode(self.params)
def __str__(self):
Modified: branches/rewrite/pywikibot/page.py =================================================================== --- branches/rewrite/pywikibot/page.py 2010-03-23 16:28:30 UTC (rev 8039) +++ branches/rewrite/pywikibot/page.py 2010-03-26 18:29:19 UTC (rev 8040) @@ -745,8 +745,7 @@ raise # TODO: other "expected" error types to catch? except pywikibot.Error, err: - logger.exception(u"Error saving page %s\n" % link) - pywikibot.output(u"") + pywikibot.log(u"Error saving page %s\n" % link, exc_info=True) if not callback: raise pywikibot.PageNotSaved(link) if callback: @@ -1378,12 +1377,12 @@
def removeImage(self, image, put=False, summary=None, safe=True): """Old method to remove all instances of an image from page.""" - logger.warning(u"Page.removeImage() is no longer supported.") + pywikibot.warning(u"Page.removeImage() is no longer supported.")
def replaceImage(self, image, replacement=None, put=False, summary=None, safe=True): """Old method to replace all instances of an image with another.""" - logger.warning(u"Page.replaceImage() is no longer supported.") + pywikibot.warning(u"Page.replaceImage() is no longer supported.")
class ImagePage(Page):
Modified: branches/rewrite/pywikibot/pagegenerators.py =================================================================== --- branches/rewrite/pywikibot/pagegenerators.py 2010-03-23 16:28:30 UTC (rev 8039) +++ branches/rewrite/pywikibot/pagegenerators.py 2010-03-26 18:29:19 UTC (rev 8040) @@ -1071,11 +1071,11 @@ gen = genFactory.getCombinedGenerator() if gen: for page in gen: - pywikibot.output(page.title(), toStdout=True) + pywikibot.stdout(page.title()) else: pywikibot.showHelp() except Exception: - pywikibot.logging.exception("") + pywikibot.error("Fatal error", exc_info=True) finally: pywikibot.stopme()
Modified: branches/rewrite/pywikibot/site.py =================================================================== --- branches/rewrite/pywikibot/site.py 2010-03-23 16:28:30 UTC (rev 8039) +++ branches/rewrite/pywikibot/site.py 2010-03-26 18:29:19 UTC (rev 8040) @@ -61,10 +61,10 @@ myfamily = __import__("%s_family" % fam) except ImportError: if fatal: - logger.exception(u"""\ + pywikibot.error(u"""\ Error importing the %s family. This probably means the family does not exist. Also check your configuration file.""" - % fam) + % fam, exc_info=True) sys.exit(1) else: raise Error("Family %s does not exist" % fam)
Modified: branches/rewrite/pywikibot/userinterfaces/terminal_interface.py =================================================================== --- branches/rewrite/pywikibot/userinterfaces/terminal_interface.py 2010-03-23 16:28:30 UTC (rev 8039) +++ branches/rewrite/pywikibot/userinterfaces/terminal_interface.py 2010-03-26 18:29:19 UTC (rev 8040) @@ -12,6 +12,7 @@ import threading import pywikibot from pywikibot import config +from pywikibot.bot import DEBUG, VERBOSE, INFO, STDOUT, INPUT, WARNING from pywikibot.userinterfaces import transliteration
@@ -114,22 +115,47 @@
colorTagR = re.compile('\03{(?P<name>%s)}' % '|'.join(windowsColors.keys()))
-class UI: - def __init__(self): - self.writelock = threading.RLock() - self.OutputHandlerClass = TerminalHandler - self.output_stream = sys.stderr +class UI(object): + def init_handlers(self, root_logger): + """Initialize the handlers for user output.
- def output(self, text, logger, level=logging.INFO, context=None): - """Send text to the logger for output to terminal.""" - self.writelock.acquire() - try: - logger.log(level, text, extra=context) - finally: - self.writelock.release() + This method initializes handler(s) for output levels VERBOSE (if + enabled by config.verbose_output), INFO, STDOUT, WARNING, ERROR, + and CRITICAL. STDOUT writes its output to sys.stdout; all the + others write theirs to sys.stderr.
+ """ + # default handler for display to terminal + default_handler = TerminalHandler(strm=sys.stderr) + if config.verbose_output: + default_handler.setLevel(VERBOSE) + else: + default_handler.setLevel(INFO) + # this handler ignores levels above INPUT + default_handler.addFilter(MaxLevelFilter(INPUT)) + default_handler.setFormatter( + TerminalFormatter(fmt="%(message)s%(newline)s")) + root_logger.addHandler(default_handler) + + # handler for level STDOUT + output_handler = TerminalHandler(strm=sys.stdout) + output_handler.setLevel(STDOUT) + output_handler.addFilter(MaxLevelFilter(STDOUT)) + output_handler.setFormatter( + TerminalFormatter(fmt="%(message)s%(newline)s")) + root_logger.addHandler(output_handler) + + # handler for levels WARNING and higher + warning_handler = TerminalHandler(strm=sys.stderr) + warning_handler.setLevel(logging.WARNING) + warning_handler.setFormatter( + TerminalFormatter(fmt="%(levelname)s: %(message)s%(newline)s")) + root_logger.addHandler(warning_handler) + def input(self, question, password = False): """ + Ask the user a question and return the answer. + Works like raw_input(), but returns a unicode string instead of ASCII.
Unlike raw_input, this function automatically adds a space after the @@ -142,23 +168,25 @@
# While we're waiting for user input, # we don't want terminal writes from other Threads - self.writelock.acquire() - pywikibot.bot._fmtoutput(question + ' ', newline=False, - _level=pywikibot.INPUT) - + TerminalHandler.sharedlock.acquire() try: + pywikibot.logoutput(question + ' ', newline=False, + _level=pywikibot.INPUT) if password: import getpass text = getpass.getpass('') else: text = raw_input() finally: - self.writelock.release() + TerminalHandler.sharedlock.release()
text = unicode(text, config.console_encoding) return text
def inputChoice(self, question, options, hotkeys, default=None): + """ + Ask the user a question with a predefined list of acceptable answers. + """ options = options[:] # we don't want to edit the passed parameter for i in range(len(options)): option = options[i] @@ -197,13 +225,15 @@ return answer
def editText(self, text, jumpIndex = None, highlight = None): - """ + """Return the text as edited by the user. + Uses a Tkinter edit box because we don't have a console editor
Parameters: * text - a Unicode string * jumpIndex - an integer: position at which to put the caret * highlight - a substring; each occurence will be highlighted + """ try: import gui @@ -214,6 +244,7 @@ return editor.edit(text, jumpIndex=jumpIndex, highlight=highlight)
def askForCaptcha(self, url): + """Show the user a CAPTCHA image and return the answer.""" try: import webbrowser pywikibot.output(u'Opening CAPTCHA in your web browser...') @@ -237,6 +268,10 @@
"""
+ # create a class-level lock that can be shared by all instances + import threading + sharedlock = threading.RLock() + def __init__(self, strm=None): """Initialize the handler.
@@ -244,6 +279,10 @@
""" logging.Handler.__init__(self) + # replace Handler's instance-specific lock with the shared class lock + # to ensure that only one instance of this handler can write to + # the console at a time + self.lock = TerminalHandler.sharedlock if strm is None: strm = sys.stderr self.stream = strm @@ -383,3 +422,24 @@ self.emitColorizedInUnix(record, text) else: self.emit_raw(record, text) + + +class TerminalFormatter(logging.Formatter): + pass + + +class MaxLevelFilter(logging.Filter): + """Filter that only passes records at or below a specific level. + + (setting handler level only passes records at or *above* a specified level, + so this provides the opposite functionality) + + """ + def __init__(self, level=None): + self.level = level + + def filter(self, record): + if self.level: + return record.levelno <= self.level + else: + return True
Modified: branches/rewrite/scripts/category.py =================================================================== --- branches/rewrite/scripts/category.py 2010-03-23 16:28:30 UTC (rev 8039) +++ branches/rewrite/scripts/category.py 2010-03-26 18:29:19 UTC (rev 8040) @@ -1048,7 +1048,7 @@ try: main() except pywikibot.Error: - pywikibot.logging.exception("Fatal error:") + pywikibot.error("Fatal error:", exc_info=True) finally: catDB.dump() pywikibot.stopme()
Modified: branches/rewrite/scripts/upload.py =================================================================== --- branches/rewrite/scripts/upload.py 2010-03-23 16:28:30 UTC (rev 8039) +++ branches/rewrite/scripts/upload.py 2010-03-26 18:29:19 UTC (rev 8040) @@ -221,7 +221,7 @@ return
except Exception, e: - pywikibot.logger.exception("Upload error: " + str(e)) + pywikibot.error("Upload error: ", exc_info=True)
else: #No warning, upload complete.
Modified: branches/rewrite/tests/site_tests.py =================================================================== --- branches/rewrite/tests/site_tests.py 2010-03-23 16:28:30 UTC (rev 8039) +++ branches/rewrite/tests/site_tests.py 2010-03-26 18:29:19 UTC (rev 8040) @@ -14,8 +14,6 @@ import pywikibot import warnings
-logger = pywikibot.logging.getLogger("wiki.site.tests") - mysite = pywikibot.Site() mainpage = pywikibot.Page(pywikibot.Link("Main Page", mysite)) imagepage = iter(mainpage.imagelinks()).next() # 1st image on main page @@ -57,7 +55,7 @@
def testLanguageMethods(self): """Test cases for languages() and related methods""" - + langs = mysite.languages() self.assertType(langs, list) self.assertTrue(mysite.code in langs) @@ -112,7 +110,7 @@
def testApiMethods(self): """Test generic ApiSite methods""" - + self.assertType(mysite.logged_in(), bool) self.assertType(mysite.logged_in(True), bool) self.assertType(mysite.userinfo, dict) @@ -129,7 +127,7 @@ self.assertType(mysite.has_group("bots", True), bool) self.assertFalse(mysite.has_group("nonexistent_group", True)) except pywikibot.NoUsername: - logger.warn( + pywikibot.warning( "Cannot test Site methods for sysop; no sysop account configured.") for msg in ("1movedto2", "about", "aboutpage", "aboutsite", "accesskey-n-portal"): @@ -147,7 +145,7 @@
def testPageMethods(self): """Test ApiSite methods for getting page-specific info""" - + self.assertType(mysite.page_exists(mainpage), bool) self.assertType(mysite.page_restrictions(mainpage), dict) self.assertType(mysite.page_can_be_edited(mainpage), bool) @@ -164,7 +162,7 @@
def testTokens(self): """Test ability to get page tokens""" - + for ttype in ("edit", "move"): # token types for non-sysops self.assertType(mysite.token(mainpage, ttype), basestring) self.assertRaises(KeyError, mysite.token, mainpage, "invalidtype") @@ -184,7 +182,7 @@
def testLinkMethods(self): """Test site methods for getting links to and from a page""" - + backlinks = set(mysite.pagebacklinks(mainpage, namespaces=[0])) # only non-redirects: filtered = set(mysite.pagebacklinks(mainpage, namespaces=0, @@ -258,7 +256,7 @@
def testLoadRevisions(self): """Test the site.loadrevisions() method""" - + mysite.loadrevisions(mainpage) self.assertTrue(hasattr(mainpage, "_revid")) self.assertTrue(hasattr(mainpage, "_revisions")) @@ -334,7 +332,7 @@
def testAllLinks(self): """Test the site.alllinks() method""" - + fwd = list(mysite.alllinks(total=10)) self.assertTrue(len(fwd) <= 10) self.assertTrue(all(isinstance(link, pywikibot.Page) for link in fwd)) @@ -361,7 +359,7 @@
def testAllCategories(self): """Test the site.allcategories() method""" - + ac = list(mysite.allcategories(total=10)) self.assertTrue(len(ac) <= 10) self.assertTrue(all(isinstance(cat, pywikibot.Category) @@ -379,7 +377,7 @@
def testAllUsers(self): """Test the site.allusers() method""" - + au = list(mysite.allusers(total=10)) self.assertTrue(len(au) <= 10) for user in au: @@ -828,7 +826,7 @@ try: mysite.login(True) except pywikibot.NoUsername: - logger.warn( + pywikibot.warning( "Cannot test Site.deleted_revs; no sysop account configured.") return dr = list(mysite.deletedrevs(total=10, page=mainpage)) @@ -909,7 +907,6 @@
if __name__ == '__main__': -# pywikibot.logging.getLogger("").setLevel(pywikibot.logging.DEBUG) try: try: unittest.main()
pywikipedia-svn@lists.wikimedia.org