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
Revision: 6476
Author: nicdumz
Date: 2009-03-03 10:01:59 +0000 (Tue, 03 Mar 2009)
Log Message:
-----------
Documentation.
Modified Paths:
--------------
branches/rewrite/pywikibot/data/logentries.py
branches/rewrite/pywikibot/page.py
Modified: branches/rewrite/pywikibot/data/logentries.py
===================================================================
--- branches/rewrite/pywikibot/data/logentries.py 2009-03-03 09:56:02 UTC (rev 6475)
+++ branches/rewrite/pywikibot/data/logentries.py 2009-03-03 10:01:59 UTC (rev 6476)
@@ -14,7 +14,7 @@
from pywikibot import date
class LogDict(dict):
- """Simple custom dictionary that raises an APIError instead of a KeyError"""
+ """Simple custom dictionary that raises a custom Error instead of a KeyError"""
def __missing__(self, key):
pywikibot.output(u"API log entry received:\n" + repr(self),
level=pywikibot.DEBUG)
@@ -23,6 +23,9 @@
class LogEntry(object):
"""Generic log entry"""
+ # Log type expected. None for every type, or one of the (letype) str :
+ # block/patrol/etc...
+ # Overriden in subclasses.
_expectedType = None
def __init__(self, apidata):
Modified: branches/rewrite/pywikibot/page.py
===================================================================
--- branches/rewrite/pywikibot/page.py 2009-03-03 09:56:02 UTC (rev 6475)
+++ branches/rewrite/pywikibot/page.py 2009-03-03 10:01:59 UTC (rev 6476)
@@ -962,7 +962,7 @@
pywikibot.output(u'Moving %s to [[%s]].'
% (self.title(asLink=True), newtitle))
reason = pywikibot.input(u'Please enter a reason for the move:')
- # TODO: implement "safe" parameter
+ # TODO: implement "safe" parameter (Is this necessary ?)
# TODO: implement "sysop" parameter
return self.site().movepage(self, newtitle, reason,
movetalk=movetalkpage,
@@ -1112,7 +1112,13 @@
oldCat and newCat should be Category objects.
If newCat is None, the category will be removed.
- """ # TODO: document remaining arguments
+ comment: string to use as an edit summary
+
+ sortKey: sortKey to use for the added category.
+ Unused if newCat is None, or if inPlace=True
+
+ """
+ #TODO: is inPlace necessary?
site = self.site()
changesMade = False
Bugs item #2531935, was opened at 2009-01-23 23:29
Message generated for change (Comment added) made by purodha
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=603138&aid=2531935&group_…
Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: interwiki
Group: None
Status: Open
Resolution: None
Priority: 5
Private: No
Submitted By: Nobody/Anonymous (nobody)
Assigned to: Purodha B Blissenbach (purodha)
Summary: -hintfile: option
Initial Comment:
The newly introduced version -hintfile: is not well-documented or it's not working as expected.
It asks for a page to be checked (see below) while (according to [2284955] interwiki hints from file) it's supposed to read both a local page and a hint page from file. Please fix it. Thanks!
python interwiki.py -hintfile:
Please enter the hint filename: hints.txt
Which page to check:
Pywikipedia [http] trunk/pywikipedia (r6291, Jan 23 2009, 16:08:14)
Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)]
----------------------------------------------------------------------
>Comment By: Purodha B Blissenbach (purodha)
Date: 2009-03-03 09:44
Message:
What you want to have, in the above example, can be had with:
python interwiki.py -v -hintfile: -file:
Pywikipediabot (r6439 (wikipedia.py), Feb 24 2009, 21:48:26)
Python 2.5.2 (r252:60911, Jan 4 2009, 21:59:32)
[GCC 4.3.2]
Please enter the hint filename: hints.txt
Please enter the local file name: local-page-title.txt
There is no documentation saying that -hintfile: was overriding or
altering
the processing of any other parameter (and in fact, it does not)
Be aware that it is hardly useful to have a file with several page titles
given
via -file: when -hintfile: is being used, since hints would apply to each
of those
pages, provoking interwiki conflicts.
Thus -hintfile: is likely more often used with a singe page title on the
command
line. That does not preclude, however, a single page title being read from
a file
using -file:
If, and only if, the file given via -hintfile: has only unspecific hints,
such as [[10:]]
or [[en:]] or [[latin:]], (or all specific hinted pages do not exist) then
supplying a
list of pages via -file: would be likely free of conflicts.
There is a difference between hints and the page being processed. While
for the
outcome, in properly preset cases, it is often irrelevant where the bot
starts
processing, and which pages are then added because hinted, for the paths
the
bot follows while collecting links, it does make a huge difference
sometimes.
We can have hintless processing, but we cannot have a bot run on hints
alone,
without a starting page.
Maybe we should add some of these to the documentation? Is that, which
you
are asking for?
----------------------------------------------------------------------
Comment By: siebrand (siebrand)
Date: 2009-01-27 08:54
Message:
Assigned to committer.
----------------------------------------------------------------------
Comment By: siebrand (siebrand)
Date: 2009-01-27 08:50
Message:
Assigned to committer.
----------------------------------------------------------------------
Comment By: siebrand (siebrand)
Date: 2009-01-27 08:45
Message:
Assigned to committer.
----------------------------------------------------------------------
Comment By: siebrand (siebrand)
Date: 2009-01-27 08:36
Message:
Assigned to committer.
----------------------------------------------------------------------
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=603138&aid=2531935&group_…
Revision: 6470
Author: nicdumz
Date: 2009-03-03 05:38:35 +0000 (Tue, 03 Mar 2009)
Log Message:
-----------
Adding logentries : A set of skeleton classes to wrap data returned by the API on logevents queries.
Wrappers still have to be implemented, with generic methods, and methods specific to each log type, but the Factory has been implemented and tested.
Added Paths:
-----------
branches/rewrite/pywikibot/data/logentries.py
Added: branches/rewrite/pywikibot/data/logentries.py
===================================================================
--- branches/rewrite/pywikibot/data/logentries.py (rev 0)
+++ branches/rewrite/pywikibot/data/logentries.py 2009-03-03 05:38:35 UTC (rev 6470)
@@ -0,0 +1,110 @@
+# -*- coding: utf-8 -*-
+"""
+Objects representing Mediawiki log entries
+"""
+#
+# (C) Pywikipedia bot team, 2007-08
+#
+# Distributed under the terms of the MIT license.
+#
+__version__ = '$Id: $'
+
+from api import APIError
+
+class LogEntry(object):
+ """Generic log entry"""
+ def __init__(self, apidata):
+ """Initialize object from a logevent dict returned by MW API"""
+ raise NotImplementedError(self.__class__)
+
+class BlockEntry(LogEntry):
+ pass
+
+class ProtectEntry(LogEntry):
+ pass
+
+class RightsEntry(LogEntry):
+ pass
+
+class DeleteEntry(LogEntry):
+ pass
+
+class UploadEntry(LogEntry):
+ pass
+
+class MoveEntry(LogEntry):
+ pass
+
+class ImportEntry(LogEntry):
+ pass
+
+class PatrolEntry(LogEntry):
+ pass
+
+class NewUsersEntry(LogEntry):
+ pass
+
+#TODO entries for merge,suppress,makebot,gblblock,renameuser,globalauth,gblrights ?
+
+
+_logtypes = {
+ 'block':BlockEntry,
+ 'protect':ProtectEntry,
+ 'rights':RightsEntry,
+ 'delete':DeleteEntry,
+ 'upload':UploadEntry,
+ 'move':MoveEntry,
+ 'import':ImportEntry,
+ 'patrol':PatrolEntry,
+ 'newusers':NewUsersEntry
+}
+
+def _getEntryClass(logtype):
+ """
+ Returns the class corresponding to the @logtype string parameter.
+ Returns LogEntry if logtype is unknown or not supported
+ """
+ try:
+ return _logtypes[logtype]
+ except KeyError:
+ return LogEntry
+
+class LogEntryFactory(object):
+ """
+ LogEntry Factory
+
+ Only available method is create()
+ """
+ def __init__(self, logtype=None):
+ """
+ @param logtype: The log type of the log entries, if known in advance.
+ If None, the Factory will fetch the log entry from
+ the data to create each object.
+ @type logtype: (letype) str : move/block/patrol/etc...
+ """
+ if logtype is None:
+ self._creator = self._createFromData
+ else:
+ # Bind a Class object to self._creator:
+ # When called, it will initialize a new object of that class
+ self._creator = _getEntryClass(logtype)
+
+ def create(self, logdata):
+ """
+ Instantiates the LogEntry object representing logdata
+ @param logdata: <item> returned by the api
+ @type logdata: dict
+
+ @return LogEntry object representing logdata
+ """
+ return self._creator(logdata)
+
+ def _createFromData(self, logdata):
+ """
+ Checks for logtype from data, and creates the correct LogEntry
+ """
+ try:
+ logtype = logdata['type']
+ return _getEntryClass(logtype)(logdata)
+ except KeyError:
+ raise APIError("Log entry has no 'type' key")