Revision: 6191 Author: russblau Date: 2008-12-23 19:37:49 +0000 (Tue, 23 Dec 2008)
Log Message: -----------
Modified Paths: -------------- branches/rewrite/pywikibot/README-conversion.txt branches/rewrite/pywikibot/__init__.py branches/rewrite/pywikibot/bot.py branches/rewrite/pywikibot/comms/http.py branches/rewrite/pywikibot/data/api.py branches/rewrite/pywikibot/login.py branches/rewrite/pywikibot/page.py branches/rewrite/pywikibot/site.py branches/rewrite/pywikibot/throttle.py branches/rewrite/pywikibot/userinterfaces/terminal_interface.py
Added Paths: ----------- branches/rewrite/pywikibot/userinterfaces/__init__.py
Modified: branches/rewrite/pywikibot/README-conversion.txt =================================================================== --- branches/rewrite/pywikibot/README-conversion.txt 2008-12-23 17:13:12 UTC (rev 6190) +++ branches/rewrite/pywikibot/README-conversion.txt 2008-12-23 19:37:49 UTC (rev 6191) @@ -31,6 +31,9 @@ change "import catlib" to "from pywikibot import catlib" change "wikipedia." to "pywikibot."
+wikipedia.setAction() no longer works; you must revise the script to pass an +explicit edit summary message on each put() or put_async() call. + == Python librairies ==
[Note: the goal will be to package pywikibot with setuptools easy_install, @@ -68,7 +71,7 @@ Category, as long as the page is in the category namespace.
The following methods of the Page object have been deprecated (deprecated -methods will still work, but print a warning message in debug mode): +methods still work, but print a warning message in debug mode):
- urlname(): replaced by Page.title(asUrl=True) - titleWithoutNamespace(): replaced by Page.title(withNamespace=False) @@ -94,8 +97,8 @@ === Category objects ===
The Category object has been moved from the catlib module to the pywikibot -namespace. Any references to "catlib.Category" need to be replaced by -"pywikibot.Category". +namespace. Any references to "catlib.Category" can be replaced by +"pywikibot.Category", but the old form is retained for backwards-compatibility.
For Category objects, the following methods are deprecated:
Modified: branches/rewrite/pywikibot/__init__.py =================================================================== --- branches/rewrite/pywikibot/__init__.py 2008-12-23 17:13:12 UTC (rev 6190) +++ branches/rewrite/pywikibot/__init__.py 2008-12-23 19:37:49 UTC (rev 6191) @@ -9,14 +9,15 @@ # __version__ = '$Id$'
-import sys +import difflib import logging import re +import sys
-from exceptions import * import config2 as config -import textlib from bot import * +from exceptions import * +from textlib import *
logging.basicConfig(fmt="%(message)s")
@@ -30,18 +31,18 @@ if old_arg in __kw: if new_arg: if new_arg in __kw: - logger.warn( + pywikibot.output( "%(new_arg)s argument of %(meth_name)s replaces %(old_arg)s; cannot use both." - % locals()) + % locals(), level=WARNING) else: - logger.debug( + pywikibot.output( "%(old_arg)s argument of %(meth_name)s is deprecated; use %(new_arg)s instead." - % locals()) + % locals(), level=DEBUG) __kw[new_arg] = __kw[old_arg] else: - logger.debug( + pywikibot.output( "%(old_arg)s argument of %(meth_name)s is deprecated." - % locals()) + % locals(), level=DEBUG) del __kw[old_arg] return method(*__args, **__kw) wrapper.__doc__ = method.__doc__ @@ -91,8 +92,8 @@ key = '%s:%s:%s' % (fam, code, user) if not _sites.has_key(key): _sites[key] = __Site(code=code, fam=fam, user=user, sysop=sysop) - logger.debug("Instantiating Site object '%(site)s'" - % {'site': _sites[key]}) + pywikibot.output("Instantiating Site object '%(site)s'" + % {'site': _sites[key]}, level=DEBUG) return _sites[key]
getSite = Site # alias for backwards-compability @@ -125,6 +126,69 @@ logging.getLogger(layer).setLevel(DEBUG)
+def showDiff(oldtext, newtext): + """ + Output a string showing the differences between oldtext and newtext. + The differences are highlighted (only on compatible systems) to show which + changes were made. + + """ + # This is probably not portable to non-terminal interfaces.... + # For information on difflib, see http://pydoc.org/2.3/difflib.html + color = { + '+': 'lightgreen', + '-': 'lightred', + } + diff = u'' + colors = [] + # This will store the last line beginning with + or -. + lastline = None + # For testing purposes only: show original, uncolored diff + # for line in difflib.ndiff(oldtext.splitlines(), newtext.splitlines()): + # print line + for line in difflib.ndiff(oldtext.splitlines(), newtext.splitlines()): + if line.startswith('?'): + # initialize color vector with None, which means default color + lastcolors = [None for c in lastline] + # colorize the + or - sign + lastcolors[0] = color[lastline[0]] + # colorize changed parts in red or green + for i in range(min(len(line), len(lastline))): + if line[i] != ' ': + lastcolors[i] = color[lastline[0]] + diff += lastline + '\n' + # append one None (default color) for the newline character + colors += lastcolors + [None] + elif lastline: + diff += lastline + '\n' + # colorize the + or - sign only + lastcolors = [None for c in lastline] + lastcolors[0] = color[lastline[0]] + colors += lastcolors + [None] + lastline = None + if line[0] in ('+', '-'): + lastline = line + # there might be one + or - line left that wasn't followed by a ? line. + if lastline: + diff += lastline + '\n' + # colorize the + or - sign only + lastcolors = [None for c in lastline] + lastcolors[0] = color[lastline[0]] + colors += lastcolors + [None] + + result = u'' + lastcolor = None + for i in range(len(diff)): + if colors[i] != lastcolor: + if lastcolor is None: + result += '\03{%s}' % colors[i] + else: + result += '\03{default}' + lastcolor = colors[i] + result += diff[i] + output(result) + + # Throttle and thread handling
threadpool = [] # add page-putting threads to this list as they are created @@ -141,11 +205,11 @@ logger = logging.getLogger("wiki")
if not stopped: - logger.debug("stopme() called") + pywikibot.output("stopme() called", level=DEBUG) count = sum(1 for thd in threadpool if thd.isAlive()) if count: - logger.info("Waiting for about %(count)s pages to be saved." - % locals()) + pywikibot.output("Waiting for about %(count)s pages to be saved." + % locals()) for thd in threadpool: if thd.isAlive(): thd.join() @@ -153,7 +217,7 @@ # only need one drop() call because all throttles use the same global pid try: _sites[_sites.keys()[0]].throttle.drop() - logger.log(VERBOSE, "Dropped throttle(s).") + pywikibot.output("Dropped throttle(s).", level=VERBOSE) except IndexError: pass
Modified: branches/rewrite/pywikibot/bot.py =================================================================== --- branches/rewrite/pywikibot/bot.py 2008-12-23 17:13:12 UTC (rev 6190) +++ branches/rewrite/pywikibot/bot.py 2008-12-23 19:37:49 UTC (rev 6191) @@ -18,7 +18,7 @@ import os.path import sys import pywikibot -from pywikibot import config2 as config +from pywikibot import config
# logging levels @@ -29,20 +29,164 @@ INPUT = 25
+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 TerminalHandler(logging.Handler): + """ + A handler class that writes logging records, appropriately formatted, + to a stream. Note that this class does not close the stream, as + sys.stdout or sys.stderr may be used. + + Slightly modified version of the StreamHandler class that ships with + logging module. + + """ + def __init__(self, strm=None): + """ + Initialize the handler. + + If strm is not specified, sys.stderr is used. + """ + logging.Handler.__init__(self) + if strm is None: + strm = sys.stderr + self.stream = strm + self.formatter = None + + def flush(self): + """ + Flush the stream. + """ + self.stream.flush() + + def emit(self, record): + """ + Emit a record. + + If a formatter is specified, it is used to format the record. The + record is then written to the stream. If exception information is + present, it is formatted using traceback.print_exception and + appended to the stream. + """ + try: + msg = self.format(record) + fs = "%s" + try: + self.stream.write(fs % msg.encode(config.console_encoding, + "xmlcharrefreplace")) + except UnicodeError: + self.stream.write(fs % msg.encode("ascii", + "xmlcharrefreplace")) + self.flush() + except (KeyboardInterrupt, SystemExit): + raise + except: + self.handleError(record) + + + +# User interface initialization +# search for user interface module in the 'userinterfaces' subdirectory +exec ("import pywikibot.userinterfaces.%s_interface as uiModule" + % config.userinterface) +ui = uiModule.UI() + def output(text, decoder=None, newline=True, toStdout=False, level=INFO): + """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 linebreak 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: http://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. + + @param level: output level for logging module; use VERBOSE for optional + messages, INPUT for prompts requiring user reponse (not yet fully + implemented) + + """ + if decoder: + text = unicode(text, decoder) + elif type(text) is not unicode: + import traceback + pywikibot.output( + u"Non-unicode (%s) passed to wikipedia.output without decoder!\n" + % type(text), + level=VERBOSE + ) + try: + text = unicode(text, 'utf-8') + except UnicodeDecodeError: + text = unicode(text, 'iso8859-1') + if newline: + text += u'\n' if toStdout: level = STDOUT - logging.getLogger().log(level, text) + ui.output(text, level=level)
+def input(question, password=False): + """Ask the user a question, return the user's answer.
-def input(prompt, password=False): - logging.getLogger().log(INPUT, prompt) - if password: - import getpass - return getpass.getpass("") - return raw_input() + Parameters: + * question - a unicode string that will be shown to the user. Don't add a + space after the question mark/colon, this method will do this + for you. + * password - if True, hides the user's input (for password entry).
+ Returns a unicode string.
+ """ + data = ui.input(question, password) + return data + +def inputChoice(question, answers, hotkeys, default=None): + """Ask the user a question with several options, return the user's choice. + + The user's input will be case-insensitive, so the hotkeys should be + distinctive case-insensitively. + + Parameters: + * question - a unicode string that will be shown to the user. Don't add a + space after the question mark, this method will do this + for you. + * answers - a list of strings that represent the options. + * hotkeys - a list of one-letter strings, one for each answer. + * default - an element of hotkeys, or None. The default choice that will + be returned when the user just presses Enter. + + Returns a one-letter string in lowercase. + + """ + data = ui.inputChoice(question, answers, hotkeys, default).lower() + return data + + +# Command line parsing and help + def calledModuleName(): """Return the name of the module calling this function.
@@ -56,24 +200,6 @@ called = called[ : called.rindex(".py")] return os.path.basename(called)
- -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 - - def _decodeArg(arg): if sys.platform=='win32': if config.console_encoding == 'cp850': @@ -91,7 +217,6 @@ # I don't know how non-Western Windows versions behave. return unicode(arg, config.console_encoding)
- def handleArgs(*args): """Handle standard command line arguments, return the rest as a list.
@@ -176,10 +301,7 @@ # ERROR - user error messages # CRITICAL - fatal error messages # Accordingly, do ''not'' use print statements in bot code; instead, - # send output to logging.log(level, text) or one of its equivalents. - # For backwards-compatibility, pywikibot.output is supported, which - # directs output to logging.info() or other levels as appropriate, but - # its use in new code is deprecated. + # use pywikibot.output function.
logging.addLevelName(VERBOSE, "VERBOSE") # for messages to be displayed on terminal at "verbose" setting @@ -190,17 +312,18 @@ # for prompts requiring user response
root_logger = logging.getLogger() - # default handler for VERBOSE and INFO levels - default_handler = root_logger.handlers[0] + root_logger.handlers = [] # get rid of default handler root_logger.setLevel(DEBUG) # all records go to logger
- # configure default handler for VERBOSE, INFO, and INPUT levels + # configure default handler for VERBOSE and INFO levels + default_handler = TerminalHandler(strm=sys.stderr) if config.verbose_output: default_handler.setLevel(VERBOSE) else: default_handler.setLevel(INFO) default_handler.addFilter(MaxLevelFilter(INPUT)) default_handler.setFormatter(logging.Formatter(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: @@ -223,13 +346,13 @@ root_logger.addHandler(file_handler)
# handler for level STDOUT - output_handler = logging.StreamHandler(strm=sys.stdout) + output_handler = TerminalHandler(strm=sys.stdout) output_handler.setLevel(STDOUT) output_handler.addFilter(MaxLevelFilter(STDOUT)) root_logger.addHandler(output_handler)
# handler for levels WARNING and higher - warning_handler = logging.StreamHandler() # uses sys.stderr + warning_handler = TerminalHandler(strm=sys.stderr) warning_handler.setLevel(logging.WARNING) warning_handler.setFormatter( logging.Formatter(fmt="%(levelname)s: %(message)s")) @@ -242,7 +365,7 @@ pywikibot.output(u'Pywikipediabot r%s' % m.group(1)) pywikibot.output(u'Python %s' % sys.version)
- root_logger.debug("handleArgs() completed.") + pywikibot.output("handleArgs() completed.", level=DEBUG) return nonGlobalArgs
Modified: branches/rewrite/pywikibot/comms/http.py =================================================================== --- branches/rewrite/pywikibot/comms/http.py 2008-12-23 17:13:12 UTC (rev 6190) +++ branches/rewrite/pywikibot/comms/http.py 2008-12-23 19:37:49 UTC (rev 6191) @@ -101,7 +101,8 @@ raise request.data
if request.data[0].status != 200: - logger.warning("Http response status %(status)s" - % {'status': request.data[0].status}) + pywikibot.output("Http response status %(status)s" + % {'status': request.data[0].status}, + level=pywikibot.WARNING)
return request.data[1]
Modified: branches/rewrite/pywikibot/data/api.py =================================================================== --- branches/rewrite/pywikibot/data/api.py 2008-12-23 17:13:12 UTC (rev 6190) +++ branches/rewrite/pywikibot/data/api.py 2008-12-23 19:37:49 UTC (rev 6191) @@ -244,7 +244,7 @@ if code == "maxlag": lag = lagpattern.search(info) if lag: - logger.info( + pywikibot.output( "Pausing due to database lag: " + info) self.site.throttle.lag(int(lag.group("lag"))) continue
Modified: branches/rewrite/pywikibot/login.py =================================================================== --- branches/rewrite/pywikibot/login.py 2008-12-23 17:13:12 UTC (rev 6190) +++ branches/rewrite/pywikibot/login.py 2008-12-23 19:37:49 UTC (rev 6191) @@ -189,8 +189,8 @@
# self.password = self.password.encode(self.site.encoding())
- logger.info(u"Logging in to %(site)s as %(name)s" - % {'name': self.username, 'site': self.site}) + pywikibot.output(u"Logging in to %(site)s as %(name)s" + % {'name': self.username, 'site': self.site}) try: cookiedata = self.getCookie() except pywikibot.data.api.APIError, e: @@ -201,7 +201,7 @@ else: return False self.storecookiedata(cookiedata) - logger.info(u"Should be logged in now") + pywikibot.output(u"Should be logged in now") ## # Show a warning according to the local bot policy ## FIXME: disabled due to recursion; need to move this to the Site object after ## login @@ -249,9 +249,11 @@ try: site = pywikibot.getSite(code=lang, fam=familyName) if not forceLogin and site.loggedInAs(sysop = sysop) != None: - logger.info(u'Already logged in on %(site)s' % locals()) + pywikibot.output(u'Already logged in on %(site)s' + % locals()) else: - loginMan = LoginManager(password, sysop=sysop, site=site) + loginMan = LoginManager(password, sysop=sysop, + site=site) loginMan.login() except pywikibot.NoSuchSite: pywikibot.output(
Modified: branches/rewrite/pywikibot/page.py =================================================================== --- branches/rewrite/pywikibot/page.py 2008-12-23 17:13:12 UTC (rev 6190) +++ branches/rewrite/pywikibot/page.py 2008-12-23 19:37:49 UTC (rev 6191) @@ -13,7 +13,6 @@ from pywikibot import deprecate_arg from pywikibot import config import pywikibot.site -import pywikibot.textlib
import htmlentitydefs import logging @@ -417,8 +416,8 @@
""" txt = self.get() - txt = pywikibot.textlib.removeLanguageLinks(txt, site = self.site()) - txt = pywikibot.textlib.removeCategoryLinks(txt, site = self.site()) + txt = pywikibot.removeLanguageLinks(txt, site = self.site()) + txt = pywikibot.removeCategoryLinks(txt, site = self.site()) if len(txt) < 4: return True else: @@ -655,9 +654,10 @@ done = self.site().editpage(self, summary=comment, minor=minor, watch=watch, unwatch=unwatch) if not done: - logger.warn("Page %s not saved" % self.title(asLink=True)) + pywikibot.output("Page %s not saved" % self.title(asLink=True), + level=pywikibot.WARNING) else: - logger.info("Page %s saved" % self.title(asLink=True)) + pywikibot.output("Page %s saved" % self.title(asLink=True)) except pywikibot.Error, err: logger.exception("Error saving page %s" % self.title(asLink=True)) if callback: @@ -721,7 +721,7 @@ else: text = self.text for linkmatch in pywikibot.link_regex.finditer( - pywikibot.textlib.removeDisabledParts(text)): + pywikibot.removeDisabledParts(text)): linktitle = linkmatch.group("title") link = Link(linktitle, self.site()) # only yield links that are to a different site and that @@ -774,7 +774,7 @@ parameters as the second entry.
""" - templates = pywikibot.textlib.extract_templates_and_params(self.text) + templates = pywikibot.extract_templates_and_params(self.text) # backwards-compatibility: convert the dict returned as the second # element into a list in the format used by old scripts result = [] @@ -900,7 +900,7 @@
""" if reason is None: - logger.info(u'Moving %s to [[%s]].' + pywikibot.output(u'Moving %s to [[%s]].' % (self.title(asLink=True), newtitle)) reason = pywikibot.input(u'Please enter a reason for the move:') # TODO: implement "safe" parameter @@ -920,7 +920,7 @@
""" if reason is None: - logger.info(u'Deleting %s.' % (self.title(asLink=True))) + pywikibot.output(u'Deleting %s.' % (self.title(asLink=True))) reason = pywikibot.input(u'Please enter a reason for the deletion:') answer = u'y' if prompt and not hasattr(self.site(), '_noDeletePrompt'): @@ -995,7 +995,7 @@
""" if comment is None: - logger.info(u'Preparing to undelete %s.' + pywikibot.output(u'Preparing to undelete %s.' % (self.title(asLink=True))) comment = pywikibot.input( u'Please enter a reason for the undeletion:') @@ -1022,7 +1022,7 @@ un = u'un' else: un = u'' - logger.info(u'Preparing to %sprotect %s.' + pywikibot.output(u'Preparing to %sprotect %s.' % (un, self.title(asLink=True))) reason = pywikibot.input(u'Please enter a reason for the action:') if unprotect: @@ -1056,8 +1056,8 @@ % self.title(asLink=True)) return False if inPlace == True: - newtext = pywikibot.textlib.replaceCategoryInPlace( - self.text, oldCat, newCat) + newtext = pywikibot.replaceCategoryInPlace(self.text, + oldCat, newCat) if newtext == self.text: pywikibot.output( u'No changes in made in page %s.' @@ -1111,8 +1111,7 @@ % (self.title(asLink=True), oldCat.title())) else: try: - text = pywikibot.textlib.replaceCategoryLinks(self.text, - newCatList) + text = pywikibot.replaceCategoryLinks(self.text, newCatList) except ValueError: # Make sure that the only way replaceCategoryLinks() can return # a ValueError is in the case of interwiki links to self. @@ -1402,7 +1401,7 @@ % targetCat.title()) return False else: - logger.info('Moving text from %s to %s.' + pywikibot.output('Moving text from %s to %s.' % (self.title(), targetCat.title())) authors = ', '.join(self.contributingUsers()) creationSummary = pywikibot.translate( @@ -1438,7 +1437,7 @@ % targetCat.title()) return False else: - logger.info('Moving text from %s to %s.' + pywikibot.output('Moving text from %s to %s.' % (self.title(), targetCat.title())) authors = ', '.join(self.contributingUsers()) creationSummary = pywikibot.translate(
Modified: branches/rewrite/pywikibot/site.py =================================================================== --- branches/rewrite/pywikibot/site.py 2008-12-23 17:13:12 UTC (rev 6190) +++ branches/rewrite/pywikibot/site.py 2008-12-23 19:37:49 UTC (rev 6191) @@ -1014,7 +1014,7 @@ rvgen.request["titles"] = "|".join(cache.keys()) rvgen.request[u"rvprop"] = \ u"ids|flags|timestamp|user|comment|content" - logger.info(u"Retrieving %s pages from %s." + pywikibot.output(u"Retrieving %s pages from %s." % (len(cache), self) ) for pagedata in rvgen: @@ -1052,7 +1052,7 @@ % (page.title(withSection=False, asLink=True), item['title'])) api.update_page(page, item) - logging.debug(str(item)) + pywikibot.output(str(item), level=pywikibot.DEBUG) return item[tokentype + "token"]
# following group of methods map more-or-less directly to API queries
Modified: branches/rewrite/pywikibot/throttle.py =================================================================== --- branches/rewrite/pywikibot/throttle.py 2008-12-23 17:13:12 UTC (rev 6190) +++ branches/rewrite/pywikibot/throttle.py 2008-12-23 19:37:49 UTC (rev 6191) @@ -10,7 +10,7 @@ __version__ = '$Id$'
import pywikibot -from pywikibot import config2 as config +from pywikibot import config
import logging import math @@ -66,7 +66,8 @@ global pid self.lock.acquire() mysite = self.mysite - logger.debug("Checking multiplicity: pid = %(pid)s" % globals()) + pywikibot.output("Checking multiplicity: pid = %(pid)s" % globals(), + level=pywikibot.DEBUG) try: processes = [] my_pid = pid or 1 # start at 1 if global pid not yet set @@ -117,7 +118,7 @@ f.close() self.process_multiplicity = count if self.verbosedelay: - logger.info( + pywikibot.output( u"Found %(count)s %(mysite)s processes running, including this one." % locals()) finally: @@ -233,11 +234,11 @@ self.next_multiplicity = math.log(1+requestsize)/math.log(2.0) # Announce the delay if it exceeds a preset limit if wait > config.noisysleep: - logger.info(u"Sleeping for %(wait).1f seconds, %(now)s" - % {'wait': wait, - 'now': time.strftime("%Y-%m-%d %H:%M:%S", - time.localtime()) - } ) + pywikibot.output(u"Sleeping for %(wait).1f seconds, %(now)s" + % {'wait': wait, + 'now': time.strftime("%Y-%m-%d %H:%M:%S", + time.localtime()) + } ) time.sleep(wait) if write: self.last_write = time.time() @@ -262,11 +263,12 @@ wait = delay - (time.time() - started) if wait > 0: if wait > config.noisysleep: - logger.info(u"Sleeping for %(wait).1f seconds, %(now)s" - % {'wait': wait, - 'now': time.strftime("%Y-%m-%d %H:%M:%S", - time.localtime()) - } ) + pywikibot.output( + u"Sleeping for %(wait).1f seconds, %(now)s" + % {'wait': wait, + 'now': time.strftime("%Y-%m-%d %H:%M:%S", + time.localtime()) + } ) time.sleep(wait) finally: self.lock.release()
Modified: branches/rewrite/pywikibot/userinterfaces/terminal_interface.py =================================================================== --- branches/rewrite/pywikibot/userinterfaces/terminal_interface.py 2008-12-23 17:13:12 UTC (rev 6190) +++ branches/rewrite/pywikibot/userinterfaces/terminal_interface.py 2008-12-23 19:37:49 UTC (rev 6191) @@ -6,16 +6,21 @@ # __version__ = '$Id$'
-import config, transliteration + import traceback, re, sys -import wikipedia +import logging +import pywikibot +from pywikibot import config +from pywikibot.userinterfaces import transliteration
+ try: import ctypes ctypes_found = True except ImportError: ctypes_found = False
+ def getDefaultTextColorInWindows(): """ This method determines the default text color and saves its color @@ -112,16 +117,15 @@ def __init__(self): pass
- def printColorizedInUnix(self, text, targetStream): + def printColorizedInUnix(self, text, level): lastColor = None for key, value in unixColors.iteritems(): text = text.replace('\03{%s}' % key, value) # just to be sure, reset the color text += unixColors['default'] + logging.log(level, text)
- targetStream.write(text.encode(config.console_encoding, 'replace')) - - def printColorizedInWindows(self, text, targetStream): + def printColorizedInWindows(self, text, level): """ This only works in Python 2.5 or higher. """ @@ -135,7 +139,7 @@ tagM = colorTagR.search(text) if tagM: # print the text up to the tag. - targetStream.write(text[:tagM.start()].encode(config.console_encoding, 'replace')) + logging.log(level, text[:tagM.start()]) newColor = tagM.group('name') if newColor == 'default': if len(colorStack) > 0: @@ -151,7 +155,7 @@ ctypes.windll.kernel32.SetConsoleTextAttribute(std_out_handle, windowsColors[newColor]) text = text[tagM.end():] # print the rest of the text - targetStream.write(text.encode(config.console_encoding, 'replace')) + logging.log(level, text) # just to be sure, reset the color ctypes.windll.kernel32.SetConsoleTextAttribute(std_out_handle, windowsColors['default']) else: @@ -164,18 +168,18 @@ if count > 0: line += '***' line += '\n' - targetStream.write(line.encode(config.console_encoding, 'replace')) + logging.log(level, line)
- def printColorized(self, text, targetStream): + def printColorized(self, text, level): if config.colorized_output: if sys.platform == 'win32': - self.printColorizedInWindows(text, targetStream) + self.printColorizedInWindows(text, level) else: - self.printColorizedInUnix(text, targetStream) + self.printColorizedInUnix(text, level) else: - targetStream.write(text.encode(config.console_encoding, 'replace')) + logging.log(level, text)
- def output(self, text, toStdout = False): + def output(self, text, level=logging.INFO): """ If a character can't be displayed in the encoding used by the user's terminal, it will be replaced with a question mark or by a @@ -212,11 +216,7 @@ prev = codecedText[i] text = transliteratedText
- if toStdout: - targetStream = sys.stdout - else: - targetStream = sys.stderr - self.printColorized(text, targetStream) + self.printColorized(text, level)
def input(self, question, password = False): """ @@ -229,8 +229,7 @@ # sound the terminal bell to notify the user if config.ring_bell: sys.stdout.write('\07') - # TODO: make sure this is logged as well - self.output(question + ' ') + self.output(question + ' ', level=pywikibot.INPUT) if password: import getpass text = getpass.getpass('') @@ -239,7 +238,7 @@ text = unicode(text, config.console_encoding) return text
- def inputChoice(self, question, options, hotkeys, default = None): + def inputChoice(self, question, options, hotkeys, default=None): options = options[:] # we don't want to edit the passed parameter for i in range(len(options)): option = options[i] @@ -279,7 +278,7 @@ print 'Could not load GUI modules: %s' % e return text editor = gui.EditBoxWindow() - return editor.edit(text, jumpIndex = jumpIndex, highlight = highlight) + return editor.edit(text, jumpIndex=jumpIndex, highlight=highlight)
def askForCaptcha(self, url): try:
pywikipedia-l@lists.wikimedia.org