Revision: 6477 Author: nicdumz Date: 2009-03-03 10:10:50 +0000 (Tue, 03 Mar 2009)
Log Message: ----------- svn propset svn:eol-style native -R .
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/epydoc.cfg branches/rewrite/pywikibot/scripts/__init__.py branches/rewrite/pywikibot/scripts/touch.py branches/rewrite/pywikibot/tests/api_tests.py branches/rewrite/pywikibot/tests/page_tests.py branches/rewrite/pywikibot/tests/site_tests.py
Property Changed: ---------------- branches/rewrite/pywikibot/README-conversion.txt branches/rewrite/pywikibot/__init__.py branches/rewrite/pywikibot/bot.py branches/rewrite/pywikibot/comms/__init__.py branches/rewrite/pywikibot/comms/http.py branches/rewrite/pywikibot/comms/threadedhttp.py branches/rewrite/pywikibot/data/logentries.py branches/rewrite/pywikibot/epydoc.cfg branches/rewrite/pywikibot/families/__init__.py branches/rewrite/pywikibot/families/osm_family.py branches/rewrite/pywikibot/scripts/__init__.py branches/rewrite/pywikibot/scripts/touch.py branches/rewrite/pywikibot/tests/__init__.py branches/rewrite/pywikibot/tests/api_tests.py branches/rewrite/pywikibot/tests/page_tests.py branches/rewrite/pywikibot/tests/site_tests.py branches/rewrite/pywikibot/userinterfaces/__init__.py
Modified: branches/rewrite/pywikibot/README-conversion.txt =================================================================== --- branches/rewrite/pywikibot/README-conversion.txt 2009-03-03 10:01:59 UTC (rev 6476) +++ branches/rewrite/pywikibot/README-conversion.txt 2009-03-03 10:10:50 UTC (rev 6477) @@ -1,110 +1,110 @@ -This is a guide to converting bot scripts from version 1 of the -Pywikipediabot framework to version 2. - -Most importantly, note that the version 2 framework *only* supports wikis -using MediaWiki v.1.14 or higher software. If you need to access a wiki that -uses older software, you should continue using version 1 for this purpose. - -The root namespace used in the project has changed from "wikipedia" -to "pywikibot". References to wikipedia need to be changed globally to -pywikibot. Unless noted in this document, other names have not changed; for -example, wikipedia.Page can be replaced by pywikibot.Page throughout any -bot. An effort has been made to design the interface to be as backwards- -compatible as possible, so that in most cases it should be possible to convert -scripts to the new interface simply by changing import statements and doing -global search-and-replace on module names, as discussed in this document. - -With pywikipedia scripts were importing "wikipedia" or "pagegenerators" -libraries; pywikibot is now written as a standard package, and other modules -are contained within it (e.g., pywikibot.site contains Site classes). However, -most commonly-used names are imported into the pywikibot namespace, so that -module names don't need to be used unless specified in the documentation. - -Make sure that the directory that contains the "pywikibot" subdirectory (or -folder) is in sys.path. - -The following changes, at a minimum, need to be made to allow scripts to run: - - change "import wikipedia" to "import pywikibot" - change "import pagegenerators" to "from pywikibot import pagegenerators" - change "import config" to "from pywikibot import config" - 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, -so that these dependencies will be loaded automatically when the package is -installed, and users won't need to worry about this...] - -To run pywikibot, you will need the httplib2, simplejson, and setuptools -packages-- -* httplib2 : http://code.google.com/p/httplib2/ -* setuptools : http://pypi.python.org/pypi/setuptools/ -* simplejson : http://svn.red-bean.com/bob/simplejson/tags/simplejson-1.7.1/docs/index.html - -or, if you already have setuptools installed, just execute -'easy_install httplib2' and 'easy_install simplejson' - -If you run into errors involving httplib2.urlnorm, update httplib2 to 0.4.0 -(Ubuntu package python-httlib2, for example, is outdated). Note that -httplib2 will run under Python 2.6, but will emit DeprecationWarnings (which -are annoying but don't affect the ability to use the package). - -== Page objects == - -The constructor syntax for Pages has been modified; existing calls in the -format of Page(site, title) will still work, and this is still the preferred -way of creating a Page object from data retrieved from the MediaWiki API -(because the API will have parsed and normalized the title). However, for -titles input by a user or scraped from wikitext, it is preferred to use the -alternative syntax Page(Link(site, wikitext)), where "wikitext" is the -string found between [[ and ]] delimiters. The new Link object (more on -this below) handles link parsing and interpretation that doesn't require -access to the wiki server. - -A third syntax allows easy conversion from a Page object to an ImagePage or -Category, or vice versa: e.g., Category(pageobj) converts a Page to a -Category, as long as the page is in the category namespace. - -The following methods of the Page object have been deprecated (deprecated -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) -- sectionFreeTitle(): replaced by Page.title(withSection=False) -- aslink(): replaced by Page.title(asLink=True) -- encoding(): replaced by Page.site().encoding() - -The following methods of the Page object have been obsoleted and no longer -work (but these methods don't appear to be used anywhere in the code -distributed with the bot framework). The functionality of the two obsolete -methods is easily replaced by using standard search-and-replace techniques. -If you call them, they will print a warning and do nothing else: - -- removeImage() -- replaceImage() - -=== ImagePage objects === - -For ImagePage objects, the getFileMd5Sum() method is deprecated; it is -recommended to replace it with getFileSHA1Sum(), because MediaWiki now -stores the SHA1 hash of images. - -=== Category objects === - -The Category object has been moved from the catlib module to the pywikibot -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: - -- subcategoriesList: use, for example, list(self.subcategories()) instead -- articlesList: use, for example, list(self.articles()) instead -- supercategories: use self.categories() instead -- supercategoriesList: use, for example, list(self.categories()) instead - -# MORE TO COME # +This is a guide to converting bot scripts from version 1 of the +Pywikipediabot framework to version 2. + +Most importantly, note that the version 2 framework *only* supports wikis +using MediaWiki v.1.14 or higher software. If you need to access a wiki that +uses older software, you should continue using version 1 for this purpose. + +The root namespace used in the project has changed from "wikipedia" +to "pywikibot". References to wikipedia need to be changed globally to +pywikibot. Unless noted in this document, other names have not changed; for +example, wikipedia.Page can be replaced by pywikibot.Page throughout any +bot. An effort has been made to design the interface to be as backwards- +compatible as possible, so that in most cases it should be possible to convert +scripts to the new interface simply by changing import statements and doing +global search-and-replace on module names, as discussed in this document. + +With pywikipedia scripts were importing "wikipedia" or "pagegenerators" +libraries; pywikibot is now written as a standard package, and other modules +are contained within it (e.g., pywikibot.site contains Site classes). However, +most commonly-used names are imported into the pywikibot namespace, so that +module names don't need to be used unless specified in the documentation. + +Make sure that the directory that contains the "pywikibot" subdirectory (or +folder) is in sys.path. + +The following changes, at a minimum, need to be made to allow scripts to run: + + change "import wikipedia" to "import pywikibot" + change "import pagegenerators" to "from pywikibot import pagegenerators" + change "import config" to "from pywikibot import config" + 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, +so that these dependencies will be loaded automatically when the package is +installed, and users won't need to worry about this...] + +To run pywikibot, you will need the httplib2, simplejson, and setuptools +packages-- +* httplib2 : http://code.google.com/p/httplib2/ +* setuptools : http://pypi.python.org/pypi/setuptools/ +* simplejson : http://svn.red-bean.com/bob/simplejson/tags/simplejson-1.7.1/docs/index.html + +or, if you already have setuptools installed, just execute +'easy_install httplib2' and 'easy_install simplejson' + +If you run into errors involving httplib2.urlnorm, update httplib2 to 0.4.0 +(Ubuntu package python-httlib2, for example, is outdated). Note that +httplib2 will run under Python 2.6, but will emit DeprecationWarnings (which +are annoying but don't affect the ability to use the package). + +== Page objects == + +The constructor syntax for Pages has been modified; existing calls in the +format of Page(site, title) will still work, and this is still the preferred +way of creating a Page object from data retrieved from the MediaWiki API +(because the API will have parsed and normalized the title). However, for +titles input by a user or scraped from wikitext, it is preferred to use the +alternative syntax Page(Link(site, wikitext)), where "wikitext" is the +string found between [[ and ]] delimiters. The new Link object (more on +this below) handles link parsing and interpretation that doesn't require +access to the wiki server. + +A third syntax allows easy conversion from a Page object to an ImagePage or +Category, or vice versa: e.g., Category(pageobj) converts a Page to a +Category, as long as the page is in the category namespace. + +The following methods of the Page object have been deprecated (deprecated +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) +- sectionFreeTitle(): replaced by Page.title(withSection=False) +- aslink(): replaced by Page.title(asLink=True) +- encoding(): replaced by Page.site().encoding() + +The following methods of the Page object have been obsoleted and no longer +work (but these methods don't appear to be used anywhere in the code +distributed with the bot framework). The functionality of the two obsolete +methods is easily replaced by using standard search-and-replace techniques. +If you call them, they will print a warning and do nothing else: + +- removeImage() +- replaceImage() + +=== ImagePage objects === + +For ImagePage objects, the getFileMd5Sum() method is deprecated; it is +recommended to replace it with getFileSHA1Sum(), because MediaWiki now +stores the SHA1 hash of images. + +=== Category objects === + +The Category object has been moved from the catlib module to the pywikibot +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: + +- subcategoriesList: use, for example, list(self.subcategories()) instead +- articlesList: use, for example, list(self.articles()) instead +- supercategories: use self.categories() instead +- supercategoriesList: use, for example, list(self.categories()) instead + +# MORE TO COME #
Property changes on: branches/rewrite/pywikibot/README-conversion.txt ___________________________________________________________________ Added: svn:eol-style + native
Modified: branches/rewrite/pywikibot/__init__.py =================================================================== --- branches/rewrite/pywikibot/__init__.py 2009-03-03 10:01:59 UTC (rev 6476) +++ branches/rewrite/pywikibot/__init__.py 2009-03-03 10:10:50 UTC (rev 6477) @@ -1,248 +1,248 @@ -# -*- coding: utf-8 -*- -""" -The initialization file for the Pywikibot framework. -""" -# -# (C) Pywikipedia bot team, 2008 -# -# Distributed under the terms of the MIT license. -# -__version__ = '$Id$' - -import difflib -import logging -import re -import sys - -import config2 as config -from bot import * -from exceptions import * -from textlib import * - -logging.basicConfig(fmt="%(message)s") - - -def deprecated(instead=None): - """Outputs a method deprecation warning. - Uses the stack to determine class and name of calling method - - @param instead: if provided, will be used to specify the replacement - @type instead: string - """ - f = sys._getframe(1) - classname = f.f_locals['self'].__class__.__name__ - funcname = f.f_code.co_name - if instead: - output(u"%s.%s is DEPRECATED, use %s instead." - % (classname, funcname, instead), - level=WARNING) - else: - output(u"%s.%s is DEPRECATED." % (classname, funcname), - level=WARNING) - -def deprecate_arg(old_arg, new_arg): - """Decorator to declare old_arg deprecated and replace it with new_arg""" - logger = logging.getLogger() - def decorator(method): - def wrapper(*__args, **__kw): - meth_name = method.__name__ - if old_arg in __kw: - if new_arg: - if new_arg in __kw: - pywikibot.output( -"%(new_arg)s argument of %(meth_name)s replaces %(old_arg)s; cannot use both." - % locals(), level=WARNING) - else: - pywikibot.output( -"%(old_arg)s argument of %(meth_name)s is deprecated; use %(new_arg)s instead." - % locals(), level=DEBUG) - __kw[new_arg] = __kw[old_arg] - else: - pywikibot.output( - "%(old_arg)s argument of %(meth_name)s is deprecated." - % locals(), level=DEBUG) - del __kw[old_arg] - return method(*__args, **__kw) - wrapper.__doc__ = method.__doc__ - wrapper.__name__ = method.__name__ - return wrapper - return decorator - - -_sites = {} - -@deprecate_arg("persistent_http", None) -def Site(code=None, fam=None, user=None, sysop=None, interface=None): - """Return the specified Site object. - - Returns a cached object if possible, otherwise instantiates a new one. - - @param code: language code - @type code: string - @param fam: family name or object - @type fam: string or Family - @param user: bot user name to use on this site - @type user: unicode - - """ - logger = logging.getLogger("wiki") - - if code is None: - code = config.mylang - if fam is None: - fam = config.family - if user is None: - try: - user = config.usernames[fam][code] - except KeyError: - user = None - if sysop is None: - try: - sysop = config.sysopnames[fam][code] - except KeyError: - sysop = None - if interface is None: - interface = config.site_interface - try: - exec "from site import %s as __Site" % interface - except ImportError: - raise ValueError("Invalid interface name '%(interface)s'" % locals()) - key = '%s:%s:%s' % (fam, code, user) - if not key in _sites: - _sites[key] = __Site(code=code, fam=fam, user=user, sysop=sysop) - logging.debug(u"Instantiating Site object '%(site)s'" - % {'site': _sites[key]}) - return _sites[key] - -getSite = Site # alias for backwards-compability - - -from page import Page, ImagePage, Category, Link - - -link_regex = re.compile(r'[[(?P<title>[^]|[#<>{}]*)(|.*?)?]]') - - -def setAction(s): - """Set a summary to use for changed page submissions""" - config.default_edit_summary = s - - -def set_debug(layer): - """Set the logger for specified layer to DEBUG level. - - The framework has four layers (by default, others can be added), each - designated by a string -- - - 1. "comm": the communication layer (http requests, etc.) - 2. "data": the raw data layer (API requests, XML dump parsing) - 3. "wiki": the wiki content representation layer (Page and Site objects) - 4. "bot": the application layer - - This method sets the logger for any specified layer to the DEBUG level, - causing it to output extensive debugging information. If this method is - not called for a layer, the default logging setting is the INFO level. - - This method does not check the 'layer' argument for validity. - - """ - 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 -stopped = False - -def stopme(): - """Drop this process from the throttle log, after pending threads finish. - - Can be called manually if desired, but if not, will be called automatically - at Python exit. - - """ - global stopped - logger = logging.getLogger("wiki") - - if not stopped: - logging.debug("stopme() called") - count = sum(1 for thd in threadpool if thd.isAlive()) - if count: - pywikibot.output(u"Waiting for about %(count)s pages to be saved." - % locals()) - for thd in threadpool: - if thd.isAlive(): - thd.join() - stopped = True - # only need one drop() call because all throttles use the same global pid - try: - _sites[_sites.keys()[0]].throttle.drop() - pywikibot.output(u"Dropped throttle(s).", level=VERBOSE) - except IndexError: - pass - -import atexit -atexit.register(stopme) +# -*- coding: utf-8 -*- +""" +The initialization file for the Pywikibot framework. +""" +# +# (C) Pywikipedia bot team, 2008 +# +# Distributed under the terms of the MIT license. +# +__version__ = '$Id$' + +import difflib +import logging +import re +import sys + +import config2 as config +from bot import * +from exceptions import * +from textlib import * + +logging.basicConfig(fmt="%(message)s") + + +def deprecated(instead=None): + """Outputs a method deprecation warning. + Uses the stack to determine class and name of calling method + + @param instead: if provided, will be used to specify the replacement + @type instead: string + """ + f = sys._getframe(1) + classname = f.f_locals['self'].__class__.__name__ + funcname = f.f_code.co_name + if instead: + output(u"%s.%s is DEPRECATED, use %s instead." + % (classname, funcname, instead), + level=WARNING) + else: + output(u"%s.%s is DEPRECATED." % (classname, funcname), + level=WARNING) + +def deprecate_arg(old_arg, new_arg): + """Decorator to declare old_arg deprecated and replace it with new_arg""" + logger = logging.getLogger() + def decorator(method): + def wrapper(*__args, **__kw): + meth_name = method.__name__ + if old_arg in __kw: + if new_arg: + if new_arg in __kw: + pywikibot.output( +"%(new_arg)s argument of %(meth_name)s replaces %(old_arg)s; cannot use both." + % locals(), level=WARNING) + else: + pywikibot.output( +"%(old_arg)s argument of %(meth_name)s is deprecated; use %(new_arg)s instead." + % locals(), level=DEBUG) + __kw[new_arg] = __kw[old_arg] + else: + pywikibot.output( + "%(old_arg)s argument of %(meth_name)s is deprecated." + % locals(), level=DEBUG) + del __kw[old_arg] + return method(*__args, **__kw) + wrapper.__doc__ = method.__doc__ + wrapper.__name__ = method.__name__ + return wrapper + return decorator + + +_sites = {} + +@deprecate_arg("persistent_http", None) +def Site(code=None, fam=None, user=None, sysop=None, interface=None): + """Return the specified Site object. + + Returns a cached object if possible, otherwise instantiates a new one. + + @param code: language code + @type code: string + @param fam: family name or object + @type fam: string or Family + @param user: bot user name to use on this site + @type user: unicode + + """ + logger = logging.getLogger("wiki") + + if code is None: + code = config.mylang + if fam is None: + fam = config.family + if user is None: + try: + user = config.usernames[fam][code] + except KeyError: + user = None + if sysop is None: + try: + sysop = config.sysopnames[fam][code] + except KeyError: + sysop = None + if interface is None: + interface = config.site_interface + try: + exec "from site import %s as __Site" % interface + except ImportError: + raise ValueError("Invalid interface name '%(interface)s'" % locals()) + key = '%s:%s:%s' % (fam, code, user) + if not key in _sites: + _sites[key] = __Site(code=code, fam=fam, user=user, sysop=sysop) + logging.debug(u"Instantiating Site object '%(site)s'" + % {'site': _sites[key]}) + return _sites[key] + +getSite = Site # alias for backwards-compability + + +from page import Page, ImagePage, Category, Link + + +link_regex = re.compile(r'[[(?P<title>[^]|[#<>{}]*)(|.*?)?]]') + + +def setAction(s): + """Set a summary to use for changed page submissions""" + config.default_edit_summary = s + + +def set_debug(layer): + """Set the logger for specified layer to DEBUG level. + + The framework has four layers (by default, others can be added), each + designated by a string -- + + 1. "comm": the communication layer (http requests, etc.) + 2. "data": the raw data layer (API requests, XML dump parsing) + 3. "wiki": the wiki content representation layer (Page and Site objects) + 4. "bot": the application layer + + This method sets the logger for any specified layer to the DEBUG level, + causing it to output extensive debugging information. If this method is + not called for a layer, the default logging setting is the INFO level. + + This method does not check the 'layer' argument for validity. + + """ + 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 +stopped = False + +def stopme(): + """Drop this process from the throttle log, after pending threads finish. + + Can be called manually if desired, but if not, will be called automatically + at Python exit. + + """ + global stopped + logger = logging.getLogger("wiki") + + if not stopped: + logging.debug("stopme() called") + count = sum(1 for thd in threadpool if thd.isAlive()) + if count: + pywikibot.output(u"Waiting for about %(count)s pages to be saved." + % locals()) + for thd in threadpool: + if thd.isAlive(): + thd.join() + stopped = True + # only need one drop() call because all throttles use the same global pid + try: + _sites[_sites.keys()[0]].throttle.drop() + pywikibot.output(u"Dropped throttle(s).", level=VERBOSE) + except IndexError: + pass + +import atexit +atexit.register(stopme)
Property changes on: branches/rewrite/pywikibot/__init__.py ___________________________________________________________________ Added: svn:eol-style + native
Modified: branches/rewrite/pywikibot/bot.py =================================================================== --- branches/rewrite/pywikibot/bot.py 2009-03-03 10:01:59 UTC (rev 6476) +++ branches/rewrite/pywikibot/bot.py 2009-03-03 10:10:50 UTC (rev 6477) @@ -1,435 +1,435 @@ -# -*- coding: utf-8 -*- -""" -User-interface related functions for building bots -""" -# -# (C) Pywikipedia bot team, 2008 -# -# Distributed under the terms of the MIT license. -# -__version__ = '$Id$' - -# Note: the intention is to develop this module (at some point) into a Bot -# class definition that can be subclassed to create new, functional bot -# scripts, instead of writing each one from scratch. - - -import logging, logging.handlers - # all output goes thru python std library "logging" module -import os -import os.path -import sys - -# logging levels -logger = logging.getLogger("bot") - -from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL -STDOUT = 16 -VERBOSE = 18 -INPUT = 25 - -import pywikibot -from pywikibot import config - - -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 - - -# 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() -TerminalHandler = uiModule.TerminalHandler - - -class RotatingFileHandler(logging.handlers.RotatingFileHandler): - """Strip trailing newlines before outputting text to file""" - def format(self, record): - text = logging.handlers.RotatingFileHandler.format(self, record) - return text.rstrip("\r\n") - - -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) - - """ - # make sure logging system has been initialized - root = logging.getLogger() - if root.level == 30: # init_handlers sets this level - init_handlers() - - if decoder: - text = unicode(text, decoder) - elif not isinstance(text, unicode): -## import traceback -## pywikibot.output( -## u"Non-unicode (%s) passed to wikipedia.output without decoder!\n" -## % type(text), -## level=VERBOSE -## ) - if not isinstance(text, str): - # looks like text is a non-text object. - # Maybe it has a __unicode__ builtin ? - # (allows to print Page, Site...) - text = unicode(text) - else: - try: - text = unicode(text, 'utf-8') - except UnicodeDecodeError: - text = unicode(text, 'iso8859-1') - if newline: - text += "\n" - if toStdout: - level = STDOUT - ui.output(text, level=level) - -def input(question, password=False): - """Ask the user a question, return the user's answer. - - 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. - - """ - # make sure logging system has been initialized - root = logging.getLogger() - if root.level == 30: # init_handlers sets this level - init_handlers() - - 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. - - """ - # make sure logging system has been initialized - root = logging.getLogger() - if root.level == 30: # init_handlers sets this level - init_handlers() - - data = ui.inputChoice(question, answers, hotkeys, default).lower() - return data - - -def init_handlers(): - """Initialize logging system for terminal-based bots""" - - # 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. - - 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() - root_logger.handlers = [] # get rid of default handler - root_logger.setLevel(DEBUG+1) # all records except DEBUG go to logger - - # 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: - 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 = logging.Formatter( - fmt="%(asctime)s %(filename)18s, %(lineno)d: " - "%(levelname)-8s %(message)s", - datefmt="%Y-%m-%d %H:%M:%S" - ) - file_handler.setFormatter(form) - root_logger.addHandler(file_handler) - for component in config.debug_log: - debuglogger = logging.getLogger(component) - debuglogger.setLevel(DEBUG) - debuglogger.addHandler(file_handler) - - # handler for level STDOUT - output_handler = TerminalHandler(strm=sys.stdout) - output_handler.setLevel(STDOUT) - output_handler.addFilter(MaxLevelFilter(STDOUT)) - output_handler.setFormatter(logging.Formatter(fmt="%(message)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( - logging.Formatter(fmt="%(levelname)s: %(message)s")) - root_logger.addHandler(warning_handler) - - -# Command line parsing and help - -def calledModuleName(): - """Return the name of the module calling this function. - - This is required because the -help option loads the module's docstring - and because the module name will be used for the filename of the log. - - """ - # get commandline arguments - called = sys.argv[0].strip() - if ".py" in called: # could end with .pyc, .pyw, etc. on some platforms - called = called[ : called.rindex(".py")] - return os.path.basename(called) - -def _decodeArg(arg): - if sys.platform=='win32': - if config.console_encoding in ("cp437", 'cp850'): - # Western Windows versions give parameters encoded as windows-1252 - # even though the console encoding is cp850 or cp437. - return unicode(arg, 'windows-1252') - elif config.console_encoding == 'cp852': - # Central/Eastern European Windows versions give parameters encoded - # as windows-1250 even though the console encoding is cp852. - return unicode(arg, 'windows-1250') - else: - return unicode(arg, config.console_encoding) - else: - # Linux uses the same encoding for both. - # 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. - - Takes the commandline arguments, converts them to Unicode, processes all - global parameters such as -lang or -log. Returns a list of all arguments - that are not global. This makes sure that global arguments are applied - first, regardless of the order in which the arguments were given. - - args may be passed as an argument, thereby overriding sys.argv - - """ - # get commandline arguments if necessary - if not args: - args = sys.argv[1:] - # get the name of the module calling this function. This is - # required because the -help option loads the module's docstring and because - # the module name will be used for the filename of the log. - moduleName = calledModuleName() - if not moduleName: - moduleName = "terminal-interface" - nonGlobalArgs = [] - username = None - do_help = False - for arg in args: - arg = _decodeArg(arg) - if arg == '-help': - do_help = True - elif arg.startswith('-family:'): - config.family = arg[len("-family:") : ] - elif arg.startswith('-lang:'): - config.mylang = arg[len("-lang:") : ] - elif arg.startswith("-user:"): - username = arg[len("-user:") : ] - elif arg.startswith('-putthrottle:'): - config.put_throttle = int(arg[len("-putthrottle:") : ]) - elif arg.startswith('-pt:'): - config.put_throttle = int(arg[len("-pt:") : ]) - elif arg.startswith("-maxlag:"): - config.maxlag = int(arg[len("-maxlag:") : ]) - elif arg == '-log': - if moduleName not in config.log: - config.log.append(moduleName) - elif arg.startswith('-log:'): - if moduleName not in config.log: - config.log.append(moduleName) - config.logfilename = arg[len("-log:") : ] - elif arg == '-nolog': - if moduleName in config.log: - config.log.remove(moduleName) - elif arg == "-debug": - if moduleName not in config.log: - config.log.append(moduleName) - if "" not in config.debug_log: - config.debug_log.append("") - elif arg.startswith("-debug:"): - if moduleName not in config.log: - config.log.append(moduleName) - component = arg[len("-debug:") : ] - if component not in config.debug_log: - config.debug_log.append(component) - elif arg == '-verbose' or arg == "-v": - config.verbose_output += 1 - elif arg == '-daemonize': - import daemonize - daemonize.daemonize() - elif arg.startswith('-daemonize:'): - import daemonize - daemonize.daemonize(redirect_std = arg[11:]) - else: - # the argument is not global. Let the specific bot script care - # about it. - nonGlobalArgs.append(arg) - - if username: - config.usernames[config.family][config.mylang] = username - - init_handlers() - - if config.verbose_output: - import re - ver = pywikibot.__version__ # probably can be improved on - m = re.search(r"$Id: .* (\d+ \d+-\d+-\d+ \d+:\d+:\d+Z) .*$", ver) - pywikibot.output(u'Pywikipediabot r%s' % m.group(1)) - pywikibot.output(u'Python %s' % sys.version) - - if do_help: - showHelp() - sys.exit(0) - logger.debug(u"handleArgs() completed.") - return nonGlobalArgs - - -def showHelp(name=""): - # argument, if given, is ignored - modname = calledModuleName() - if not modname: - try: - modname = sys.modules['__main__'].main.__module__ - except NameError: - modname = "no_module" - - globalHelp =u'''\ -Global arguments available for all bots: - --dir:PATH Read the bot's configuration data from directory given by - PATH, instead of from the default directory. - --lang:xx Set the language of the wiki you want to work on, overriding - the configuration in user-config.py. xx should be the - language code. - --family:xyz Set the family of the wiki you want to work on, e.g. - wikipedia, wiktionary, wikitravel, ... - This will override the configuration in user-config.py. - --user:xyz Log in as user 'xyz' instead of the default username. - --daemonize:xyz Immediately return control to the terminal and redirect - stdout and stderr to xyz (only use for bots that require - no input from stdin). - --help Show this help text. - --log Enable the logfile, using the default filename - '%s-bot.log' - --log:xyz Enable the logfile, using 'xyz' as the filename. - --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 - is used). - --putthrottle:n Set the minimum time (in seconds) the bot will wait between --pt:n saving pages. - --verbose Have the bot provide additional console output that may be --v useful in debugging. - -''' % modname - try: - exec('import %s as module' % modname) - helpText = module.__doc__.decode('utf-8') - if hasattr(module, 'docuReplacements'): - for key, value in module.docuReplacements.iteritems(): - helpText = helpText.replace(key, value.strip('\n\r')) - pywikibot.output(helpText, level=pywikibot.STDOUT) # output to STDOUT - except Exception: - if modname: - pywikibot.output(u'Sorry, no help available for %s' % modname, - level=pywikibot.STDOUT) - logging.exception('showHelp:') - pywikibot.output(globalHelp, level=pywikibot.STDOUT) +# -*- coding: utf-8 -*- +""" +User-interface related functions for building bots +""" +# +# (C) Pywikipedia bot team, 2008 +# +# Distributed under the terms of the MIT license. +# +__version__ = '$Id$' + +# Note: the intention is to develop this module (at some point) into a Bot +# class definition that can be subclassed to create new, functional bot +# scripts, instead of writing each one from scratch. + + +import logging, logging.handlers + # all output goes thru python std library "logging" module +import os +import os.path +import sys + +# logging levels +logger = logging.getLogger("bot") + +from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL +STDOUT = 16 +VERBOSE = 18 +INPUT = 25 + +import pywikibot +from pywikibot import config + + +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 + + +# 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() +TerminalHandler = uiModule.TerminalHandler + + +class RotatingFileHandler(logging.handlers.RotatingFileHandler): + """Strip trailing newlines before outputting text to file""" + def format(self, record): + text = logging.handlers.RotatingFileHandler.format(self, record) + return text.rstrip("\r\n") + + +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) + + """ + # make sure logging system has been initialized + root = logging.getLogger() + if root.level == 30: # init_handlers sets this level + init_handlers() + + if decoder: + text = unicode(text, decoder) + elif not isinstance(text, unicode): +## import traceback +## pywikibot.output( +## u"Non-unicode (%s) passed to wikipedia.output without decoder!\n" +## % type(text), +## level=VERBOSE +## ) + if not isinstance(text, str): + # looks like text is a non-text object. + # Maybe it has a __unicode__ builtin ? + # (allows to print Page, Site...) + text = unicode(text) + else: + try: + text = unicode(text, 'utf-8') + except UnicodeDecodeError: + text = unicode(text, 'iso8859-1') + if newline: + text += "\n" + if toStdout: + level = STDOUT + ui.output(text, level=level) + +def input(question, password=False): + """Ask the user a question, return the user's answer. + + 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. + + """ + # make sure logging system has been initialized + root = logging.getLogger() + if root.level == 30: # init_handlers sets this level + init_handlers() + + 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. + + """ + # make sure logging system has been initialized + root = logging.getLogger() + if root.level == 30: # init_handlers sets this level + init_handlers() + + data = ui.inputChoice(question, answers, hotkeys, default).lower() + return data + + +def init_handlers(): + """Initialize logging system for terminal-based bots""" + + # 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. + + 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() + root_logger.handlers = [] # get rid of default handler + root_logger.setLevel(DEBUG+1) # all records except DEBUG go to logger + + # 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: + 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 = logging.Formatter( + fmt="%(asctime)s %(filename)18s, %(lineno)d: " + "%(levelname)-8s %(message)s", + datefmt="%Y-%m-%d %H:%M:%S" + ) + file_handler.setFormatter(form) + root_logger.addHandler(file_handler) + for component in config.debug_log: + debuglogger = logging.getLogger(component) + debuglogger.setLevel(DEBUG) + debuglogger.addHandler(file_handler) + + # handler for level STDOUT + output_handler = TerminalHandler(strm=sys.stdout) + output_handler.setLevel(STDOUT) + output_handler.addFilter(MaxLevelFilter(STDOUT)) + output_handler.setFormatter(logging.Formatter(fmt="%(message)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( + logging.Formatter(fmt="%(levelname)s: %(message)s")) + root_logger.addHandler(warning_handler) + + +# Command line parsing and help + +def calledModuleName(): + """Return the name of the module calling this function. + + This is required because the -help option loads the module's docstring + and because the module name will be used for the filename of the log. + + """ + # get commandline arguments + called = sys.argv[0].strip() + if ".py" in called: # could end with .pyc, .pyw, etc. on some platforms + called = called[ : called.rindex(".py")] + return os.path.basename(called) + +def _decodeArg(arg): + if sys.platform=='win32': + if config.console_encoding in ("cp437", 'cp850'): + # Western Windows versions give parameters encoded as windows-1252 + # even though the console encoding is cp850 or cp437. + return unicode(arg, 'windows-1252') + elif config.console_encoding == 'cp852': + # Central/Eastern European Windows versions give parameters encoded + # as windows-1250 even though the console encoding is cp852. + return unicode(arg, 'windows-1250') + else: + return unicode(arg, config.console_encoding) + else: + # Linux uses the same encoding for both. + # 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. + + Takes the commandline arguments, converts them to Unicode, processes all + global parameters such as -lang or -log. Returns a list of all arguments + that are not global. This makes sure that global arguments are applied + first, regardless of the order in which the arguments were given. + + args may be passed as an argument, thereby overriding sys.argv + + """ + # get commandline arguments if necessary + if not args: + args = sys.argv[1:] + # get the name of the module calling this function. This is + # required because the -help option loads the module's docstring and because + # the module name will be used for the filename of the log. + moduleName = calledModuleName() + if not moduleName: + moduleName = "terminal-interface" + nonGlobalArgs = [] + username = None + do_help = False + for arg in args: + arg = _decodeArg(arg) + if arg == '-help': + do_help = True + elif arg.startswith('-family:'): + config.family = arg[len("-family:") : ] + elif arg.startswith('-lang:'): + config.mylang = arg[len("-lang:") : ] + elif arg.startswith("-user:"): + username = arg[len("-user:") : ] + elif arg.startswith('-putthrottle:'): + config.put_throttle = int(arg[len("-putthrottle:") : ]) + elif arg.startswith('-pt:'): + config.put_throttle = int(arg[len("-pt:") : ]) + elif arg.startswith("-maxlag:"): + config.maxlag = int(arg[len("-maxlag:") : ]) + elif arg == '-log': + if moduleName not in config.log: + config.log.append(moduleName) + elif arg.startswith('-log:'): + if moduleName not in config.log: + config.log.append(moduleName) + config.logfilename = arg[len("-log:") : ] + elif arg == '-nolog': + if moduleName in config.log: + config.log.remove(moduleName) + elif arg == "-debug": + if moduleName not in config.log: + config.log.append(moduleName) + if "" not in config.debug_log: + config.debug_log.append("") + elif arg.startswith("-debug:"): + if moduleName not in config.log: + config.log.append(moduleName) + component = arg[len("-debug:") : ] + if component not in config.debug_log: + config.debug_log.append(component) + elif arg == '-verbose' or arg == "-v": + config.verbose_output += 1 + elif arg == '-daemonize': + import daemonize + daemonize.daemonize() + elif arg.startswith('-daemonize:'): + import daemonize + daemonize.daemonize(redirect_std = arg[11:]) + else: + # the argument is not global. Let the specific bot script care + # about it. + nonGlobalArgs.append(arg) + + if username: + config.usernames[config.family][config.mylang] = username + + init_handlers() + + if config.verbose_output: + import re + ver = pywikibot.__version__ # probably can be improved on + m = re.search(r"$Id: .* (\d+ \d+-\d+-\d+ \d+:\d+:\d+Z) .*$", ver) + pywikibot.output(u'Pywikipediabot r%s' % m.group(1)) + pywikibot.output(u'Python %s' % sys.version) + + if do_help: + showHelp() + sys.exit(0) + logger.debug(u"handleArgs() completed.") + return nonGlobalArgs + + +def showHelp(name=""): + # argument, if given, is ignored + modname = calledModuleName() + if not modname: + try: + modname = sys.modules['__main__'].main.__module__ + except NameError: + modname = "no_module" + + globalHelp =u'''\ +Global arguments available for all bots: + +-dir:PATH Read the bot's configuration data from directory given by + PATH, instead of from the default directory. + +-lang:xx Set the language of the wiki you want to work on, overriding + the configuration in user-config.py. xx should be the + language code. + +-family:xyz Set the family of the wiki you want to work on, e.g. + wikipedia, wiktionary, wikitravel, ... + This will override the configuration in user-config.py. + +-user:xyz Log in as user 'xyz' instead of the default username. + +-daemonize:xyz Immediately return control to the terminal and redirect + stdout and stderr to xyz (only use for bots that require + no input from stdin). + +-help Show this help text. + +-log Enable the logfile, using the default filename + '%s-bot.log' + +-log:xyz Enable the logfile, using 'xyz' as the filename. + +-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 + is used). + +-putthrottle:n Set the minimum time (in seconds) the bot will wait between +-pt:n saving pages. + +-verbose Have the bot provide additional console output that may be +-v useful in debugging. + +''' % modname + try: + exec('import %s as module' % modname) + helpText = module.__doc__.decode('utf-8') + if hasattr(module, 'docuReplacements'): + for key, value in module.docuReplacements.iteritems(): + helpText = helpText.replace(key, value.strip('\n\r')) + pywikibot.output(helpText, level=pywikibot.STDOUT) # output to STDOUT + except Exception: + if modname: + pywikibot.output(u'Sorry, no help available for %s' % modname, + level=pywikibot.STDOUT) + logging.exception('showHelp:') + pywikibot.output(globalHelp, level=pywikibot.STDOUT)
Property changes on: branches/rewrite/pywikibot/bot.py ___________________________________________________________________ Added: svn:eol-style + native
Property changes on: branches/rewrite/pywikibot/comms/__init__.py ___________________________________________________________________ Added: svn:eol-style + native
Modified: branches/rewrite/pywikibot/comms/http.py =================================================================== --- branches/rewrite/pywikibot/comms/http.py 2009-03-03 10:01:59 UTC (rev 6476) +++ branches/rewrite/pywikibot/comms/http.py 2009-03-03 10:10:50 UTC (rev 6477) @@ -1,111 +1,111 @@ -# -*- coding: utf-8 -*- -""" -Basic HTTP access interface. - -This module handles communication between the bot and the HTTP threads. - -This module is responsible for - - Setting up a connection pool - - Providing a (blocking) interface for HTTP requests - - Translate site objects with query strings into urls - - Urlencoding all data - - Basic HTTP error handling -""" - -# -# (C) Pywikipedia bot team, 2007 -# -# Distributed under the terms of the MIT license. -# - -__version__ = '$Id: $' -__docformat__ = 'epytext' - -import Queue -import urllib -import urlparse -import logging -import atexit - -from pywikibot import config -import pywikibot -import cookielib -import threadedhttp - -logger = logging.getLogger("comms.http") - - -# global variables - -useragent = 'Pywikipediabot/2.0' # This should include some global version string -numthreads = 1 -threads = [] - -connection_pool = threadedhttp.ConnectionPool() -http_queue = Queue.Queue() - -cookie_jar = threadedhttp.LockableCookieJar( - config.datafilepath("pywikibot.lwp")) -try: - cookie_jar.load() -except (IOError, cookielib.LoadError): - logger.debug("Loading cookies failed.") -else: - logger.debug("Loaded cookies from file.") - - -# Build up HttpProcessors -pywikibot.output('Starting %(numthreads)i threads...' % locals(), - level=pywikibot.VERBOSE) -for i in range(numthreads): - proc = threadedhttp.HttpProcessor(http_queue, cookie_jar, connection_pool) - proc.setDaemon(True) - threads.append(proc) - proc.start() - -# Prepare flush on quit -def _flush(): - for i in threads: - http_queue.put(None) - pywikibot.output(u'Waiting for threads to finish... ', - level=pywikibot.VERBOSE) - for i in threads: - i.join() - logger.debug('All threads finished.') -atexit.register(_flush) - -# export cookie_jar to global namespace -import pywikibot -pywikibot.cookie_jar = cookie_jar - -def request(site, uri, *args, **kwargs): - """Queue a request to be submitted to Site. - - All parameters not listed below are the same as - L{httplib2.Http.request}, but the uri is relative - - @param site: The Site to connect to - @return: The received data (a unicode string). - """ - baseuri = "%s://%s/" % (site.protocol(), site.hostname()) - uri = urlparse.urljoin(baseuri, uri) - - # set default user-agent string - kwargs.setdefault("headers", {}) - kwargs["headers"].setdefault("user-agent", useragent) - request = threadedhttp.HttpRequest(uri, *args, **kwargs) - http_queue.put(request) - request.lock.acquire() - - #TODO: do some error correcting stuff - - #if all else fails - if isinstance(request.data, Exception): - raise request.data - - if request.data[0].status != 200: - pywikibot.output(u"Http response status %(status)s" - % {'status': request.data[0].status}, - level=pywikibot.WARNING) - - return request.data[1] +# -*- coding: utf-8 -*- +""" +Basic HTTP access interface. + +This module handles communication between the bot and the HTTP threads. + +This module is responsible for + - Setting up a connection pool + - Providing a (blocking) interface for HTTP requests + - Translate site objects with query strings into urls + - Urlencoding all data + - Basic HTTP error handling +""" + +# +# (C) Pywikipedia bot team, 2007 +# +# Distributed under the terms of the MIT license. +# + +__version__ = '$Id: $' +__docformat__ = 'epytext' + +import Queue +import urllib +import urlparse +import logging +import atexit + +from pywikibot import config +import pywikibot +import cookielib +import threadedhttp + +logger = logging.getLogger("comms.http") + + +# global variables + +useragent = 'Pywikipediabot/2.0' # This should include some global version string +numthreads = 1 +threads = [] + +connection_pool = threadedhttp.ConnectionPool() +http_queue = Queue.Queue() + +cookie_jar = threadedhttp.LockableCookieJar( + config.datafilepath("pywikibot.lwp")) +try: + cookie_jar.load() +except (IOError, cookielib.LoadError): + logger.debug("Loading cookies failed.") +else: + logger.debug("Loaded cookies from file.") + + +# Build up HttpProcessors +pywikibot.output('Starting %(numthreads)i threads...' % locals(), + level=pywikibot.VERBOSE) +for i in range(numthreads): + proc = threadedhttp.HttpProcessor(http_queue, cookie_jar, connection_pool) + proc.setDaemon(True) + threads.append(proc) + proc.start() + +# Prepare flush on quit +def _flush(): + for i in threads: + http_queue.put(None) + pywikibot.output(u'Waiting for threads to finish... ', + level=pywikibot.VERBOSE) + for i in threads: + i.join() + logger.debug('All threads finished.') +atexit.register(_flush) + +# export cookie_jar to global namespace +import pywikibot +pywikibot.cookie_jar = cookie_jar + +def request(site, uri, *args, **kwargs): + """Queue a request to be submitted to Site. + + All parameters not listed below are the same as + L{httplib2.Http.request}, but the uri is relative + + @param site: The Site to connect to + @return: The received data (a unicode string). + """ + baseuri = "%s://%s/" % (site.protocol(), site.hostname()) + uri = urlparse.urljoin(baseuri, uri) + + # set default user-agent string + kwargs.setdefault("headers", {}) + kwargs["headers"].setdefault("user-agent", useragent) + request = threadedhttp.HttpRequest(uri, *args, **kwargs) + http_queue.put(request) + request.lock.acquire() + + #TODO: do some error correcting stuff + + #if all else fails + if isinstance(request.data, Exception): + raise request.data + + if request.data[0].status != 200: + pywikibot.output(u"Http response status %(status)s" + % {'status': request.data[0].status}, + level=pywikibot.WARNING) + + return request.data[1]
Property changes on: branches/rewrite/pywikibot/comms/http.py ___________________________________________________________________ Added: svn:eol-style + native
Property changes on: branches/rewrite/pywikibot/comms/threadedhttp.py ___________________________________________________________________ Added: svn:eol-style + native
Property changes on: branches/rewrite/pywikibot/data/logentries.py ___________________________________________________________________ Added: svn:eol-style + native
Modified: branches/rewrite/pywikibot/epydoc.cfg =================================================================== --- branches/rewrite/pywikibot/epydoc.cfg 2009-03-03 10:01:59 UTC (rev 6476) +++ branches/rewrite/pywikibot/epydoc.cfg 2009-03-03 10:10:50 UTC (rev 6477) @@ -1,84 +1,84 @@ -[epydoc] # Epydoc section marker (required by ConfigParser) - -# modules -# The list of objects to document. Objects can be named using -# dotted names, module filenames, or package directory names. -# Alases for this option include "objects" and "values". -modules: data.threadedhttp - -# output -# The type of output that should be generated. Should be one -# of: html, text, latex, dvi, ps, pdf. -output: html - -# target -# The path to the output directory. May be relative or absolute. -target: doc/ - -# css -# The CSS stylesheet for HTML output. Can be the name of a builtin -# stylesheet, or the name of a file. -css: white - -# name -# The documented project's name. -name: Python Mediawiki Framework - -# url -# The documented project's URL. -url: http://pywikipediabot.sourceforge.net - -# frames -# Whether or not to include a frames-based table of contents. -frames: yes - -# private -# Whether or not to inclue private variables. (Even if included, -# private variables will be hidden by default.) -private: yes - -# imports -# Whether or not to list each module's imports. -imports: yes - -# verbosity -# An integer indicating how verbose epydoc should be. The default -# value is 0; negative values will supress warnings and errors; -# positive values will give more verbose output. -verbosity: 0 - -# parse -# Whether or not parsing should be used to examine objects. -parse: yes - -# introspect -# Whether or not introspection should be used to examine objects. -introspect: yes - -# graph -# The list of graph types that should be automatically included -# in the output. Graphs are generated using the Graphviz "dot" -# executable. Graph types include: "classtree", "callgraph", -# "umlclass". Use "all" to include all graph types -graph: all - -# dotpath -# The path to the Graphviz "dot" executable, used to generate -# graphs. -dotpath: /usr/bin/dot - -# sourcecode -# Whether or not to include syntax highlighted source code in -# the output (HTML only). -sourcecode: no - -# pstat -# The name of one or more pstat files (generated by the profile -# or hotshot module). These are used to generate call graphs. -pstat: profile.out - -# separate-classes -# Whether each class should be listed in its own section when -# generating LaTeX or PDF output. -separate-classes: no - +[epydoc] # Epydoc section marker (required by ConfigParser) + +# modules +# The list of objects to document. Objects can be named using +# dotted names, module filenames, or package directory names. +# Alases for this option include "objects" and "values". +modules: data.threadedhttp + +# output +# The type of output that should be generated. Should be one +# of: html, text, latex, dvi, ps, pdf. +output: html + +# target +# The path to the output directory. May be relative or absolute. +target: doc/ + +# css +# The CSS stylesheet for HTML output. Can be the name of a builtin +# stylesheet, or the name of a file. +css: white + +# name +# The documented project's name. +name: Python Mediawiki Framework + +# url +# The documented project's URL. +url: http://pywikipediabot.sourceforge.net + +# frames +# Whether or not to include a frames-based table of contents. +frames: yes + +# private +# Whether or not to inclue private variables. (Even if included, +# private variables will be hidden by default.) +private: yes + +# imports +# Whether or not to list each module's imports. +imports: yes + +# verbosity +# An integer indicating how verbose epydoc should be. The default +# value is 0; negative values will supress warnings and errors; +# positive values will give more verbose output. +verbosity: 0 + +# parse +# Whether or not parsing should be used to examine objects. +parse: yes + +# introspect +# Whether or not introspection should be used to examine objects. +introspect: yes + +# graph +# The list of graph types that should be automatically included +# in the output. Graphs are generated using the Graphviz "dot" +# executable. Graph types include: "classtree", "callgraph", +# "umlclass". Use "all" to include all graph types +graph: all + +# dotpath +# The path to the Graphviz "dot" executable, used to generate +# graphs. +dotpath: /usr/bin/dot + +# sourcecode +# Whether or not to include syntax highlighted source code in +# the output (HTML only). +sourcecode: no + +# pstat +# The name of one or more pstat files (generated by the profile +# or hotshot module). These are used to generate call graphs. +pstat: profile.out + +# separate-classes +# Whether each class should be listed in its own section when +# generating LaTeX or PDF output. +separate-classes: no +
Property changes on: branches/rewrite/pywikibot/epydoc.cfg ___________________________________________________________________ Added: svn:eol-style + native
Property changes on: branches/rewrite/pywikibot/families/__init__.py ___________________________________________________________________ Added: svn:eol-style + native
Property changes on: branches/rewrite/pywikibot/families/osm_family.py ___________________________________________________________________ Added: svn:eol-style + native
Modified: branches/rewrite/pywikibot/scripts/__init__.py =================================================================== --- branches/rewrite/pywikibot/scripts/__init__.py 2009-03-03 10:01:59 UTC (rev 6476) +++ branches/rewrite/pywikibot/scripts/__init__.py 2009-03-03 10:10:50 UTC (rev 6477) @@ -1 +1 @@ -# THIS DIRECTORY IS TO HOLD BOT SCRIPTS FOR THE NEW FRAMEWORK +# THIS DIRECTORY IS TO HOLD BOT SCRIPTS FOR THE NEW FRAMEWORK
Property changes on: branches/rewrite/pywikibot/scripts/__init__.py ___________________________________________________________________ Added: svn:eol-style + native
Modified: branches/rewrite/pywikibot/scripts/touch.py =================================================================== --- branches/rewrite/pywikibot/scripts/touch.py 2009-03-03 10:01:59 UTC (rev 6476) +++ branches/rewrite/pywikibot/scripts/touch.py 2009-03-03 10:10:50 UTC (rev 6477) @@ -1,92 +1,92 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -"""This bot goes over multiple pages of a wiki, and edits them without -changing. This is for example used to get category links in templates -working. - -This script understands various command-line arguments: - -¶ms; - --redir specifies that the robot should touch redirect pages; - otherwise, they will be skipped. - -All other parameters will be regarded as a page title; in this case, the bot -will only touch a single page. -""" - -__version__='$Id: touch.py,v 1.13 2006/03/01 14:07:06 russblau Exp $' - -import pywikibot -from pywikibot import pagegenerators, catlib, config -import sys - -docuReplacements = {'¶ms;': pagegenerators.parameterHelp} - - -class TouchBot: - def __init__(self, generator, touch_redirects): - self.generator = generator - self.touch_redirects = touch_redirects - - def run(self): - for page in self.generator: - try: - # get the page, and save it using the unmodified text. - # whether or not getting a redirect throws an exception - # depends on the variable self.touch_redirects. - text = page.get(get_redirect = self.touch_redirects) - page.save("Pywikibot touch script") - except pywikibot.NoPage: - pywikibot.output(u"Page %s does not exist?!" % page.title(asLink=True), - level=pywikibot.ERROR) - except pywikibot.IsRedirectPage: - pywikibot.output(u"Page %s is a redirect; skipping." - % page.title(asLink=True), - level=pywikibot.WARNING) - except pywikibot.LockedPage: - pywikibot.output(u"Page %s is locked?!" % page.title(asLink=True), - level=pywikibot.ERROR) - - -def main(*args): - global bot - # Disable cosmetic changes because we don't want to modify any page - # content, so that we don't flood the histories with minor changes. - config.cosmetic_changes = False - #page generator - gen = None - genFactory = pagegenerators.GeneratorFactory() - redirs = False - # If the user chooses to work on a single page, this temporary array is - # used to read the words from the page title. The words will later be - # joined with spaces to retrieve the full title. - pageTitle = [] - for arg in pywikibot.handleArgs(*args): - if genFactory.handleArg(arg): - continue - if arg == '-redir': - redirs = True - else: - pageTitle.append(arg) - - gen = genFactory.getCombinedGenerator() - if not gen: - if pageTitle: - # work on a single page - page = pywikibot.Page(pywikibot.Link(' '.join(pageTitle))) - gen = iter([page]) - else: - pywikibot.showHelp() - return - preloadingGen = pagegenerators.PreloadingGenerator(gen) - bot = TouchBot(preloadingGen, redirs) - bot.run() - - -if __name__ == "__main__": - try: - main() - finally: - pywikibot.stopme() +#!/usr/bin/python +# -*- coding: utf-8 -*- + +"""This bot goes over multiple pages of a wiki, and edits them without +changing. This is for example used to get category links in templates +working. + +This script understands various command-line arguments: + +¶ms; + +-redir specifies that the robot should touch redirect pages; + otherwise, they will be skipped. + +All other parameters will be regarded as a page title; in this case, the bot +will only touch a single page. +""" + +__version__='$Id: touch.py,v 1.13 2006/03/01 14:07:06 russblau Exp $' + +import pywikibot +from pywikibot import pagegenerators, catlib, config +import sys + +docuReplacements = {'¶ms;': pagegenerators.parameterHelp} + + +class TouchBot: + def __init__(self, generator, touch_redirects): + self.generator = generator + self.touch_redirects = touch_redirects + + def run(self): + for page in self.generator: + try: + # get the page, and save it using the unmodified text. + # whether or not getting a redirect throws an exception + # depends on the variable self.touch_redirects. + text = page.get(get_redirect = self.touch_redirects) + page.save("Pywikibot touch script") + except pywikibot.NoPage: + pywikibot.output(u"Page %s does not exist?!" % page.title(asLink=True), + level=pywikibot.ERROR) + except pywikibot.IsRedirectPage: + pywikibot.output(u"Page %s is a redirect; skipping." + % page.title(asLink=True), + level=pywikibot.WARNING) + except pywikibot.LockedPage: + pywikibot.output(u"Page %s is locked?!" % page.title(asLink=True), + level=pywikibot.ERROR) + + +def main(*args): + global bot + # Disable cosmetic changes because we don't want to modify any page + # content, so that we don't flood the histories with minor changes. + config.cosmetic_changes = False + #page generator + gen = None + genFactory = pagegenerators.GeneratorFactory() + redirs = False + # If the user chooses to work on a single page, this temporary array is + # used to read the words from the page title. The words will later be + # joined with spaces to retrieve the full title. + pageTitle = [] + for arg in pywikibot.handleArgs(*args): + if genFactory.handleArg(arg): + continue + if arg == '-redir': + redirs = True + else: + pageTitle.append(arg) + + gen = genFactory.getCombinedGenerator() + if not gen: + if pageTitle: + # work on a single page + page = pywikibot.Page(pywikibot.Link(' '.join(pageTitle))) + gen = iter([page]) + else: + pywikibot.showHelp() + return + preloadingGen = pagegenerators.PreloadingGenerator(gen) + bot = TouchBot(preloadingGen, redirs) + bot.run() + + +if __name__ == "__main__": + try: + main() + finally: + pywikibot.stopme()
Property changes on: branches/rewrite/pywikibot/scripts/touch.py ___________________________________________________________________ Added: svn:eol-style + native
Property changes on: branches/rewrite/pywikibot/tests/__init__.py ___________________________________________________________________ Added: svn:eol-style + native
Modified: branches/rewrite/pywikibot/tests/api_tests.py =================================================================== --- branches/rewrite/pywikibot/tests/api_tests.py 2009-03-03 10:01:59 UTC (rev 6476) +++ branches/rewrite/pywikibot/tests/api_tests.py 2009-03-03 10:10:50 UTC (rev 6477) @@ -1,71 +1,71 @@ -import unittest -import pywikibot -import pywikibot.data.api as api - -mysite = pywikibot.Site('en', 'wikipedia') - - -class TestApiFunctions(unittest.TestCase): - - def testObjectCreation(self): - """Test that api.Request() creates an object with desired attributes""" - req = api.Request(site=mysite, foo="", bar="test") - self.assert_(req) - self.assertEqual(req.site, mysite) - self.assert_("foo" in req.params) - self.assertEqual(req["format"], "json") - self.assertEqual(req["bar"], "test") - # test item assignment - req["one"] = "1" - self.assertEqual(req.params['one'], "1") - # test compliance with dict interface - # req.keys() should contain "foo", "bar", "format", "maxlag", "one" - self.assertEqual(len(req.keys()), 5) - self.assert_("test" in req.values()) - self.assert_(all(len(item) == 2 for item in req.items())) - - -class TestPageGenerator(unittest.TestCase): - def setUp(self): - self.gen = api.PageGenerator(site=mysite, - generator="links", - titles="User:R'n'B") - # following test data is copied from an actual api.php response - self.gen.data = { - "query": {"pages": {"296589": {"pageid": 296589, - "ns": 0, - "title": "Broadcaster.com" - }, - "13918157": {"pageid": 13918157, - "ns": 0, - "title": "Broadcaster (definition)" - }, - "156658": {"pageid": 156658, - "ns": 0, - "title": "Wiktionary" - }, - "47757": {"pageid": 47757, - "ns": 4, - "title": "Wikipedia:Disambiguation" - } - } - } - } - - def testGeneratorResults(self): - """Test that PageGenerator yields pages with expected attributes.""" - titles = ["Broadcaster.com", "Broadcaster (definition)", - "Wiktionary", "Wikipedia:Disambiguation"] - results = [p for p in self.gen] - self.assertEqual(len(results), 4) - for page in results: - self.assertEqual(type(page), pywikibot.Page) - self.assertEqual(page.site(), mysite) - self.assert_(page.title() in titles) - - -if __name__ == '__main__': - try: - unittest.main() - except SystemExit: - pass +import unittest +import pywikibot +import pywikibot.data.api as api + +mysite = pywikibot.Site('en', 'wikipedia') + + +class TestApiFunctions(unittest.TestCase): + + def testObjectCreation(self): + """Test that api.Request() creates an object with desired attributes""" + req = api.Request(site=mysite, foo="", bar="test") + self.assert_(req) + self.assertEqual(req.site, mysite) + self.assert_("foo" in req.params) + self.assertEqual(req["format"], "json") + self.assertEqual(req["bar"], "test") + # test item assignment + req["one"] = "1" + self.assertEqual(req.params['one'], "1") + # test compliance with dict interface + # req.keys() should contain "foo", "bar", "format", "maxlag", "one" + self.assertEqual(len(req.keys()), 5) + self.assert_("test" in req.values()) + self.assert_(all(len(item) == 2 for item in req.items())) + + +class TestPageGenerator(unittest.TestCase): + def setUp(self): + self.gen = api.PageGenerator(site=mysite, + generator="links", + titles="User:R'n'B") + # following test data is copied from an actual api.php response + self.gen.data = { + "query": {"pages": {"296589": {"pageid": 296589, + "ns": 0, + "title": "Broadcaster.com" + }, + "13918157": {"pageid": 13918157, + "ns": 0, + "title": "Broadcaster (definition)" + }, + "156658": {"pageid": 156658, + "ns": 0, + "title": "Wiktionary" + }, + "47757": {"pageid": 47757, + "ns": 4, + "title": "Wikipedia:Disambiguation" + } + } + } + } + + def testGeneratorResults(self): + """Test that PageGenerator yields pages with expected attributes.""" + titles = ["Broadcaster.com", "Broadcaster (definition)", + "Wiktionary", "Wikipedia:Disambiguation"] + results = [p for p in self.gen] + self.assertEqual(len(results), 4) + for page in results: + self.assertEqual(type(page), pywikibot.Page) + self.assertEqual(page.site(), mysite) + self.assert_(page.title() in titles) + + +if __name__ == '__main__': + try: + unittest.main() + except SystemExit: + pass
Property changes on: branches/rewrite/pywikibot/tests/api_tests.py ___________________________________________________________________ Added: svn:eol-style + native
Modified: branches/rewrite/pywikibot/tests/page_tests.py =================================================================== --- branches/rewrite/pywikibot/tests/page_tests.py 2009-03-03 10:01:59 UTC (rev 6476) +++ branches/rewrite/pywikibot/tests/page_tests.py 2009-03-03 10:10:50 UTC (rev 6477) @@ -1,281 +1,281 @@ -# -*- coding: utf-8 -*- -""" -Tests for the page module. -""" -# -# (C) Pywikipedia bot team, 2008 -# -# Distributed under the terms of the MIT license. -# -__version__ = '$Id: $' - - -import unittest -import pywikibot -import pywikibot.page - -site = pywikibot.Site() -mainpage = pywikibot.Page(pywikibot.page.Link("Main Page", site)) -maintalk = pywikibot.Page(pywikibot.page.Link("Talk:Main Page", site)) -badpage = pywikibot.Page(pywikibot.page.Link("There is no page with this title", - site)) - -class TestLinkObject(unittest.TestCase): - """Test cases for Link objects""" - - enwiki = pywikibot.Site("en", "wikipedia") - namespaces = {0: [u""], # en.wikipedia.org namespaces for testing - 1: [u"Talk:"], # canonical form first, then others - 2: [u"User:"], # must end with : - 3: [u"User talk:", u"User_talk:"], - 4: [u"Wikipedia:", u"Project:", u"WP:"], - 5: [u"Wikipedia talk:", u"Project talk:", u"Wikipedia_talk:", - u"Project_talk:", u"WT:"], - 6: [u"Image:"], - 7: [u"Image talk:", u"Image_talk:"], - 8: [u"MediaWiki:"], - 9: [u"MediaWiki talk:", u"MediaWiki_talk:"], - 10: [u"Template:"], - 11: [u"Template talk:", u"Template_talk:"], - 12: [u"Help:"], - 13: [u"Help talk:", u"Help_talk:"], - 14: [u"Category:"], - 15: [u"Category talk:", u"Category_talk:"], - 100: [u"Portal:"], - 101: [u"Portal talk:", u"Portal_talk:"], - } - titles = { - # just a bunch of randomly selected titles - # input format : expected output format - u"Cities in Burkina Faso" : u"Cities in Burkina Faso", - u"eastern Sayan" : u"Eastern Sayan", - u"The_Addams_Family_(pinball)" : u"The Addams Family (pinball)", - u"Hispanic (U.S. Census)" : u"Hispanic (U.S. Census)", - u"Stołpce" : u"Stołpce", - u"Nowy_Sącz" : u"Nowy Sącz", - u"battle of Węgierska Górka" : u"Battle of Węgierska Górka", - } - # random bunch of possible section titles - sections = [u"", - u"#Phase_2", - u"#History", - u"#later life", - ] - - def testNamespaces(self): - """Test that Link() normalizes namespace names""" - for num in self.namespaces: - for prefix in self.namespaces[num]: - l = pywikibot.page.Link(prefix+self.titles.keys()[0], - self.enwiki) - self.assertEqual(l.namespace, num) - # namespace prefixes are case-insensitive - m = pywikibot.page.Link(prefix.lower()+self.titles.keys()[1], - self.enwiki) - self.assertEqual(m.namespace, num) - - def testTitles(self): - """Test that Link() normalizes titles""" - for title in self.titles: - for num in (0, 1): - l = pywikibot.page.Link(self.namespaces[num][0]+title) - self.assertEqual(l.title, self.titles[title]) - # prefixing name with ":" shouldn't change result - m = pywikibot.page.Link(":"+self.namespaces[num][0]+title) - self.assertEqual(m.title, self.titles[title]) - - -class TestPageObject(unittest.TestCase): - def testGeneral(self): - self.assertEqual(str(mainpage), "[[%s:%s]]" - % (site.lang, mainpage.title())) - self.assertTrue(mainpage < maintalk) - - def testSite(self): - """Test site() method""" - self.assertEqual(mainpage.site(), site) - self.assertEqual(mainpage.encoding(), site.encoding()) - - def testNamespace(self): - """Test namespace() method""" - self.assertEqual(mainpage.namespace(), 0) - self.assertEqual(maintalk.namespace(), 1) - self.assertEqual(badpage.namespace(), 0) - - def testTitle(self): - """Test title() method options.""" - p1 = pywikibot.Page(site, u"Help:Test page#Testing") - self.assertEqual(p1.title(), - u"Help:Test page#Testing") - self.assertEqual(p1.title(underscore=True), - u"Help:Test_page#Testing") - self.assertEqual(p1.title(withNamespace=False), - u"Test page#Testing") - self.assertEqual(p1.title(withSection=False), - u"Help:Test page") - self.assertEqual(p1.title(withNamespace=False, withSection=False), - u"Test page") - self.assertEqual(p1.title(asUrl=True), - "Help%3ATest_page%23Testing") - self.assertEqual(p1.title(asLink=True), - u"[[Help:Test page#Testing]]") - self.assertEqual(p1.title(asLink=True, forceInterwiki=True), - u"[[en:Help:Test page#Testing]]") - self.assertEqual(p1.title(asLink=True, textlink=True), - p1.title(asLink=True)) - # also test a page with non-ASCII chars and a different namespace - p2 = pywikibot.Page(site, u"Image:Jean-Léon Gérôme 003.jpg") - self.assertEqual(p2.title(), - u"Image:Jean-Léon Gérôme 003.jpg") - self.assertEqual(p2.title(underscore=True), - u"Image:Jean-Léon_Gérôme_003.jpg") - self.assertEqual(p2.title(withNamespace=False), - u"Jean-Léon Gérôme 003.jpg") - self.assertEqual(p2.title(withSection=False), - u"Image:Jean-Léon Gérôme 003.jpg") - self.assertEqual(p2.title(withNamespace=False, withSection=False), - u"Jean-Léon Gérôme 003.jpg") - self.assertEqual(p2.title(asUrl=True), - u"Image%3AJean-L%C3%A9on_G%C3%A9r%C3%B4me_003.jpg") - self.assertEqual(p2.title(asLink=True), - u"[[Image:Jean-Léon Gérôme 003.jpg]]") - self.assertEqual(p2.title(asLink=True, forceInterwiki=True), - u"[[en:Image:Jean-Léon Gérôme 003.jpg]]") - self.assertEqual(p2.title(asLink=True, textlink=True), - u"[[:Image:Jean-Léon Gérôme 003.jpg]]") - self.assertEqual(p2.title(as_filename=True), - u"Image_Jean-Léon_Gérôme_003.jpg") - - def testSection(self): - """Test section() method.""" - # use same pages as in previous test - p1 = pywikibot.Page(site, u"Help:Test page#Testing") - p2 = pywikibot.Page(site, u"Image:Jean-Léon Gérôme 003.jpg") - self.assertEqual(p1.section(), u"Testing") - self.assertEqual(p2.section(), None) - - def testIsTalkPage(self): - """Test isTalkPage() method.""" - p1 = pywikibot.Page(site, u"First page") - p2 = pywikibot.Page(site, u"Talk:First page") - p3 = pywikibot.Page(site, u"User:Second page") - p4 = pywikibot.Page(site, u"User talk:Second page") - self.assertEqual(p1.isTalkPage(), False) - self.assertEqual(p2.isTalkPage(), True) - self.assertEqual(p3.isTalkPage(), False) - self.assertEqual(p4.isTalkPage(), True) - - def testIsCategory(self): - """Test isCategory method.""" - p1 = pywikibot.Page(site, u"First page") - p2 = pywikibot.Page(site, u"Category:Second page") - p3 = pywikibot.Page(site, u"Category talk:Second page") - self.assertEqual(p1.isCategory(), False) - self.assertEqual(p2.isCategory(), True) - self.assertEqual(p3.isCategory(), False) - - def testIsImage(self): - p1 = pywikibot.Page(site, u"First page") - p2 = pywikibot.Page(site, u"Image:Second page") - p3 = pywikibot.Page(site, u"Image talk:Second page") - self.assertEqual(p1.isImage(), False) - self.assertEqual(p2.isImage(), True) - self.assertEqual(p3.isImage(), False) - - def testApiMethods(self): - """Test various methods that rely on API.""" - # since there is no way to predict what data the wiki will return, - # we only check that the returned objects are of correct type. - self.assertTrue(isinstance(mainpage.get(), unicode)) - self.assertTrue(isinstance(maintalk.get(), unicode)) - self.assertRaises(pywikibot.NoPage, badpage.get) - self.assertTrue(isinstance(mainpage.latestRevision(), int)) - self.assertTrue(isinstance(mainpage.userName(), unicode)) - self.assertTrue(isinstance(mainpage.isIpEdit(), bool)) - self.assertTrue(isinstance(mainpage.exists(), bool)) - self.assertTrue(isinstance(mainpage.isRedirectPage(), bool)) - self.assertTrue(isinstance(mainpage.isEmpty(), bool)) - self.assertEqual(mainpage.toggleTalkPage(), maintalk) - self.assertEqual(maintalk.toggleTalkPage(), mainpage) - self.assertTrue(isinstance(mainpage.isDisambig(), bool)) - self.assertTrue(isinstance(mainpage.canBeEdited(), bool)) - self.assertTrue(isinstance(mainpage.botMayEdit(), bool)) - self.assertTrue(isinstance(mainpage.editTime(), unicode)) - self.assertTrue(isinstance(mainpage.previousRevision(), int)) - self.assertTrue(isinstance(mainpage.permalink(), basestring)) - - def testReferences(self): - count = 0 - for p in mainpage.getReferences(): - count += 1 - self.assertTrue(isinstance(p, pywikibot.Page)) - if count >= 10: - break - count = 0 - for p in mainpage.backlinks(): - count += 1 - self.assertTrue(isinstance(p, pywikibot.Page)) - if count >= 10: - break - count = 0 - for p in mainpage.embeddedin(): - count += 1 - self.assertTrue(isinstance(p, pywikibot.Page)) - if count >= 10: - break - - def testLinks(self): - for p in mainpage.linkedPages(): - self.assertTrue(isinstance(p, pywikibot.Page)) - iw = list(mainpage.interwiki(expand=True)) - for p in iw: - self.assertTrue(isinstance(p, pywikibot.Link)) - for p2 in mainpage.interwiki(expand=False): - self.assertTrue(isinstance(p2, pywikibot.Link)) - self.assertTrue(p2 in iw) - for p in mainpage.langlinks(): - self.assertTrue(isinstance(p, pywikibot.Link)) - for p in mainpage.imagelinks(): - self.assertTrue(isinstance(p, pywikibot.ImagePage)) - for p in mainpage.templates(): - self.assertTrue(isinstance(p, pywikibot.Page)) - for t, params in mainpage.templatesWithParams(): - self.assertTrue(isinstance(t, pywikibot.Page)) - self.assertTrue(isinstance(params, list)) - for p in mainpage.categories(): - self.assertTrue(isinstance(p, pywikibot.Category)) - for p in mainpage.extlinks(): - self.assertTrue(isinstance(p, unicode)) - -# methods that still need tests implemented or expanded: - -## def autoFormat(self): -## def isAutoTitle(self): -## def get(self, force=False, get_redirect=False, sysop=False): -## def getOldVersion(self, oldid, force=False, get_redirect=False, -## sysop=False): -## text = property(_textgetter, _textsetter, _cleartext, -## "The edited wikitext (unicode) of this Page") -## def getReferences(self, follow_redirects=True, withTemplateInclusion=True, -## onlyTemplateInclusion=False, redirectsOnly=False, -## namespaces=None): -## def backlinks(self, followRedirects=True, filterRedirects=None, -## namespaces=None): -## def embeddedin(self, filter_redirects=None, namespaces=None): -## def getRedirectTarget(self): -## def getVersionHistory(self, reverseOrder=False, getAll=False, -## revCount=500): -## def getVersionHistoryTable(self, forceReload=False, reverseOrder=False, -## getAll=False, revCount=500): -## def fullVersionHistory(self): -## def contributingUsers(self): - - -if __name__ == '__main__': - try: - try: - unittest.main() - except SystemExit: - pass - finally: - pywikibot.stopme() +# -*- coding: utf-8 -*- +""" +Tests for the page module. +""" +# +# (C) Pywikipedia bot team, 2008 +# +# Distributed under the terms of the MIT license. +# +__version__ = '$Id: $' + + +import unittest +import pywikibot +import pywikibot.page + +site = pywikibot.Site() +mainpage = pywikibot.Page(pywikibot.page.Link("Main Page", site)) +maintalk = pywikibot.Page(pywikibot.page.Link("Talk:Main Page", site)) +badpage = pywikibot.Page(pywikibot.page.Link("There is no page with this title", + site)) + +class TestLinkObject(unittest.TestCase): + """Test cases for Link objects""" + + enwiki = pywikibot.Site("en", "wikipedia") + namespaces = {0: [u""], # en.wikipedia.org namespaces for testing + 1: [u"Talk:"], # canonical form first, then others + 2: [u"User:"], # must end with : + 3: [u"User talk:", u"User_talk:"], + 4: [u"Wikipedia:", u"Project:", u"WP:"], + 5: [u"Wikipedia talk:", u"Project talk:", u"Wikipedia_talk:", + u"Project_talk:", u"WT:"], + 6: [u"Image:"], + 7: [u"Image talk:", u"Image_talk:"], + 8: [u"MediaWiki:"], + 9: [u"MediaWiki talk:", u"MediaWiki_talk:"], + 10: [u"Template:"], + 11: [u"Template talk:", u"Template_talk:"], + 12: [u"Help:"], + 13: [u"Help talk:", u"Help_talk:"], + 14: [u"Category:"], + 15: [u"Category talk:", u"Category_talk:"], + 100: [u"Portal:"], + 101: [u"Portal talk:", u"Portal_talk:"], + } + titles = { + # just a bunch of randomly selected titles + # input format : expected output format + u"Cities in Burkina Faso" : u"Cities in Burkina Faso", + u"eastern Sayan" : u"Eastern Sayan", + u"The_Addams_Family_(pinball)" : u"The Addams Family (pinball)", + u"Hispanic (U.S. Census)" : u"Hispanic (U.S. Census)", + u"Stołpce" : u"Stołpce", + u"Nowy_Sącz" : u"Nowy Sącz", + u"battle of Węgierska Górka" : u"Battle of Węgierska Górka", + } + # random bunch of possible section titles + sections = [u"", + u"#Phase_2", + u"#History", + u"#later life", + ] + + def testNamespaces(self): + """Test that Link() normalizes namespace names""" + for num in self.namespaces: + for prefix in self.namespaces[num]: + l = pywikibot.page.Link(prefix+self.titles.keys()[0], + self.enwiki) + self.assertEqual(l.namespace, num) + # namespace prefixes are case-insensitive + m = pywikibot.page.Link(prefix.lower()+self.titles.keys()[1], + self.enwiki) + self.assertEqual(m.namespace, num) + + def testTitles(self): + """Test that Link() normalizes titles""" + for title in self.titles: + for num in (0, 1): + l = pywikibot.page.Link(self.namespaces[num][0]+title) + self.assertEqual(l.title, self.titles[title]) + # prefixing name with ":" shouldn't change result + m = pywikibot.page.Link(":"+self.namespaces[num][0]+title) + self.assertEqual(m.title, self.titles[title]) + + +class TestPageObject(unittest.TestCase): + def testGeneral(self): + self.assertEqual(str(mainpage), "[[%s:%s]]" + % (site.lang, mainpage.title())) + self.assertTrue(mainpage < maintalk) + + def testSite(self): + """Test site() method""" + self.assertEqual(mainpage.site(), site) + self.assertEqual(mainpage.encoding(), site.encoding()) + + def testNamespace(self): + """Test namespace() method""" + self.assertEqual(mainpage.namespace(), 0) + self.assertEqual(maintalk.namespace(), 1) + self.assertEqual(badpage.namespace(), 0) + + def testTitle(self): + """Test title() method options.""" + p1 = pywikibot.Page(site, u"Help:Test page#Testing") + self.assertEqual(p1.title(), + u"Help:Test page#Testing") + self.assertEqual(p1.title(underscore=True), + u"Help:Test_page#Testing") + self.assertEqual(p1.title(withNamespace=False), + u"Test page#Testing") + self.assertEqual(p1.title(withSection=False), + u"Help:Test page") + self.assertEqual(p1.title(withNamespace=False, withSection=False), + u"Test page") + self.assertEqual(p1.title(asUrl=True), + "Help%3ATest_page%23Testing") + self.assertEqual(p1.title(asLink=True), + u"[[Help:Test page#Testing]]") + self.assertEqual(p1.title(asLink=True, forceInterwiki=True), + u"[[en:Help:Test page#Testing]]") + self.assertEqual(p1.title(asLink=True, textlink=True), + p1.title(asLink=True)) + # also test a page with non-ASCII chars and a different namespace + p2 = pywikibot.Page(site, u"Image:Jean-Léon Gérôme 003.jpg") + self.assertEqual(p2.title(), + u"Image:Jean-Léon Gérôme 003.jpg") + self.assertEqual(p2.title(underscore=True), + u"Image:Jean-Léon_Gérôme_003.jpg") + self.assertEqual(p2.title(withNamespace=False), + u"Jean-Léon Gérôme 003.jpg") + self.assertEqual(p2.title(withSection=False), + u"Image:Jean-Léon Gérôme 003.jpg") + self.assertEqual(p2.title(withNamespace=False, withSection=False), + u"Jean-Léon Gérôme 003.jpg") + self.assertEqual(p2.title(asUrl=True), + u"Image%3AJean-L%C3%A9on_G%C3%A9r%C3%B4me_003.jpg") + self.assertEqual(p2.title(asLink=True), + u"[[Image:Jean-Léon Gérôme 003.jpg]]") + self.assertEqual(p2.title(asLink=True, forceInterwiki=True), + u"[[en:Image:Jean-Léon Gérôme 003.jpg]]") + self.assertEqual(p2.title(asLink=True, textlink=True), + u"[[:Image:Jean-Léon Gérôme 003.jpg]]") + self.assertEqual(p2.title(as_filename=True), + u"Image_Jean-Léon_Gérôme_003.jpg") + + def testSection(self): + """Test section() method.""" + # use same pages as in previous test + p1 = pywikibot.Page(site, u"Help:Test page#Testing") + p2 = pywikibot.Page(site, u"Image:Jean-Léon Gérôme 003.jpg") + self.assertEqual(p1.section(), u"Testing") + self.assertEqual(p2.section(), None) + + def testIsTalkPage(self): + """Test isTalkPage() method.""" + p1 = pywikibot.Page(site, u"First page") + p2 = pywikibot.Page(site, u"Talk:First page") + p3 = pywikibot.Page(site, u"User:Second page") + p4 = pywikibot.Page(site, u"User talk:Second page") + self.assertEqual(p1.isTalkPage(), False) + self.assertEqual(p2.isTalkPage(), True) + self.assertEqual(p3.isTalkPage(), False) + self.assertEqual(p4.isTalkPage(), True) + + def testIsCategory(self): + """Test isCategory method.""" + p1 = pywikibot.Page(site, u"First page") + p2 = pywikibot.Page(site, u"Category:Second page") + p3 = pywikibot.Page(site, u"Category talk:Second page") + self.assertEqual(p1.isCategory(), False) + self.assertEqual(p2.isCategory(), True) + self.assertEqual(p3.isCategory(), False) + + def testIsImage(self): + p1 = pywikibot.Page(site, u"First page") + p2 = pywikibot.Page(site, u"Image:Second page") + p3 = pywikibot.Page(site, u"Image talk:Second page") + self.assertEqual(p1.isImage(), False) + self.assertEqual(p2.isImage(), True) + self.assertEqual(p3.isImage(), False) + + def testApiMethods(self): + """Test various methods that rely on API.""" + # since there is no way to predict what data the wiki will return, + # we only check that the returned objects are of correct type. + self.assertTrue(isinstance(mainpage.get(), unicode)) + self.assertTrue(isinstance(maintalk.get(), unicode)) + self.assertRaises(pywikibot.NoPage, badpage.get) + self.assertTrue(isinstance(mainpage.latestRevision(), int)) + self.assertTrue(isinstance(mainpage.userName(), unicode)) + self.assertTrue(isinstance(mainpage.isIpEdit(), bool)) + self.assertTrue(isinstance(mainpage.exists(), bool)) + self.assertTrue(isinstance(mainpage.isRedirectPage(), bool)) + self.assertTrue(isinstance(mainpage.isEmpty(), bool)) + self.assertEqual(mainpage.toggleTalkPage(), maintalk) + self.assertEqual(maintalk.toggleTalkPage(), mainpage) + self.assertTrue(isinstance(mainpage.isDisambig(), bool)) + self.assertTrue(isinstance(mainpage.canBeEdited(), bool)) + self.assertTrue(isinstance(mainpage.botMayEdit(), bool)) + self.assertTrue(isinstance(mainpage.editTime(), unicode)) + self.assertTrue(isinstance(mainpage.previousRevision(), int)) + self.assertTrue(isinstance(mainpage.permalink(), basestring)) + + def testReferences(self): + count = 0 + for p in mainpage.getReferences(): + count += 1 + self.assertTrue(isinstance(p, pywikibot.Page)) + if count >= 10: + break + count = 0 + for p in mainpage.backlinks(): + count += 1 + self.assertTrue(isinstance(p, pywikibot.Page)) + if count >= 10: + break + count = 0 + for p in mainpage.embeddedin(): + count += 1 + self.assertTrue(isinstance(p, pywikibot.Page)) + if count >= 10: + break + + def testLinks(self): + for p in mainpage.linkedPages(): + self.assertTrue(isinstance(p, pywikibot.Page)) + iw = list(mainpage.interwiki(expand=True)) + for p in iw: + self.assertTrue(isinstance(p, pywikibot.Link)) + for p2 in mainpage.interwiki(expand=False): + self.assertTrue(isinstance(p2, pywikibot.Link)) + self.assertTrue(p2 in iw) + for p in mainpage.langlinks(): + self.assertTrue(isinstance(p, pywikibot.Link)) + for p in mainpage.imagelinks(): + self.assertTrue(isinstance(p, pywikibot.ImagePage)) + for p in mainpage.templates(): + self.assertTrue(isinstance(p, pywikibot.Page)) + for t, params in mainpage.templatesWithParams(): + self.assertTrue(isinstance(t, pywikibot.Page)) + self.assertTrue(isinstance(params, list)) + for p in mainpage.categories(): + self.assertTrue(isinstance(p, pywikibot.Category)) + for p in mainpage.extlinks(): + self.assertTrue(isinstance(p, unicode)) + +# methods that still need tests implemented or expanded: + +## def autoFormat(self): +## def isAutoTitle(self): +## def get(self, force=False, get_redirect=False, sysop=False): +## def getOldVersion(self, oldid, force=False, get_redirect=False, +## sysop=False): +## text = property(_textgetter, _textsetter, _cleartext, +## "The edited wikitext (unicode) of this Page") +## def getReferences(self, follow_redirects=True, withTemplateInclusion=True, +## onlyTemplateInclusion=False, redirectsOnly=False, +## namespaces=None): +## def backlinks(self, followRedirects=True, filterRedirects=None, +## namespaces=None): +## def embeddedin(self, filter_redirects=None, namespaces=None): +## def getRedirectTarget(self): +## def getVersionHistory(self, reverseOrder=False, getAll=False, +## revCount=500): +## def getVersionHistoryTable(self, forceReload=False, reverseOrder=False, +## getAll=False, revCount=500): +## def fullVersionHistory(self): +## def contributingUsers(self): + + +if __name__ == '__main__': + try: + try: + unittest.main() + except SystemExit: + pass + finally: + pywikibot.stopme()
Property changes on: branches/rewrite/pywikibot/tests/page_tests.py ___________________________________________________________________ Added: svn:eol-style + native
Modified: branches/rewrite/pywikibot/tests/site_tests.py =================================================================== --- branches/rewrite/pywikibot/tests/site_tests.py 2009-03-03 10:01:59 UTC (rev 6476) +++ branches/rewrite/pywikibot/tests/site_tests.py 2009-03-03 10:10:50 UTC (rev 6477) @@ -1,919 +1,919 @@ -# -*- coding: utf-8 -*- -""" -Tests for the site module. -""" -# -# (C) Pywikipedia bot team, 2008 -# -# Distributed under the terms of the MIT license. -# -__version__ = '$Id: $' - - -import unittest -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 - - -class TestSiteObject(unittest.TestCase): - """Test cases for Site methods.""" - - def assertType(self, obj, cls): - """Assert that obj is an instance of type cls""" - return self.assertTrue(isinstance(obj, cls)) - - def testBaseMethods(self): - """Test cases for BaseSite methods""" - - self.assertEqual(mysite.family.name, pywikibot.config2.family) - self.assertEqual(mysite.code, pywikibot.config2.mylang) - self.assertType(mysite.lang, basestring) - self.assertType(mysite == pywikibot.Site("en", "wikipedia"), bool) - self.assertType(mysite.user(), (basestring, type(None))) - self.assertEqual(mysite.sitename(), - "%s:%s" % (pywikibot.config2.family, - pywikibot.config2.mylang)) - self.assertEqual(repr(mysite), - 'Site("%s", "%s")' - % (pywikibot.config2.mylang, pywikibot.config2.family)) - self.assertType(mysite.linktrail(), basestring) - self.assertType(mysite.redirect(default=True), basestring) - self.assertType(mysite.disambcategory(), pywikibot.Category) - self.assertEqual(mysite.linkto("foo"), u"[[Foo]]") - self.assertFalse(mysite.isInterwikiLink("foo")) - self.assertType(mysite.redirectRegex().pattern, basestring) - self.assertType(mysite.category_on_one_line(), bool) - for grp in ("user", "autoconfirmed", "bot", "sysop", "nosuchgroup"): - self.assertType(mysite.has_group(grp), bool) - for rgt in ("read", "edit", "move", "delete", "rollback", "block", - "nosuchright"): - self.assertType(mysite.has_right(rgt), bool) - - def testLanguageMethods(self): - """Test cases for languages() and related methods""" - - langs = mysite.languages() - self.assertType(langs, list) - self.assertTrue(mysite.code in langs) - obs = mysite.family.obsolete - ipf = mysite.interwiki_putfirst() - self.assertType(ipf, list) - self.assertTrue(all(item in langs or item in obs - for item in ipf)) - self.assertTrue(all(item in langs - for item in mysite.validLanguageLinks())) - - def testNamespaceMethods(self): - """Test cases for methods manipulating namespace names""" - - builtins = {'Talk': 1, # these should work in any MW wiki - 'User': 2, - 'User talk': 3, - 'Project': 4, - 'Project talk': 5, - 'Image': 6, - 'Image talk': 7, - 'MediaWiki': 8, - 'MediaWiki talk': 9, - 'Template': 10, - 'Template talk': 11, - 'Help': 12, - 'Help talk': 13, - 'Category': 14, - 'Category talk': 15, - } - self.assertTrue(all(mysite.ns_index(b) == builtins[b] - for b in builtins)) - ns = mysite.namespaces() - self.assertType(ns, dict) - self.assertTrue(all(x in ns for x in xrange(0, 16))) - # built-in namespaces always present - self.assertType(mysite.ns_normalize("project"), basestring) - self.assertTrue(all(isinstance(key, int) - for key in ns)) - self.assertTrue(all(isinstance(val, list) - for val in ns.values())) - self.assertTrue(all(isinstance(name, basestring) - for val in ns.values() - for name in val)) - self.assertTrue(all(isinstance(mysite.namespace(key), basestring) - for key in ns)) - self.assertTrue(all(isinstance(mysite.namespace(key, True), list) - for key in ns)) - self.assertTrue(all(isinstance(item, basestring) - for key in ns - for item in mysite.namespace(key, True))) - - 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) - self.assertType(mysite.is_blocked(), bool) - self.assertType(mysite.messages(), bool) - self.assertType(mysite.has_right("edit"), bool) - self.assertFalse(mysite.has_right("nonexistent_right")) - self.assertType(mysite.has_group("bots"), bool) - self.assertFalse(mysite.has_group("nonexistent_group")) - try: - self.assertType(mysite.is_blocked(True), bool) - self.assertType(mysite.has_right("edit", True), bool) - self.assertFalse(mysite.has_right("nonexistent_right", True)) - self.assertType(mysite.has_group("bots", True), bool) - self.assertFalse(mysite.has_group("nonexistent_group", True)) - except pywikibot.NoUsername: - logger.warn( - "Cannot test Site methods for sysop; no sysop account configured.") - for msg in ("1movedto2", "about", "aboutpage", "aboutsite", - "accesskey-n-portal"): - self.assertTrue(mysite.has_mediawiki_message(msg)) - self.assertType(mysite.mediawiki_message(msg), basestring) - self.assertFalse(mysite.has_mediawiki_message("nosuchmessage")) - self.assertRaises(KeyError, mysite.mediawiki_message, "nosuchmessage") - self.assertType(mysite.getcurrenttimestamp(), basestring) - self.assertType(mysite.siteinfo, dict) - self.assertType(mysite.case(), basestring) - ver = mysite.live_version() - self.assertType(ver, tuple) - self.assertTrue(all(isinstance(ver[i], int) for i in (0, 1))) - self.assertType(ver[2], basestring) - - 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) - self.assertType(mysite.page_isredirect(mainpage), bool) - if mysite.page_isredirect(mainpage): - self.assertType(mysite.getredirtarget(mainpage), pywikibot.Page) - else: - self.assertRaises(pywikibot.IsNotRedirectPage, - mysite.getredirtarget, mainpage) - a = list(mysite.preloadpages([mainpage])) - self.assertEqual(len(a), int(mysite.page_exists(mainpage))) - if a: - self.assertEqual(a[0], mainpage) - - 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") - - def testPreload(self): - """Test that preloading works""" - - count = 0 - for page in mysite.preloadpages(mysite.pagelinks(mainpage, limit=10)): - self.assertType(page, pywikibot.Page) - self.assertType(page.exists(), bool) - if page.exists(): - self.assertTrue(hasattr(page, "_text")) - count += 1 - if count >= 5: - break - - 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, - filterRedirects=False)) - # only redirects: - redirs = set(mysite.pagebacklinks(mainpage, namespaces=0, - filterRedirects=True)) - # including links to redirect pages (but not the redirects): - indirect = set(mysite.pagebacklinks(mainpage, namespaces=[0], - followRedirects=True)) - self.assertEqual(filtered & redirs, set([])) - self.assertEqual(indirect & redirs, set([])) - self.assertTrue(filtered.issubset(indirect)) - self.assertTrue(filtered.issubset(backlinks)) - self.assertTrue(redirs.issubset(backlinks)) - self.assertTrue(backlinks.issubset( - set(mysite.pagebacklinks(mainpage, namespaces=[0, 2])))) - - # pagereferences includes both backlinks and embeddedin - embedded = set(mysite.page_embeddedin(mainpage, namespaces=[0])) - refs = set(mysite.pagereferences(mainpage, namespaces=[0])) - self.assertTrue(backlinks.issubset(refs)) - self.assertTrue(embedded.issubset(refs)) - for bl in backlinks: - self.assertType(bl, pywikibot.Page) - self.assertTrue(bl in refs) - for ei in embedded: - self.assertType(ei, pywikibot.Page) - self.assertTrue(ei in refs) - for ref in refs: - self.assertTrue(ref in backlinks or ref in embedded) - # test embeddedin arguments - self.assertTrue(embedded.issuperset( - set(mysite.page_embeddedin(mainpage, filterRedirects=True, - namespaces=[0])))) - self.assertTrue(embedded.issuperset( - set(mysite.page_embeddedin(mainpage, filterRedirects=False, - namespaces=[0])))) - self.assertTrue(embedded.issubset( - set(mysite.page_embeddedin(mainpage, namespaces=[0, 2])))) - links = set(mysite.pagelinks(mainpage)) - for pl in links: - self.assertType(pl, pywikibot.Page) - # test links arguments - self.assertTrue(links.issuperset( - set(mysite.pagelinks(mainpage, namespaces=[0, 1])))) - for target in mysite.preloadpages( - mysite.pagelinks(mainpage, follow_redirects=True, - limit=5)): - self.assertType(target, pywikibot.Page) - self.assertFalse(target.isRedirectPage()) - # test pagecategories - for cat in mysite.pagecategories(mainpage): - self.assertType(cat, pywikibot.Category) - for cm in mysite.categorymembers(cat): - self.assertType(cat, pywikibot.Page) - # test pageimages - self.assertTrue(all(isinstance(im, pywikibot.ImagePage) - for im in mysite.pageimages(mainpage))) - # test pagetemplates - self.assertTrue(all(isinstance(te, pywikibot.Page) - for te in mysite.pagetemplates(mainpage))) - self.assertTrue(set(mysite.pagetemplates(mainpage)).issuperset( - set(mysite.pagetemplates(mainpage, namespaces=[10])))) - # test pagelanglinks - for ll in mysite.pagelanglinks(mainpage): - self.assertType(ll, pywikibot.Link) - # test page_extlinks - self.assertTrue(all(isinstance(el, basestring) - for el in mysite.page_extlinks(mainpage))) - - def testLoadRevisions(self): - """Test the site.loadrevisions() method""" - - mysite.loadrevisions(mainpage) - self.assertTrue(hasattr(mainpage, "_revid")) - self.assertTrue(hasattr(mainpage, "_revisions")) - self.assertTrue(mainpage._revid in mainpage._revisions) - # TODO test all the optional arguments - - def testAllPages(self): - """Test the site.allpages() method""" - - fwd = list(mysite.allpages(limit=10)) - self.assertTrue(len(fwd) <= 10) - for page in fwd: - self.assertType(page, pywikibot.Page) - self.assertTrue(mysite.page_exists(page)) - self.assertEqual(page.namespace(), 0) - rev = list(mysite.allpages(reverse=True, start="Aa", limit=12)) - self.assertTrue(len(rev) <= 12) - for page in rev: - self.assertType(page, pywikibot.Page) - self.assertTrue(mysite.page_exists(page)) - self.assertEqual(page.namespace(), 0) - self.assertTrue(page.title() <= "Aa") - for page in mysite.allpages(start="Py", limit=5): - self.assertType(page, pywikibot.Page) - self.assertTrue(mysite.page_exists(page)) - self.assertEqual(page.namespace(), 0) - self.assertTrue(page.title() >= "Py") - for page in mysite.allpages(prefix="Pre", limit=5): - self.assertType(page, pywikibot.Page) - self.assertTrue(mysite.page_exists(page)) - self.assertEqual(page.namespace(), 0) - self.assertTrue(page.title().startswith("Pre")) - for page in mysite.allpages(namespace=1, limit=5): - self.assertType(page, pywikibot.Page) - self.assertTrue(mysite.page_exists(page)) - self.assertEqual(page.namespace(), 1) - for page in mysite.allpages(filterredir=True, limit=5): - self.assertType(page, pywikibot.Page) - self.assertTrue(mysite.page_exists(page)) - self.assertEqual(page.namespace(), 0) - self.assertTrue(page.isRedirectPage()) - for page in mysite.allpages(filterredir=False, limit=5): - self.assertType(page, pywikibot.Page) - self.assertTrue(mysite.page_exists(page)) - self.assertEqual(page.namespace(), 0) - self.assertFalse(page.isRedirectPage()) -## for page in mysite.allpages(filterlanglinks=True, limit=5): -## self.assertType(page, pywikibot.Page) -## self.assertTrue(mysite.page_exists(page)) -## self.assertEqual(page.namespace(), 0) -## for page in mysite.allpages(filterlanglinks=False, limit=5): -## self.assertType(page, pywikibot.Page) -## self.assertTrue(mysite.page_exists(page)) -## self.assertEqual(page.namespace(), 0) - for page in mysite.allpages(minsize=100, limit=5): - self.assertType(page, pywikibot.Page) - self.assertTrue(mysite.page_exists(page)) - self.assertTrue(len(page.text) >= 100) - for page in mysite.allpages(maxsize=200, limit=5): - self.assertType(page, pywikibot.Page) - self.assertTrue(mysite.page_exists(page)) - self.assertTrue(len(page.text) <= 200) - for page in mysite.allpages(protect_type="edit", limit=5): - self.assertType(page, pywikibot.Page) - self.assertTrue(mysite.page_exists(page)) - self.assertTrue("edit" in page._protection) - for page in mysite.allpages(protect_type="edit", - protect_level="sysop", limit=5): - self.assertType(page, pywikibot.Page) - self.assertTrue(mysite.page_exists(page)) - self.assertTrue("edit" in page._protection) - self.assertTrue("sysop" in page._protection["edit"]) - - def testAllLinks(self): - """Test the site.alllinks() method""" - - fwd = list(mysite.alllinks(limit=10)) - self.assertTrue(len(fwd) <= 10) - self.assertTrue(all(isinstance(link, pywikibot.Page) for link in fwd)) - uniq = list(mysite.alllinks(limit=10, unique=True)) - self.assertTrue(all(link in uniq for link in fwd)) - for page in mysite.alllinks(start="Link", limit=5): - self.assertType(page, pywikibot.Page) - self.assertEqual(page.namespace(), 0) - self.assertTrue(page.title() >= "Link") - for page in mysite.alllinks(prefix="Fix", limit=5): - self.assertType(page, pywikibot.Page) - self.assertEqual(page.namespace(), 0) - self.assertTrue(page.title().startswith("Fix")) - for page in mysite.alllinks(namespace=1, limit=5): - self.assertType(page, pywikibot.Page) - self.assertEqual(page.namespace(), 1) - for page in mysite.alllinks(start="From", namespace=4, fromids=True, - limit=5): - self.assertType(page, pywikibot.Page) - self.assertTrue(page.title(withNamespace=False) >= "From") - self.assertTrue(hasattr(page, "_fromid")) - errgen = mysite.alllinks(unique=True, fromids=True) - self.assertRaises(pywikibot.Error, errgen.next) - - def testAllCategories(self): - """Test the site.allcategories() method""" - - ac = list(mysite.allcategories(limit=10)) - self.assertTrue(len(ac) <= 10) - self.assertTrue(all(isinstance(cat, pywikibot.Category) - for cat in ac)) - for cat in mysite.allcategories(limit=5, start="Abc"): - self.assertType(cat, pywikibot.Category) - self.assertTrue(cat.title(withNamespace=False) >= "Abc") - for cat in mysite.allcategories(limit=5, prefix="Def"): - self.assertType(cat, pywikibot.Category) - self.assertTrue(cat.title(withNamespace=False).startswith("Def")) -## # Bug # 15985 -## for cat in mysite.allcategories(limit=5, start="Hij", reverse=True): -## self.assertType(cat, pywikibot.Category) -## self.assertTrue(cat.title(withNamespace=False) <= "Hij") - - def testAllUsers(self): - """Test the site.allusers() method""" - - au = list(mysite.allusers(limit=10)) - self.assertTrue(len(au) <= 10) - for user in au: - self.assertType(user, dict) - self.assertTrue("name" in user) - self.assertTrue("editcount" in user) - self.assertTrue("registration" in user) - for user in mysite.allusers(start="B", limit=5): - self.assertType(user, dict) - self.assertTrue("name" in user) - self.assertTrue(user["name"] >= "B") - self.assertTrue("editcount" in user) - self.assertTrue("registration" in user) - for user in mysite.allusers(prefix="C", limit=5): - self.assertType(user, dict) - self.assertTrue("name" in user) - self.assertTrue(user["name"].startswith("C")) - self.assertTrue("editcount" in user) - self.assertTrue("registration" in user) - for user in mysite.allusers(prefix="D", group="sysop", limit=5): - self.assertType(user, dict) - self.assertTrue("name" in user) - self.assertTrue(user["name"].startswith("D")) - self.assertTrue("editcount" in user) - self.assertTrue("registration" in user) - self.assertTrue("groups" in user and "sysop" in user["groups"]) - - def testAllImages(self): - """Test the site.allimages() method""" - - ai = list(mysite.allimages(limit=10)) - self.assertTrue(len(ai) <= 10) - self.assertTrue(all(isinstance(image, pywikibot.ImagePage) - for image in ai)) - for impage in mysite.allimages(start="Ba", limit=5): - self.assertType(impage, pywikibot.ImagePage) - self.assertTrue(mysite.page_exists(impage)) - self.assertTrue(impage.title(withNamespace=False) >= "Ba") -## # Bug # 15985 -## for impage in mysite.allimages(start="Da", reverse=True, limit=5): -## self.assertType(impage, pywikibot.ImagePage) -## self.assertTrue(mysite.page_exists(impage)) -## self.assertTrue(impage.title() <= "Da") - for impage in mysite.allimages(prefix="Ch", limit=5): - self.assertType(impage, pywikibot.ImagePage) - self.assertTrue(mysite.page_exists(impage)) - self.assertTrue(impage.title(withNamespace=False).startswith("Ch")) - for impage in mysite.allimages(minsize=100, limit=5): - self.assertType(impage, pywikibot.ImagePage) - self.assertTrue(mysite.page_exists(impage)) - self.assertTrue(impage._imageinfo["size"] >= 100) - for impage in mysite.allimages(maxsize=2000, limit=5): - self.assertType(impage, pywikibot.ImagePage) - self.assertTrue(mysite.page_exists(impage)) - self.assertTrue(impage._imageinfo["size"] <= 2000) - - def testBlocks(self): - """Test the site.blocks() method""" - - props = ("id", "by", "timestamp", "expiry", "reason") - bl = list(mysite.blocks(limit=10)) - self.assertTrue(len(bl) <= 10) - for block in bl: - self.assertType(block, dict) - for prop in props: - self.assertTrue(prop in block) - # timestamps should be in descending order - timestamps = [block['timestamp'] for block in bl] - for t in xrange(1, len(timestamps)): - self.assertTrue(timestamps[t] <= timestamps[t-1]) - - b2 = list(mysite.blocks(limit=10, reverse=True)) - self.assertTrue(len(b2) <= 10) - for block in b2: - self.assertType(block, dict) - for prop in props: - self.assertTrue(prop in block) - # timestamps should be in ascending order - timestamps = [block['timestamp'] for block in b2] - for t in xrange(1, len(timestamps)): - self.assertTrue(timestamps[t] >= timestamps[t-1]) - - for block in mysite.blocks(starttime="2008-07-01T00:00:01Z", limit=5): - self.assertType(block, dict) - for prop in props: - self.assertTrue(prop in block) - for block in mysite.blocks(endtime="2008-07-31T23:59:59Z", limit=5): - self.assertType(block, dict) - for prop in props: - self.assertTrue(prop in block) - for block in mysite.blocks(starttime="2008-08-02T00:00:01Z", - endtime="2008-08-02T23:59:59Z", - reverse=True, limit=5): - self.assertType(block, dict) - for prop in props: - self.assertTrue(prop in block) - for block in mysite.blocks(starttime="2008-08-03T23:59:59Z", - endtime="2008-08-03T00:00:01Z", - limit=5): - self.assertType(block, dict) - for prop in props: - self.assertTrue(prop in block) - # starttime earlier than endtime - self.assertRaises(pywikibot.Error, mysite.blocks, - starttime="2008-08-03T00:00:01Z", - endtime="2008-08-03T23:59:59Z", limit=5) - # reverse: endtime earlier than starttime - self.assertRaises(pywikibot.Error, mysite.blocks, - starttime="2008-08-03T23:59:59Z", - endtime="2008-08-03T00:00:01Z", reverse=True, limit=5) - for block in mysite.blocks(users=mysite.user(), limit=5): - self.assertType(block, dict) - self.assertEqual(block['user'], mysite.user()) - - def testExturlusage(self): - """Test the site.exturlusage() method""" - - url = "www.google.com" - eu = list(mysite.exturlusage(url, limit=10)) - self.assertTrue(len(eu) <= 10) - self.assertTrue(all(isinstance(link, pywikibot.Page) - for link in eu)) - for link in mysite.exturlusage(url, namespaces=[2, 3], limit=5): - self.assertType(link, pywikibot.Page) - self.assertTrue(link.namespace() in (2, 3)) - - def testImageusage(self): - """Test the site.imageusage() method""" - - iu = list(mysite.imageusage(imagepage, limit=10)) - self.assertTrue(len(iu) <= 10) - self.assertTrue(all(isinstance(link, pywikibot.Page) - for link in iu)) - for using in mysite.imageusage(imagepage, namespaces=[3,4], limit=5): - self.assertType(using, pywikibot.Page) - self.assertTrue(imagepage in list(using.imagelinks())) - for using in mysite.imageusage(imagepage, filterredir=True, limit=5): - self.assertType(using, pywikibot.Page) - self.assertTrue(using.isRedirectPage()) - for using in mysite.imageusage(imagepage, filterredir=True, limit=5): - self.assertType(using, pywikibot.Page) - self.assertFalse(using.isRedirectPage()) - - def testLogEvents(self): - """Test the site.logevents() method""" - - le = list(mysite.logevents(limit=10)) - self.assertTrue(len(le) <= 10) - self.assertTrue(all(isinstance(entry, dict) and "type" in entry - for entry in le)) - for typ in ("block", "protect", "rights", "delete", "upload", - "move", "import", "patrol", "merge"): - for entry in mysite.logevents(logtype=typ, limit=3): - self.assertEqual(entry["type"], typ) - for entry in mysite.logevents(page=mainpage, limit=3): - self.assertTrue("title" in entry - and entry["title"] == mainpage.title()) - for entry in mysite.logevents(user=mysite.user(), limit=3): - self.assertTrue("user" in entry - and entry["user"] == mysite.user()) - for entry in mysite.logevents(start="2008-09-01T00:00:01Z", limit=5): - self.assertType(entry, dict) - self.assertTrue(entry['timestamp'] <= "2008-09-01T00:00:01Z") - for entry in mysite.logevents(end="2008-09-02T23:59:59Z", limit=5): - self.assertType(entry, dict) - self.assertTrue(entry['timestamp'] >= "2008-09-02T23:59:59Z") - for entry in mysite.logevents(start="2008-02-02T00:00:01Z", - end="2008-02-02T23:59:59Z", - reverse=True, limit=5): - self.assertType(entry, dict) - self.assertTrue("2008-02-02T00:00:01Z" <= entry['timestamp'] - <= "2008-02-02T23:59:59Z") - for entry in mysite.logevents(start="2008-02-03T23:59:59Z", - end="2008-02-03T00:00:01Z", - limit=5): - self.assertType(entry, dict) - self.assertTrue("2008-02-03T00:00:01Z" <= entry['timestamp'] - <= "2008-02-03T23:59:59Z") - # starttime earlier than endtime - self.assertRaises(pywikibot.Error, mysite.logevents, - start="2008-02-03T00:00:01Z", - end="2008-02-03T23:59:59Z", limit=5) - # reverse: endtime earlier than starttime - self.assertRaises(pywikibot.Error, mysite.logevents, - start="2008-02-03T23:59:59Z", - end="2008-02-03T00:00:01Z", reverse=True, limit=5) - - def testRecentchanges(self): - """Test the site.recentchanges() method""" - - rc = list(mysite.recentchanges(limit=10)) - self.assertTrue(len(rc) <= 10) - self.assertTrue(all(isinstance(change, dict) - for change in rc)) - for change in mysite.recentchanges(start="2008-10-01T01:02:03Z", - limit=5): - self.assertType(change, dict) - self.assertTrue(change['timestamp'] <= "2008-10-01T01:02:03Z") - for change in mysite.recentchanges(end="2008-04-01T02:03:04Z", - limit=5): - self.assertType(change, dict) - self.assertTrue(change['timestamp'] >= "2008-10-01T02:03:04Z") - for change in mysite.recentchanges(start="2008-10-01T03:05:07Z", - limit=5, reverse=True): - self.assertType(change, dict) - self.assertTrue(change['timestamp'] >= "2008-10-01T03:05:07Z") - for change in mysite.recentchanges(end="2008-10-01T04:06:08Z", - limit=5, reverse=True): - self.assertType(change, dict) - self.assertTrue(change['timestamp'] <= "2008-10-01T04:06:08Z") - for change in mysite.recentchanges(start="2008-10-03T11:59:59Z", - end="2008-10-03T00:00:01Z", - limit=5): - self.assertType(change, dict) - self.assertTrue("2008-10-03T00:00:01Z" <= change['timestamp'] - <= "2008-10-03T11:59:59Z") - for change in mysite.recentchanges(start="2008-10-05T06:00:01Z", - end="2008-10-05T23:59:59Z", - reverse=True, limit=5): - self.assertType(change, dict) - self.assertTrue("2008-10-05T06:00:01Z" <= change['timestamp'] - <= "2008-10-05T23:59:59Z") - # start earlier than end - self.assertRaises(pywikibot.Error, mysite.recentchanges, - start="2008-02-03T00:00:01Z", - end="2008-02-03T23:59:59Z", limit=5) - # reverse: end earlier than start - self.assertRaises(pywikibot.Error, mysite.recentchanges, - start="2008-02-03T23:59:59Z", - end="2008-02-03T00:00:01Z", reverse=True, limit=5) - for change in mysite.recentchanges(namespaces=[6,7], limit=5): - self.assertType(change, dict) - self.assertTrue("title" in change and "ns" in change) - title = change['title'] - self.assertTrue(":" in title) - prefix = title[ : title.index(":")] - self.assertTrue(mysite.ns_index(prefix) in [6,7]) - self.assertTrue(change["ns"] in [6,7]) - for change in mysite.recentchanges(pagelist=[mainpage, imagepage], - limit=5): - self.assertType(change, dict) - self.assertTrue("title" in change) - self.assertTrue(change["title"] in (mainpage.title(), - imagepage.title())) - for typ in ("edit", "new", "log"): - for change in mysite.recentchanges(changetype=typ, limit=5): - self.assertType(change, dict) - self.assertTrue("type" in change) - self.assertEqual(change["type"], typ) - for change in mysite.recentchanges(showMinor=True, limit=5): - self.assertType(change, dict) - self.assertTrue("minor" in change) - for change in mysite.recentchanges(showMinor=False, limit=5): - self.assertType(change, dict) - self.assertTrue("minor" not in change) - for change in mysite.recentchanges(showBot=True, limit=5): - self.assertType(change, dict) - self.assertTrue("bot" in change) - for change in mysite.recentchanges(showBot=False, limit=5): - self.assertType(change, dict) - self.assertTrue("bot" not in change) - for change in mysite.recentchanges(showAnon=True, limit=5): - self.assertType(change, dict) - for change in mysite.recentchanges(showAnon=False, limit=5): - self.assertType(change, dict) - for change in mysite.recentchanges(showRedirects=True, limit=5): - self.assertType(change, dict) - self.assertTrue("redirect" in change) - for change in mysite.recentchanges(showRedirects=False, limit=5): - self.assertType(change, dict) - self.assertTrue("redirect" not in change) - for change in mysite.recentchanges(showPatrolled=True, limit=5): - self.assertType(change, dict) - self.assertTrue("patrolled" in change) - for change in mysite.recentchanges(showPatrolled=False, limit=5): - self.assertType(change, dict) - self.assertTrue("patrolled" not in change) - - def testSearch(self): - """Test the site.search() method""" - - se = list(mysite.search("wiki", limit=10)) - self.assertTrue(len(se) <= 10) - self.assertTrue(all(isinstance(hit, pywikibot.Page) - for hit in se)) - self.assertTrue(all(hit.namespace() == 0 for hit in se)) - for hit in mysite.search("common", namespaces=4, limit=5): - self.assertType(hit, pywikibot.Page) - self.assertEqual(hit.namespace(), 4) - for hit in mysite.search("word", namespaces=[5,6,7], limit=5): - self.assertType(hit, pywikibot.Page) - self.assertTrue(hit.namespace() in [5,6,7]) - for hit in mysite.search("another", namespaces="8|9|10", limit=5): - self.assertType(hit, pywikibot.Page) - self.assertTrue(hit.namespace() in [8,9,10]) - for hit in mysite.search("wiki", namespaces=0, limit=10, - getredirects=True): - self.assertType(hit, pywikibot.Page) - self.assertEqual(hit.namespace(), 0) - - def testUsercontribs(self): - """Test the site.usercontribs() method""" - - uc = list(mysite.usercontribs(user=mysite.user(), limit=10)) - self.assertTrue(len(uc) <= 10) - self.assertTrue(all(isinstance(contrib, dict) - for contrib in uc)) - self.assertTrue(all("user" in contrib - and contrib["user"] == mysite.user() - for contrib in uc)) - for contrib in mysite.usercontribs(userprefix="John", limit=5): - self.assertType(contrib, dict) - for key in ("user", "title", "ns", "pageid", "revid"): - self.assertTrue(key in contrib) - self.assertTrue(contrib["user"].startswith("John")) - for contrib in mysite.usercontribs(userprefix="Jane", - start="2008-10-06T01:02:03Z", - limit=5): - self.assertTrue(contrib['timestamp'] <= "2008-10-06T01:02:03Z") - for contrib in mysite.usercontribs(userprefix="Jane", - end="2008-10-07T02:03:04Z", - limit=5): - self.assertTrue(contrib['timestamp'] >= "2008-10-07T02:03:04Z") - for contrib in mysite.usercontribs(userprefix="Brion", - start="2008-10-08T03:05:07Z", - limit=5, reverse=True): - self.assertTrue(contrib['timestamp'] >= "2008-10-08T03:05:07Z") - for contrib in mysite.usercontribs(userprefix="Brion", - end="2008-10-09T04:06:08Z", - limit=5, reverse=True): - self.assertTrue(contrib['timestamp'] <= "2008-10-09T04:06:08Z") - for contrib in mysite.usercontribs(userprefix="Tim", - start="2008-10-10T11:59:59Z", - end="2008-10-10T00:00:01Z", - limit=5): - self.assertTrue("2008-10-10T00:00:01Z" <= contrib['timestamp'] - <= "2008-10-10T11:59:59Z") - for contrib in mysite.usercontribs(userprefix="Tim", - start="2008-10-11T06:00:01Z", - end="2008-10-11T23:59:59Z", - reverse=True, limit=5): - self.assertTrue("2008-10-11T06:00:01Z" <= contrib['timestamp'] - <= "2008-10-11T23:59:59Z") - # start earlier than end - self.assertRaises(pywikibot.Error, mysite.usercontribs, - userprefix="Jim", - start="2008-10-03T00:00:01Z", - end="2008-10-03T23:59:59Z", limit=5) - # reverse: end earlier than start - self.assertRaises(pywikibot.Error, mysite.usercontribs, - userprefix="Jim", - start="2008-10-03T23:59:59Z", - end="2008-10-03T00:00:01Z", reverse=True, limit=5) - - for contrib in mysite.usercontribs(user=mysite.user(), - namespaces=14, limit=5): - self.assertType(contrib, dict) - self.assertTrue("title" in contrib) - self.assertTrue(contrib["title"].startswith(mysite.namespace(14))) - for contrib in mysite.usercontribs(user=mysite.user(), - namespaces=[10,11], limit=5): - self.assertType(contrib, dict) - self.assertTrue("title" in contrib) - self.assertTrue(contrib["ns"] in (10, 11)) - for contrib in mysite.usercontribs(user=mysite.user(), - showMinor=True, limit=5): - self.assertType(contrib, dict) - self.assertTrue("minor" in contrib) - for contrib in mysite.usercontribs(user=mysite.user(), - showMinor=False, limit=5): - self.assertType(contrib, dict) - self.assertTrue("minor" not in contrib) - - def testWatchlistrevs(self): - """Test the site.watchlist_revs() method""" - - wl = list(mysite.watchlist_revs(limit=10)) - self.assertTrue(len(wl) <= 10) - self.assertTrue(all(isinstance(rev, dict) - for rev in wl)) - for rev in mysite.watchlist_revs(start="2008-10-11T01:02:03Z", - limit=5): - self.assertType(rev, dict) - self.assertTrue(rev['timestamp'] <= "2008-10-11T01:02:03Z") - for rev in mysite.watchlist_revs(end="2008-04-01T02:03:04Z", - limit=5): - self.assertType(rev, dict) - self.assertTrue(rev['timestamp'] >= "2008-10-11T02:03:04Z") - for rev in mysite.watchlist_revs(start="2008-10-11T03:05:07Z", - limit=5, reverse=True): - self.assertType(rev, dict) - self.assertTrue(rev['timestamp'] >= "2008-10-11T03:05:07Z") - for rev in mysite.watchlist_revs(end="2008-10-11T04:06:08Z", - limit=5, reverse=True): - self.assertType(rev, dict) - self.assertTrue(rev['timestamp'] <= "2008-10-11T04:06:08Z") - for rev in mysite.watchlist_revs(start="2008-10-13T11:59:59Z", - end="2008-10-13T00:00:01Z", - limit=5): - self.assertType(rev, dict) - self.assertTrue("2008-10-13T00:00:01Z" <= rev['timestamp'] - <= "2008-10-13T11:59:59Z") - for rev in mysite.watchlist_revs(start="2008-10-15T06:00:01Z", - end="2008-10-15T23:59:59Z", - reverse=True, limit=5): - self.assertType(rev, dict) - self.assertTrue("2008-10-15T06:00:01Z" <= rev['timestamp'] - <= "2008-10-15T23:59:59Z") - # start earlier than end - self.assertRaises(pywikibot.Error, mysite.watchlist_revs, - start="2008-09-03T00:00:01Z", - end="2008-09-03T23:59:59Z", limit=5) - # reverse: end earlier than start - self.assertRaises(pywikibot.Error, mysite.watchlist_revs, - start="2008-09-03T23:59:59Z", - end="2008-09-03T00:00:01Z", reverse=True, limit=5) - for rev in mysite.watchlist_revs(namespaces=[6,7], limit=5): - self.assertType(rev, dict) - self.assertTrue("title" in rev and "ns" in rev) - title = rev['title'] - self.assertTrue(":" in title) - prefix = title[ : title.index(":")] - self.assertTrue(mysite.ns_index(prefix) in [6,7]) - self.assertTrue(rev["ns"] in [6,7]) - for rev in mysite.watchlist_revs(showMinor=True, limit=5): - self.assertType(rev, dict) - self.assertTrue("minor" in rev) - for rev in mysite.watchlist_revs(showMinor=False, limit=5): - self.assertType(rev, dict) - self.assertTrue("minor" not in rev) - for rev in mysite.watchlist_revs(showBot=True, limit=5): - self.assertType(rev, dict) - self.assertTrue("bot" in rev) - for rev in mysite.watchlist_revs(showBot=False, limit=5): - self.assertType(rev, dict) - self.assertTrue("bot" not in rev) - for rev in mysite.watchlist_revs(showAnon=True, limit=5): - self.assertType(rev, dict) - for rev in mysite.watchlist_revs(showAnon=False, limit=5): - self.assertType(rev, dict) - - def testDeletedrevs(self): - """Test the site.deletedrevs() method""" - - if not mysite.logged_in(True): - try: - mysite.login(True) - except pywikibot.NoUsername: - logger.warn( - "Cannot test Site.deleted_revs; no sysop account configured.") - return - dr = list(mysite.deletedrevs(limit=10, page=mainpage)) - self.assertTrue(len(dr) <= 10) - self.assertTrue(all(isinstance(rev, dict) - for rev in dr)) - dr2 = list(mysite.deletedrevs(page=mainpage, limit=10)) - self.assertTrue(len(dr2) <= 10) - self.assertTrue(all(isinstance(rev, dict) - for rev in dr2)) - for rev in mysite.deletedrevs(start="2008-10-11T01:02:03Z", - page=mainpage, limit=5): - self.assertType(rev, dict) - self.assertTrue(rev['timestamp'] <= "2008-10-11T01:02:03Z") - for rev in mysite.deletedrevs(end="2008-04-01T02:03:04Z", - page=mainpage, limit=5): - self.assertType(rev, dict) - self.assertTrue(rev['timestamp'] >= "2008-10-11T02:03:04Z") - for rev in mysite.deletedrevs(start="2008-10-11T03:05:07Z", - page=mainpage, limit=5, - reverse=True): - self.assertType(rev, dict) - self.assertTrue(rev['timestamp'] >= "2008-10-11T03:05:07Z") - for rev in mysite.deletedrevs(end="2008-10-11T04:06:08Z", - page=mainpage, limit=5, - reverse=True): - self.assertType(rev, dict) - self.assertTrue(rev['timestamp'] <= "2008-10-11T04:06:08Z") - for rev in mysite.deletedrevs(start="2008-10-13T11:59:59Z", - end="2008-10-13T00:00:01Z", - page=mainpage, limit=5): - self.assertType(rev, dict) - self.assertTrue("2008-10-13T00:00:01Z" <= rev['timestamp'] - <= "2008-10-13T11:59:59Z") - for rev in mysite.deletedrevs(start="2008-10-15T06:00:01Z", - end="2008-10-15T23:59:59Z", - page=mainpage, reverse=True, - limit=5): - self.assertType(rev, dict) - self.assertTrue("2008-10-15T06:00:01Z" <= rev['timestamp'] - <= "2008-10-15T23:59:59Z") - # start earlier than end - self.assertRaises(pywikibot.Error, mysite.deletedrevs, - page=mainpage, start="2008-09-03T00:00:01Z", - end="2008-09-03T23:59:59Z", limit=5) - # reverse: end earlier than start - self.assertRaises(pywikibot.Error, mysite.deletedrevs, - page=mainpage, start="2008-09-03T23:59:59Z", - end="2008-09-03T00:00:01Z", reverse=True, - limit=5) - - def testUsers(self): - """Test the site.users() method""" - - us = list(mysite.users(mysite.user())) - self.assertEqual(len(us), 1) - self.assertType(us[0], dict) - for user in mysite.users( - ["Jimbo Wales", "Brion VIBBER", "Tim Starling"]): - self.assertType(user, dict) - self.assertTrue(user["name"] - in ["Jimbo Wales", "Brion VIBBER", "Tim Starling"]) - - def testRandompages(self): - """Test the site.randompages() method""" - - rn = list(mysite.randompages(limit=10)) - self.assertTrue(len(rn) <= 10) - self.assertTrue(all(isinstance(a_page, pywikibot.Page) - for a_page in rn)) - self.assertFalse(all(a_page.isRedirectPage() for a_page in rn)) - for rndpage in mysite.randompages(limit=5, redirects=True): - self.assertType(rndpage, pywikibot.Page) - self.assertTrue(rndpage.isRedirectPage()) - for rndpage in mysite.randompages(limit=5, namespaces=[6, 7]): - self.assertType(rndpage, pywikibot.Page) - self.assertTrue(rndpage.namespace() in [6, 7]) - - -if __name__ == '__main__': -# pywikibot.logging.getLogger("").setLevel(pywikibot.logging.DEBUG) - try: - try: - unittest.main() - except SystemExit: - pass - finally: - pywikibot.stopme() +# -*- coding: utf-8 -*- +""" +Tests for the site module. +""" +# +# (C) Pywikipedia bot team, 2008 +# +# Distributed under the terms of the MIT license. +# +__version__ = '$Id: $' + + +import unittest +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 + + +class TestSiteObject(unittest.TestCase): + """Test cases for Site methods.""" + + def assertType(self, obj, cls): + """Assert that obj is an instance of type cls""" + return self.assertTrue(isinstance(obj, cls)) + + def testBaseMethods(self): + """Test cases for BaseSite methods""" + + self.assertEqual(mysite.family.name, pywikibot.config2.family) + self.assertEqual(mysite.code, pywikibot.config2.mylang) + self.assertType(mysite.lang, basestring) + self.assertType(mysite == pywikibot.Site("en", "wikipedia"), bool) + self.assertType(mysite.user(), (basestring, type(None))) + self.assertEqual(mysite.sitename(), + "%s:%s" % (pywikibot.config2.family, + pywikibot.config2.mylang)) + self.assertEqual(repr(mysite), + 'Site("%s", "%s")' + % (pywikibot.config2.mylang, pywikibot.config2.family)) + self.assertType(mysite.linktrail(), basestring) + self.assertType(mysite.redirect(default=True), basestring) + self.assertType(mysite.disambcategory(), pywikibot.Category) + self.assertEqual(mysite.linkto("foo"), u"[[Foo]]") + self.assertFalse(mysite.isInterwikiLink("foo")) + self.assertType(mysite.redirectRegex().pattern, basestring) + self.assertType(mysite.category_on_one_line(), bool) + for grp in ("user", "autoconfirmed", "bot", "sysop", "nosuchgroup"): + self.assertType(mysite.has_group(grp), bool) + for rgt in ("read", "edit", "move", "delete", "rollback", "block", + "nosuchright"): + self.assertType(mysite.has_right(rgt), bool) + + def testLanguageMethods(self): + """Test cases for languages() and related methods""" + + langs = mysite.languages() + self.assertType(langs, list) + self.assertTrue(mysite.code in langs) + obs = mysite.family.obsolete + ipf = mysite.interwiki_putfirst() + self.assertType(ipf, list) + self.assertTrue(all(item in langs or item in obs + for item in ipf)) + self.assertTrue(all(item in langs + for item in mysite.validLanguageLinks())) + + def testNamespaceMethods(self): + """Test cases for methods manipulating namespace names""" + + builtins = {'Talk': 1, # these should work in any MW wiki + 'User': 2, + 'User talk': 3, + 'Project': 4, + 'Project talk': 5, + 'Image': 6, + 'Image talk': 7, + 'MediaWiki': 8, + 'MediaWiki talk': 9, + 'Template': 10, + 'Template talk': 11, + 'Help': 12, + 'Help talk': 13, + 'Category': 14, + 'Category talk': 15, + } + self.assertTrue(all(mysite.ns_index(b) == builtins[b] + for b in builtins)) + ns = mysite.namespaces() + self.assertType(ns, dict) + self.assertTrue(all(x in ns for x in xrange(0, 16))) + # built-in namespaces always present + self.assertType(mysite.ns_normalize("project"), basestring) + self.assertTrue(all(isinstance(key, int) + for key in ns)) + self.assertTrue(all(isinstance(val, list) + for val in ns.values())) + self.assertTrue(all(isinstance(name, basestring) + for val in ns.values() + for name in val)) + self.assertTrue(all(isinstance(mysite.namespace(key), basestring) + for key in ns)) + self.assertTrue(all(isinstance(mysite.namespace(key, True), list) + for key in ns)) + self.assertTrue(all(isinstance(item, basestring) + for key in ns + for item in mysite.namespace(key, True))) + + 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) + self.assertType(mysite.is_blocked(), bool) + self.assertType(mysite.messages(), bool) + self.assertType(mysite.has_right("edit"), bool) + self.assertFalse(mysite.has_right("nonexistent_right")) + self.assertType(mysite.has_group("bots"), bool) + self.assertFalse(mysite.has_group("nonexistent_group")) + try: + self.assertType(mysite.is_blocked(True), bool) + self.assertType(mysite.has_right("edit", True), bool) + self.assertFalse(mysite.has_right("nonexistent_right", True)) + self.assertType(mysite.has_group("bots", True), bool) + self.assertFalse(mysite.has_group("nonexistent_group", True)) + except pywikibot.NoUsername: + logger.warn( + "Cannot test Site methods for sysop; no sysop account configured.") + for msg in ("1movedto2", "about", "aboutpage", "aboutsite", + "accesskey-n-portal"): + self.assertTrue(mysite.has_mediawiki_message(msg)) + self.assertType(mysite.mediawiki_message(msg), basestring) + self.assertFalse(mysite.has_mediawiki_message("nosuchmessage")) + self.assertRaises(KeyError, mysite.mediawiki_message, "nosuchmessage") + self.assertType(mysite.getcurrenttimestamp(), basestring) + self.assertType(mysite.siteinfo, dict) + self.assertType(mysite.case(), basestring) + ver = mysite.live_version() + self.assertType(ver, tuple) + self.assertTrue(all(isinstance(ver[i], int) for i in (0, 1))) + self.assertType(ver[2], basestring) + + 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) + self.assertType(mysite.page_isredirect(mainpage), bool) + if mysite.page_isredirect(mainpage): + self.assertType(mysite.getredirtarget(mainpage), pywikibot.Page) + else: + self.assertRaises(pywikibot.IsNotRedirectPage, + mysite.getredirtarget, mainpage) + a = list(mysite.preloadpages([mainpage])) + self.assertEqual(len(a), int(mysite.page_exists(mainpage))) + if a: + self.assertEqual(a[0], mainpage) + + 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") + + def testPreload(self): + """Test that preloading works""" + + count = 0 + for page in mysite.preloadpages(mysite.pagelinks(mainpage, limit=10)): + self.assertType(page, pywikibot.Page) + self.assertType(page.exists(), bool) + if page.exists(): + self.assertTrue(hasattr(page, "_text")) + count += 1 + if count >= 5: + break + + 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, + filterRedirects=False)) + # only redirects: + redirs = set(mysite.pagebacklinks(mainpage, namespaces=0, + filterRedirects=True)) + # including links to redirect pages (but not the redirects): + indirect = set(mysite.pagebacklinks(mainpage, namespaces=[0], + followRedirects=True)) + self.assertEqual(filtered & redirs, set([])) + self.assertEqual(indirect & redirs, set([])) + self.assertTrue(filtered.issubset(indirect)) + self.assertTrue(filtered.issubset(backlinks)) + self.assertTrue(redirs.issubset(backlinks)) + self.assertTrue(backlinks.issubset( + set(mysite.pagebacklinks(mainpage, namespaces=[0, 2])))) + + # pagereferences includes both backlinks and embeddedin + embedded = set(mysite.page_embeddedin(mainpage, namespaces=[0])) + refs = set(mysite.pagereferences(mainpage, namespaces=[0])) + self.assertTrue(backlinks.issubset(refs)) + self.assertTrue(embedded.issubset(refs)) + for bl in backlinks: + self.assertType(bl, pywikibot.Page) + self.assertTrue(bl in refs) + for ei in embedded: + self.assertType(ei, pywikibot.Page) + self.assertTrue(ei in refs) + for ref in refs: + self.assertTrue(ref in backlinks or ref in embedded) + # test embeddedin arguments + self.assertTrue(embedded.issuperset( + set(mysite.page_embeddedin(mainpage, filterRedirects=True, + namespaces=[0])))) + self.assertTrue(embedded.issuperset( + set(mysite.page_embeddedin(mainpage, filterRedirects=False, + namespaces=[0])))) + self.assertTrue(embedded.issubset( + set(mysite.page_embeddedin(mainpage, namespaces=[0, 2])))) + links = set(mysite.pagelinks(mainpage)) + for pl in links: + self.assertType(pl, pywikibot.Page) + # test links arguments + self.assertTrue(links.issuperset( + set(mysite.pagelinks(mainpage, namespaces=[0, 1])))) + for target in mysite.preloadpages( + mysite.pagelinks(mainpage, follow_redirects=True, + limit=5)): + self.assertType(target, pywikibot.Page) + self.assertFalse(target.isRedirectPage()) + # test pagecategories + for cat in mysite.pagecategories(mainpage): + self.assertType(cat, pywikibot.Category) + for cm in mysite.categorymembers(cat): + self.assertType(cat, pywikibot.Page) + # test pageimages + self.assertTrue(all(isinstance(im, pywikibot.ImagePage) + for im in mysite.pageimages(mainpage))) + # test pagetemplates + self.assertTrue(all(isinstance(te, pywikibot.Page) + for te in mysite.pagetemplates(mainpage))) + self.assertTrue(set(mysite.pagetemplates(mainpage)).issuperset( + set(mysite.pagetemplates(mainpage, namespaces=[10])))) + # test pagelanglinks + for ll in mysite.pagelanglinks(mainpage): + self.assertType(ll, pywikibot.Link) + # test page_extlinks + self.assertTrue(all(isinstance(el, basestring) + for el in mysite.page_extlinks(mainpage))) + + def testLoadRevisions(self): + """Test the site.loadrevisions() method""" + + mysite.loadrevisions(mainpage) + self.assertTrue(hasattr(mainpage, "_revid")) + self.assertTrue(hasattr(mainpage, "_revisions")) + self.assertTrue(mainpage._revid in mainpage._revisions) + # TODO test all the optional arguments + + def testAllPages(self): + """Test the site.allpages() method""" + + fwd = list(mysite.allpages(limit=10)) + self.assertTrue(len(fwd) <= 10) + for page in fwd: + self.assertType(page, pywikibot.Page) + self.assertTrue(mysite.page_exists(page)) + self.assertEqual(page.namespace(), 0) + rev = list(mysite.allpages(reverse=True, start="Aa", limit=12)) + self.assertTrue(len(rev) <= 12) + for page in rev: + self.assertType(page, pywikibot.Page) + self.assertTrue(mysite.page_exists(page)) + self.assertEqual(page.namespace(), 0) + self.assertTrue(page.title() <= "Aa") + for page in mysite.allpages(start="Py", limit=5): + self.assertType(page, pywikibot.Page) + self.assertTrue(mysite.page_exists(page)) + self.assertEqual(page.namespace(), 0) + self.assertTrue(page.title() >= "Py") + for page in mysite.allpages(prefix="Pre", limit=5): + self.assertType(page, pywikibot.Page) + self.assertTrue(mysite.page_exists(page)) + self.assertEqual(page.namespace(), 0) + self.assertTrue(page.title().startswith("Pre")) + for page in mysite.allpages(namespace=1, limit=5): + self.assertType(page, pywikibot.Page) + self.assertTrue(mysite.page_exists(page)) + self.assertEqual(page.namespace(), 1) + for page in mysite.allpages(filterredir=True, limit=5): + self.assertType(page, pywikibot.Page) + self.assertTrue(mysite.page_exists(page)) + self.assertEqual(page.namespace(), 0) + self.assertTrue(page.isRedirectPage()) + for page in mysite.allpages(filterredir=False, limit=5): + self.assertType(page, pywikibot.Page) + self.assertTrue(mysite.page_exists(page)) + self.assertEqual(page.namespace(), 0) + self.assertFalse(page.isRedirectPage()) +## for page in mysite.allpages(filterlanglinks=True, limit=5): +## self.assertType(page, pywikibot.Page) +## self.assertTrue(mysite.page_exists(page)) +## self.assertEqual(page.namespace(), 0) +## for page in mysite.allpages(filterlanglinks=False, limit=5): +## self.assertType(page, pywikibot.Page) +## self.assertTrue(mysite.page_exists(page)) +## self.assertEqual(page.namespace(), 0) + for page in mysite.allpages(minsize=100, limit=5): + self.assertType(page, pywikibot.Page) + self.assertTrue(mysite.page_exists(page)) + self.assertTrue(len(page.text) >= 100) + for page in mysite.allpages(maxsize=200, limit=5): + self.assertType(page, pywikibot.Page) + self.assertTrue(mysite.page_exists(page)) + self.assertTrue(len(page.text) <= 200) + for page in mysite.allpages(protect_type="edit", limit=5): + self.assertType(page, pywikibot.Page) + self.assertTrue(mysite.page_exists(page)) + self.assertTrue("edit" in page._protection) + for page in mysite.allpages(protect_type="edit", + protect_level="sysop", limit=5): + self.assertType(page, pywikibot.Page) + self.assertTrue(mysite.page_exists(page)) + self.assertTrue("edit" in page._protection) + self.assertTrue("sysop" in page._protection["edit"]) + + def testAllLinks(self): + """Test the site.alllinks() method""" + + fwd = list(mysite.alllinks(limit=10)) + self.assertTrue(len(fwd) <= 10) + self.assertTrue(all(isinstance(link, pywikibot.Page) for link in fwd)) + uniq = list(mysite.alllinks(limit=10, unique=True)) + self.assertTrue(all(link in uniq for link in fwd)) + for page in mysite.alllinks(start="Link", limit=5): + self.assertType(page, pywikibot.Page) + self.assertEqual(page.namespace(), 0) + self.assertTrue(page.title() >= "Link") + for page in mysite.alllinks(prefix="Fix", limit=5): + self.assertType(page, pywikibot.Page) + self.assertEqual(page.namespace(), 0) + self.assertTrue(page.title().startswith("Fix")) + for page in mysite.alllinks(namespace=1, limit=5): + self.assertType(page, pywikibot.Page) + self.assertEqual(page.namespace(), 1) + for page in mysite.alllinks(start="From", namespace=4, fromids=True, + limit=5): + self.assertType(page, pywikibot.Page) + self.assertTrue(page.title(withNamespace=False) >= "From") + self.assertTrue(hasattr(page, "_fromid")) + errgen = mysite.alllinks(unique=True, fromids=True) + self.assertRaises(pywikibot.Error, errgen.next) + + def testAllCategories(self): + """Test the site.allcategories() method""" + + ac = list(mysite.allcategories(limit=10)) + self.assertTrue(len(ac) <= 10) + self.assertTrue(all(isinstance(cat, pywikibot.Category) + for cat in ac)) + for cat in mysite.allcategories(limit=5, start="Abc"): + self.assertType(cat, pywikibot.Category) + self.assertTrue(cat.title(withNamespace=False) >= "Abc") + for cat in mysite.allcategories(limit=5, prefix="Def"): + self.assertType(cat, pywikibot.Category) + self.assertTrue(cat.title(withNamespace=False).startswith("Def")) +## # Bug # 15985 +## for cat in mysite.allcategories(limit=5, start="Hij", reverse=True): +## self.assertType(cat, pywikibot.Category) +## self.assertTrue(cat.title(withNamespace=False) <= "Hij") + + def testAllUsers(self): + """Test the site.allusers() method""" + + au = list(mysite.allusers(limit=10)) + self.assertTrue(len(au) <= 10) + for user in au: + self.assertType(user, dict) + self.assertTrue("name" in user) + self.assertTrue("editcount" in user) + self.assertTrue("registration" in user) + for user in mysite.allusers(start="B", limit=5): + self.assertType(user, dict) + self.assertTrue("name" in user) + self.assertTrue(user["name"] >= "B") + self.assertTrue("editcount" in user) + self.assertTrue("registration" in user) + for user in mysite.allusers(prefix="C", limit=5): + self.assertType(user, dict) + self.assertTrue("name" in user) + self.assertTrue(user["name"].startswith("C")) + self.assertTrue("editcount" in user) + self.assertTrue("registration" in user) + for user in mysite.allusers(prefix="D", group="sysop", limit=5): + self.assertType(user, dict) + self.assertTrue("name" in user) + self.assertTrue(user["name"].startswith("D")) + self.assertTrue("editcount" in user) + self.assertTrue("registration" in user) + self.assertTrue("groups" in user and "sysop" in user["groups"]) + + def testAllImages(self): + """Test the site.allimages() method""" + + ai = list(mysite.allimages(limit=10)) + self.assertTrue(len(ai) <= 10) + self.assertTrue(all(isinstance(image, pywikibot.ImagePage) + for image in ai)) + for impage in mysite.allimages(start="Ba", limit=5): + self.assertType(impage, pywikibot.ImagePage) + self.assertTrue(mysite.page_exists(impage)) + self.assertTrue(impage.title(withNamespace=False) >= "Ba") +## # Bug # 15985 +## for impage in mysite.allimages(start="Da", reverse=True, limit=5): +## self.assertType(impage, pywikibot.ImagePage) +## self.assertTrue(mysite.page_exists(impage)) +## self.assertTrue(impage.title() <= "Da") + for impage in mysite.allimages(prefix="Ch", limit=5): + self.assertType(impage, pywikibot.ImagePage) + self.assertTrue(mysite.page_exists(impage)) + self.assertTrue(impage.title(withNamespace=False).startswith("Ch")) + for impage in mysite.allimages(minsize=100, limit=5): + self.assertType(impage, pywikibot.ImagePage) + self.assertTrue(mysite.page_exists(impage)) + self.assertTrue(impage._imageinfo["size"] >= 100) + for impage in mysite.allimages(maxsize=2000, limit=5): + self.assertType(impage, pywikibot.ImagePage) + self.assertTrue(mysite.page_exists(impage)) + self.assertTrue(impage._imageinfo["size"] <= 2000) + + def testBlocks(self): + """Test the site.blocks() method""" + + props = ("id", "by", "timestamp", "expiry", "reason") + bl = list(mysite.blocks(limit=10)) + self.assertTrue(len(bl) <= 10) + for block in bl: + self.assertType(block, dict) + for prop in props: + self.assertTrue(prop in block) + # timestamps should be in descending order + timestamps = [block['timestamp'] for block in bl] + for t in xrange(1, len(timestamps)): + self.assertTrue(timestamps[t] <= timestamps[t-1]) + + b2 = list(mysite.blocks(limit=10, reverse=True)) + self.assertTrue(len(b2) <= 10) + for block in b2: + self.assertType(block, dict) + for prop in props: + self.assertTrue(prop in block) + # timestamps should be in ascending order + timestamps = [block['timestamp'] for block in b2] + for t in xrange(1, len(timestamps)): + self.assertTrue(timestamps[t] >= timestamps[t-1]) + + for block in mysite.blocks(starttime="2008-07-01T00:00:01Z", limit=5): + self.assertType(block, dict) + for prop in props: + self.assertTrue(prop in block) + for block in mysite.blocks(endtime="2008-07-31T23:59:59Z", limit=5): + self.assertType(block, dict) + for prop in props: + self.assertTrue(prop in block) + for block in mysite.blocks(starttime="2008-08-02T00:00:01Z", + endtime="2008-08-02T23:59:59Z", + reverse=True, limit=5): + self.assertType(block, dict) + for prop in props: + self.assertTrue(prop in block) + for block in mysite.blocks(starttime="2008-08-03T23:59:59Z", + endtime="2008-08-03T00:00:01Z", + limit=5): + self.assertType(block, dict) + for prop in props: + self.assertTrue(prop in block) + # starttime earlier than endtime + self.assertRaises(pywikibot.Error, mysite.blocks, + starttime="2008-08-03T00:00:01Z", + endtime="2008-08-03T23:59:59Z", limit=5) + # reverse: endtime earlier than starttime + self.assertRaises(pywikibot.Error, mysite.blocks, + starttime="2008-08-03T23:59:59Z", + endtime="2008-08-03T00:00:01Z", reverse=True, limit=5) + for block in mysite.blocks(users=mysite.user(), limit=5): + self.assertType(block, dict) + self.assertEqual(block['user'], mysite.user()) + + def testExturlusage(self): + """Test the site.exturlusage() method""" + + url = "www.google.com" + eu = list(mysite.exturlusage(url, limit=10)) + self.assertTrue(len(eu) <= 10) + self.assertTrue(all(isinstance(link, pywikibot.Page) + for link in eu)) + for link in mysite.exturlusage(url, namespaces=[2, 3], limit=5): + self.assertType(link, pywikibot.Page) + self.assertTrue(link.namespace() in (2, 3)) + + def testImageusage(self): + """Test the site.imageusage() method""" + + iu = list(mysite.imageusage(imagepage, limit=10)) + self.assertTrue(len(iu) <= 10) + self.assertTrue(all(isinstance(link, pywikibot.Page) + for link in iu)) + for using in mysite.imageusage(imagepage, namespaces=[3,4], limit=5): + self.assertType(using, pywikibot.Page) + self.assertTrue(imagepage in list(using.imagelinks())) + for using in mysite.imageusage(imagepage, filterredir=True, limit=5): + self.assertType(using, pywikibot.Page) + self.assertTrue(using.isRedirectPage()) + for using in mysite.imageusage(imagepage, filterredir=True, limit=5): + self.assertType(using, pywikibot.Page) + self.assertFalse(using.isRedirectPage()) + + def testLogEvents(self): + """Test the site.logevents() method""" + + le = list(mysite.logevents(limit=10)) + self.assertTrue(len(le) <= 10) + self.assertTrue(all(isinstance(entry, dict) and "type" in entry + for entry in le)) + for typ in ("block", "protect", "rights", "delete", "upload", + "move", "import", "patrol", "merge"): + for entry in mysite.logevents(logtype=typ, limit=3): + self.assertEqual(entry["type"], typ) + for entry in mysite.logevents(page=mainpage, limit=3): + self.assertTrue("title" in entry + and entry["title"] == mainpage.title()) + for entry in mysite.logevents(user=mysite.user(), limit=3): + self.assertTrue("user" in entry + and entry["user"] == mysite.user()) + for entry in mysite.logevents(start="2008-09-01T00:00:01Z", limit=5): + self.assertType(entry, dict) + self.assertTrue(entry['timestamp'] <= "2008-09-01T00:00:01Z") + for entry in mysite.logevents(end="2008-09-02T23:59:59Z", limit=5): + self.assertType(entry, dict) + self.assertTrue(entry['timestamp'] >= "2008-09-02T23:59:59Z") + for entry in mysite.logevents(start="2008-02-02T00:00:01Z", + end="2008-02-02T23:59:59Z", + reverse=True, limit=5): + self.assertType(entry, dict) + self.assertTrue("2008-02-02T00:00:01Z" <= entry['timestamp'] + <= "2008-02-02T23:59:59Z") + for entry in mysite.logevents(start="2008-02-03T23:59:59Z", + end="2008-02-03T00:00:01Z", + limit=5): + self.assertType(entry, dict) + self.assertTrue("2008-02-03T00:00:01Z" <= entry['timestamp'] + <= "2008-02-03T23:59:59Z") + # starttime earlier than endtime + self.assertRaises(pywikibot.Error, mysite.logevents, + start="2008-02-03T00:00:01Z", + end="2008-02-03T23:59:59Z", limit=5) + # reverse: endtime earlier than starttime + self.assertRaises(pywikibot.Error, mysite.logevents, + start="2008-02-03T23:59:59Z", + end="2008-02-03T00:00:01Z", reverse=True, limit=5) + + def testRecentchanges(self): + """Test the site.recentchanges() method""" + + rc = list(mysite.recentchanges(limit=10)) + self.assertTrue(len(rc) <= 10) + self.assertTrue(all(isinstance(change, dict) + for change in rc)) + for change in mysite.recentchanges(start="2008-10-01T01:02:03Z", + limit=5): + self.assertType(change, dict) + self.assertTrue(change['timestamp'] <= "2008-10-01T01:02:03Z") + for change in mysite.recentchanges(end="2008-04-01T02:03:04Z", + limit=5): + self.assertType(change, dict) + self.assertTrue(change['timestamp'] >= "2008-10-01T02:03:04Z") + for change in mysite.recentchanges(start="2008-10-01T03:05:07Z", + limit=5, reverse=True): + self.assertType(change, dict) + self.assertTrue(change['timestamp'] >= "2008-10-01T03:05:07Z") + for change in mysite.recentchanges(end="2008-10-01T04:06:08Z", + limit=5, reverse=True): + self.assertType(change, dict) + self.assertTrue(change['timestamp'] <= "2008-10-01T04:06:08Z") + for change in mysite.recentchanges(start="2008-10-03T11:59:59Z", + end="2008-10-03T00:00:01Z", + limit=5): + self.assertType(change, dict) + self.assertTrue("2008-10-03T00:00:01Z" <= change['timestamp'] + <= "2008-10-03T11:59:59Z") + for change in mysite.recentchanges(start="2008-10-05T06:00:01Z", + end="2008-10-05T23:59:59Z", + reverse=True, limit=5): + self.assertType(change, dict) + self.assertTrue("2008-10-05T06:00:01Z" <= change['timestamp'] + <= "2008-10-05T23:59:59Z") + # start earlier than end + self.assertRaises(pywikibot.Error, mysite.recentchanges, + start="2008-02-03T00:00:01Z", + end="2008-02-03T23:59:59Z", limit=5) + # reverse: end earlier than start + self.assertRaises(pywikibot.Error, mysite.recentchanges, + start="2008-02-03T23:59:59Z", + end="2008-02-03T00:00:01Z", reverse=True, limit=5) + for change in mysite.recentchanges(namespaces=[6,7], limit=5): + self.assertType(change, dict) + self.assertTrue("title" in change and "ns" in change) + title = change['title'] + self.assertTrue(":" in title) + prefix = title[ : title.index(":")] + self.assertTrue(mysite.ns_index(prefix) in [6,7]) + self.assertTrue(change["ns"] in [6,7]) + for change in mysite.recentchanges(pagelist=[mainpage, imagepage], + limit=5): + self.assertType(change, dict) + self.assertTrue("title" in change) + self.assertTrue(change["title"] in (mainpage.title(), + imagepage.title())) + for typ in ("edit", "new", "log"): + for change in mysite.recentchanges(changetype=typ, limit=5): + self.assertType(change, dict) + self.assertTrue("type" in change) + self.assertEqual(change["type"], typ) + for change in mysite.recentchanges(showMinor=True, limit=5): + self.assertType(change, dict) + self.assertTrue("minor" in change) + for change in mysite.recentchanges(showMinor=False, limit=5): + self.assertType(change, dict) + self.assertTrue("minor" not in change) + for change in mysite.recentchanges(showBot=True, limit=5): + self.assertType(change, dict) + self.assertTrue("bot" in change) + for change in mysite.recentchanges(showBot=False, limit=5): + self.assertType(change, dict) + self.assertTrue("bot" not in change) + for change in mysite.recentchanges(showAnon=True, limit=5): + self.assertType(change, dict) + for change in mysite.recentchanges(showAnon=False, limit=5): + self.assertType(change, dict) + for change in mysite.recentchanges(showRedirects=True, limit=5): + self.assertType(change, dict) + self.assertTrue("redirect" in change) + for change in mysite.recentchanges(showRedirects=False, limit=5): + self.assertType(change, dict) + self.assertTrue("redirect" not in change) + for change in mysite.recentchanges(showPatrolled=True, limit=5): + self.assertType(change, dict) + self.assertTrue("patrolled" in change) + for change in mysite.recentchanges(showPatrolled=False, limit=5): + self.assertType(change, dict) + self.assertTrue("patrolled" not in change) + + def testSearch(self): + """Test the site.search() method""" + + se = list(mysite.search("wiki", limit=10)) + self.assertTrue(len(se) <= 10) + self.assertTrue(all(isinstance(hit, pywikibot.Page) + for hit in se)) + self.assertTrue(all(hit.namespace() == 0 for hit in se)) + for hit in mysite.search("common", namespaces=4, limit=5): + self.assertType(hit, pywikibot.Page) + self.assertEqual(hit.namespace(), 4) + for hit in mysite.search("word", namespaces=[5,6,7], limit=5): + self.assertType(hit, pywikibot.Page) + self.assertTrue(hit.namespace() in [5,6,7]) + for hit in mysite.search("another", namespaces="8|9|10", limit=5): + self.assertType(hit, pywikibot.Page) + self.assertTrue(hit.namespace() in [8,9,10]) + for hit in mysite.search("wiki", namespaces=0, limit=10, + getredirects=True): + self.assertType(hit, pywikibot.Page) + self.assertEqual(hit.namespace(), 0) + + def testUsercontribs(self): + """Test the site.usercontribs() method""" + + uc = list(mysite.usercontribs(user=mysite.user(), limit=10)) + self.assertTrue(len(uc) <= 10) + self.assertTrue(all(isinstance(contrib, dict) + for contrib in uc)) + self.assertTrue(all("user" in contrib + and contrib["user"] == mysite.user() + for contrib in uc)) + for contrib in mysite.usercontribs(userprefix="John", limit=5): + self.assertType(contrib, dict) + for key in ("user", "title", "ns", "pageid", "revid"): + self.assertTrue(key in contrib) + self.assertTrue(contrib["user"].startswith("John")) + for contrib in mysite.usercontribs(userprefix="Jane", + start="2008-10-06T01:02:03Z", + limit=5): + self.assertTrue(contrib['timestamp'] <= "2008-10-06T01:02:03Z") + for contrib in mysite.usercontribs(userprefix="Jane", + end="2008-10-07T02:03:04Z", + limit=5): + self.assertTrue(contrib['timestamp'] >= "2008-10-07T02:03:04Z") + for contrib in mysite.usercontribs(userprefix="Brion", + start="2008-10-08T03:05:07Z", + limit=5, reverse=True): + self.assertTrue(contrib['timestamp'] >= "2008-10-08T03:05:07Z") + for contrib in mysite.usercontribs(userprefix="Brion", + end="2008-10-09T04:06:08Z", + limit=5, reverse=True): + self.assertTrue(contrib['timestamp'] <= "2008-10-09T04:06:08Z") + for contrib in mysite.usercontribs(userprefix="Tim", + start="2008-10-10T11:59:59Z", + end="2008-10-10T00:00:01Z", + limit=5): + self.assertTrue("2008-10-10T00:00:01Z" <= contrib['timestamp'] + <= "2008-10-10T11:59:59Z") + for contrib in mysite.usercontribs(userprefix="Tim", + start="2008-10-11T06:00:01Z", + end="2008-10-11T23:59:59Z", + reverse=True, limit=5): + self.assertTrue("2008-10-11T06:00:01Z" <= contrib['timestamp'] + <= "2008-10-11T23:59:59Z") + # start earlier than end + self.assertRaises(pywikibot.Error, mysite.usercontribs, + userprefix="Jim", + start="2008-10-03T00:00:01Z", + end="2008-10-03T23:59:59Z", limit=5) + # reverse: end earlier than start + self.assertRaises(pywikibot.Error, mysite.usercontribs, + userprefix="Jim", + start="2008-10-03T23:59:59Z", + end="2008-10-03T00:00:01Z", reverse=True, limit=5) + + for contrib in mysite.usercontribs(user=mysite.user(), + namespaces=14, limit=5): + self.assertType(contrib, dict) + self.assertTrue("title" in contrib) + self.assertTrue(contrib["title"].startswith(mysite.namespace(14))) + for contrib in mysite.usercontribs(user=mysite.user(), + namespaces=[10,11], limit=5): + self.assertType(contrib, dict) + self.assertTrue("title" in contrib) + self.assertTrue(contrib["ns"] in (10, 11)) + for contrib in mysite.usercontribs(user=mysite.user(), + showMinor=True, limit=5): + self.assertType(contrib, dict) + self.assertTrue("minor" in contrib) + for contrib in mysite.usercontribs(user=mysite.user(), + showMinor=False, limit=5): + self.assertType(contrib, dict) + self.assertTrue("minor" not in contrib) + + def testWatchlistrevs(self): + """Test the site.watchlist_revs() method""" + + wl = list(mysite.watchlist_revs(limit=10)) + self.assertTrue(len(wl) <= 10) + self.assertTrue(all(isinstance(rev, dict) + for rev in wl)) + for rev in mysite.watchlist_revs(start="2008-10-11T01:02:03Z", + limit=5): + self.assertType(rev, dict) + self.assertTrue(rev['timestamp'] <= "2008-10-11T01:02:03Z") + for rev in mysite.watchlist_revs(end="2008-04-01T02:03:04Z", + limit=5): + self.assertType(rev, dict) + self.assertTrue(rev['timestamp'] >= "2008-10-11T02:03:04Z") + for rev in mysite.watchlist_revs(start="2008-10-11T03:05:07Z", + limit=5, reverse=True): + self.assertType(rev, dict) + self.assertTrue(rev['timestamp'] >= "2008-10-11T03:05:07Z") + for rev in mysite.watchlist_revs(end="2008-10-11T04:06:08Z", + limit=5, reverse=True): + self.assertType(rev, dict) + self.assertTrue(rev['timestamp'] <= "2008-10-11T04:06:08Z") + for rev in mysite.watchlist_revs(start="2008-10-13T11:59:59Z", + end="2008-10-13T00:00:01Z", + limit=5): + self.assertType(rev, dict) + self.assertTrue("2008-10-13T00:00:01Z" <= rev['timestamp'] + <= "2008-10-13T11:59:59Z") + for rev in mysite.watchlist_revs(start="2008-10-15T06:00:01Z", + end="2008-10-15T23:59:59Z", + reverse=True, limit=5): + self.assertType(rev, dict) + self.assertTrue("2008-10-15T06:00:01Z" <= rev['timestamp'] + <= "2008-10-15T23:59:59Z") + # start earlier than end + self.assertRaises(pywikibot.Error, mysite.watchlist_revs, + start="2008-09-03T00:00:01Z", + end="2008-09-03T23:59:59Z", limit=5) + # reverse: end earlier than start + self.assertRaises(pywikibot.Error, mysite.watchlist_revs, + start="2008-09-03T23:59:59Z", + end="2008-09-03T00:00:01Z", reverse=True, limit=5) + for rev in mysite.watchlist_revs(namespaces=[6,7], limit=5): + self.assertType(rev, dict) + self.assertTrue("title" in rev and "ns" in rev) + title = rev['title'] + self.assertTrue(":" in title) + prefix = title[ : title.index(":")] + self.assertTrue(mysite.ns_index(prefix) in [6,7]) + self.assertTrue(rev["ns"] in [6,7]) + for rev in mysite.watchlist_revs(showMinor=True, limit=5): + self.assertType(rev, dict) + self.assertTrue("minor" in rev) + for rev in mysite.watchlist_revs(showMinor=False, limit=5): + self.assertType(rev, dict) + self.assertTrue("minor" not in rev) + for rev in mysite.watchlist_revs(showBot=True, limit=5): + self.assertType(rev, dict) + self.assertTrue("bot" in rev) + for rev in mysite.watchlist_revs(showBot=False, limit=5): + self.assertType(rev, dict) + self.assertTrue("bot" not in rev) + for rev in mysite.watchlist_revs(showAnon=True, limit=5): + self.assertType(rev, dict) + for rev in mysite.watchlist_revs(showAnon=False, limit=5): + self.assertType(rev, dict) + + def testDeletedrevs(self): + """Test the site.deletedrevs() method""" + + if not mysite.logged_in(True): + try: + mysite.login(True) + except pywikibot.NoUsername: + logger.warn( + "Cannot test Site.deleted_revs; no sysop account configured.") + return + dr = list(mysite.deletedrevs(limit=10, page=mainpage)) + self.assertTrue(len(dr) <= 10) + self.assertTrue(all(isinstance(rev, dict) + for rev in dr)) + dr2 = list(mysite.deletedrevs(page=mainpage, limit=10)) + self.assertTrue(len(dr2) <= 10) + self.assertTrue(all(isinstance(rev, dict) + for rev in dr2)) + for rev in mysite.deletedrevs(start="2008-10-11T01:02:03Z", + page=mainpage, limit=5): + self.assertType(rev, dict) + self.assertTrue(rev['timestamp'] <= "2008-10-11T01:02:03Z") + for rev in mysite.deletedrevs(end="2008-04-01T02:03:04Z", + page=mainpage, limit=5): + self.assertType(rev, dict) + self.assertTrue(rev['timestamp'] >= "2008-10-11T02:03:04Z") + for rev in mysite.deletedrevs(start="2008-10-11T03:05:07Z", + page=mainpage, limit=5, + reverse=True): + self.assertType(rev, dict) + self.assertTrue(rev['timestamp'] >= "2008-10-11T03:05:07Z") + for rev in mysite.deletedrevs(end="2008-10-11T04:06:08Z", + page=mainpage, limit=5, + reverse=True): + self.assertType(rev, dict) + self.assertTrue(rev['timestamp'] <= "2008-10-11T04:06:08Z") + for rev in mysite.deletedrevs(start="2008-10-13T11:59:59Z", + end="2008-10-13T00:00:01Z", + page=mainpage, limit=5): + self.assertType(rev, dict) + self.assertTrue("2008-10-13T00:00:01Z" <= rev['timestamp'] + <= "2008-10-13T11:59:59Z") + for rev in mysite.deletedrevs(start="2008-10-15T06:00:01Z", + end="2008-10-15T23:59:59Z", + page=mainpage, reverse=True, + limit=5): + self.assertType(rev, dict) + self.assertTrue("2008-10-15T06:00:01Z" <= rev['timestamp'] + <= "2008-10-15T23:59:59Z") + # start earlier than end + self.assertRaises(pywikibot.Error, mysite.deletedrevs, + page=mainpage, start="2008-09-03T00:00:01Z", + end="2008-09-03T23:59:59Z", limit=5) + # reverse: end earlier than start + self.assertRaises(pywikibot.Error, mysite.deletedrevs, + page=mainpage, start="2008-09-03T23:59:59Z", + end="2008-09-03T00:00:01Z", reverse=True, + limit=5) + + def testUsers(self): + """Test the site.users() method""" + + us = list(mysite.users(mysite.user())) + self.assertEqual(len(us), 1) + self.assertType(us[0], dict) + for user in mysite.users( + ["Jimbo Wales", "Brion VIBBER", "Tim Starling"]): + self.assertType(user, dict) + self.assertTrue(user["name"] + in ["Jimbo Wales", "Brion VIBBER", "Tim Starling"]) + + def testRandompages(self): + """Test the site.randompages() method""" + + rn = list(mysite.randompages(limit=10)) + self.assertTrue(len(rn) <= 10) + self.assertTrue(all(isinstance(a_page, pywikibot.Page) + for a_page in rn)) + self.assertFalse(all(a_page.isRedirectPage() for a_page in rn)) + for rndpage in mysite.randompages(limit=5, redirects=True): + self.assertType(rndpage, pywikibot.Page) + self.assertTrue(rndpage.isRedirectPage()) + for rndpage in mysite.randompages(limit=5, namespaces=[6, 7]): + self.assertType(rndpage, pywikibot.Page) + self.assertTrue(rndpage.namespace() in [6, 7]) + + +if __name__ == '__main__': +# pywikibot.logging.getLogger("").setLevel(pywikibot.logging.DEBUG) + try: + try: + unittest.main() + except SystemExit: + pass + finally: + pywikibot.stopme()
Property changes on: branches/rewrite/pywikibot/tests/site_tests.py ___________________________________________________________________ Added: svn:eol-style + native
Property changes on: branches/rewrite/pywikibot/userinterfaces/__init__.py ___________________________________________________________________ Added: svn:eol-style + native