Revision: 7984
Author: russblau
Date: 2010-03-09 19:07:34 +0000 (Tue, 09 Mar 2010)
Log Message:
-----------
Implement Assert Edit extension (note: using assert=user, *not* assert=bot, because it may
be possible to use the framework without a bot flag on some wikis); also convert various
debug statements to pywikibot.output calls.
Modified Paths:
--------------
branches/rewrite/pywikibot/data/api.py
Modified: branches/rewrite/pywikibot/data/api.py
===================================================================
--- branches/rewrite/pywikibot/data/api.py 2010-03-09 08:14:34 UTC (rev 7983)
+++ branches/rewrite/pywikibot/data/api.py 2010-03-09 19:07:34 UTC (rev 7984)
@@ -79,7 +79,7 @@
Returns a dict containing the JSON data returned by the wiki. Normally,
one of the dict keys will be equal to the value of the 'action'
parameter. Errors are caught and raise an APIError exception.
-
+
Example:
>> r = Request(site=mysite,
action="query", meta="userinfo")
@@ -99,7 +99,7 @@
[u'query']
>> data[u'query'].keys()
[u'userinfo', u'namespaces']
-
+
@param site: The Site to which the request will be submitted. If not
supplied, uses the user's configured default Site.
@param mime: If true, send in "multipart/form-data" format (default False)
@@ -123,6 +123,15 @@
if "action" not in kwargs:
raise ValueError("'action' specification missing from
Request.")
self.update(**kwargs)
+ self.write = self.params["action"] in (
+ "edit", "move", "rollback",
"delete", "undelete",
+ "protect", "block", "unblock",
"watch", "patrol",
+ "import", "userrights", "upload"
+ )
+ if self.write:
+ pywikibot.output(u"Adding user assertion",
+ level=pywikibot.DEBUG)
+ self.params["assert"] = "user" # make sure user is logged
in
# implement dict interface
def __getitem__(self, key):
@@ -151,7 +160,13 @@
for key in self.params:
if isinstance(self.params[key], basestring):
+ # convert a stringified sequence into a list
self.params[key] = self.params[key].split("|")
+ try:
+ iter(self.params[key])
+ except TypeError:
+ # convert any non-iterable value into a single-element list
+ self.params[key] = [str(self.params[key])]
if self.params["action"] == ['query']:
meta = self.params.get("meta", [])
if "userinfo" not in meta:
@@ -187,27 +202,23 @@
+ "/api.php?"
+ self.http_params()
)
-
+
def submit(self):
"""Submit a query and parse the response.
@return: The data retrieved from api.php (a dict)
-
+
"""
from pywikibot.comms import http
from email.mime.multipart import MIMEMultipart
from email.mime.nonmultipart import MIMENonMultipart
- params = self.http_params()
+ paramstring = self.http_params()
if self.site._loginstatus == -3:
self.site.login(False)
while True:
action = self.params.get("action", "")
- write = action in (
- "edit", "move", "rollback",
"delete", "undelete",
- "protect", "block", "unblock"
- )
- self.site.throttle(write=write)
+ self.site.throttle(write=self.write)
uri = self.site.scriptpath() + "/api.php"
try:
ssl = False
@@ -256,22 +267,24 @@
rawdata = http.request(self.site, uri, ssl, method="POST",
headers={'Content-Type':
'application/x-www-form-urlencoded'},
- body=params)
+ body=paramstring)
except Server504Error:
- logger.debug(u"Caught 504 error")
+ pywikibot.output(u"Caught 504 error",
+ level=pywikibot.DEBUG)
raise
#TODO: what other exceptions can occur here?
except Exception, e:
# for any other error on the http request, wait and retry
pywikibot.output(traceback.format_exc(),
level=pywikibot.ERROR)
- pywikibot.output(u"%s, %s" % (uri, params),
+ pywikibot.output(u"%s, %s" % (uri, paramstring),
level=pywikibot.VERBOSE)
self.wait()
continue
if not isinstance(rawdata, unicode):
rawdata = rawdata.decode(self.site.encoding())
- logger.debug(u"API response received:\n" + rawdata)
+ pywikibot.output(u"API response received:\n" + rawdata,
+ level=pywikibot.DEBUG)
if rawdata.startswith(u"unknown_action"):
raise APIError(rawdata[:14], rawdata[16:])
try:
@@ -281,8 +294,10 @@
# problem. Wait a few seconds and try again
pywikibot.output(
"Non-JSON response received from server %s; the server may be down."
- % self.site, level=pywikibot.WARNING)
- logger.debug(rawdata)
+ % self.site,
+ level=pywikibot.WARNING)
+ pywikibot.output(rawdata,
+ level=pywikibot.DEBUG)
self.wait()
continue
if not result:
@@ -389,6 +404,7 @@
self.site = kwargs["site"]
except KeyError:
self.site = pywikibot.Site()
+ kwargs["site"] = self.site
# make sure request type is valid, and get limit key if any
for modtype in ("generator", "list", "prop",
"meta"):
if modtype in kwargs:
@@ -417,7 +433,7 @@
def get_module(self):
"""Query api on self.site for paraminfo on
querymodule=self.module"""
-
+
paramreq = Request(site=self.site, action="paraminfo",
querymodules=self.module)
data = paramreq.submit()
@@ -456,7 +472,7 @@
"""
self.limit = int(value)
-
+
def update_limit(self):
"""Set query_limit for self.module based on api
response"""
@@ -472,9 +488,10 @@
self.query_limit = int(param["max"])
if self.prefix is None:
self.prefix = _modules[mod]["prefix"]
- logger.debug(u"%s: Set query_limit to %i."
- % (self.__class__.__name__,
- self.query_limit))
+ pywikibot.output(u"%s: Set query_limit to %i."
+ % (self.__class__.__name__,
+ self.query_limit),
+ level=pywikibot.DEBUG)
return
def set_namespace(self, namespaces):
@@ -522,27 +539,34 @@
self.set_query_increment(old_limit // 2)
continue
if not self.data or not isinstance(self.data, dict):
- logger.debug(
+ pywikibot.output(
u"%s: stopped iteration because no dict retrieved from
api."
- % self.__class__.__name__)
+ % self.__class__.__name__,
+ level=pywikibot.DEBUG)
return
if not ("query" in self.data
and self.resultkey in self.data["query"]):
- logger.debug(
+ pywikibot.output(
u"%s: stopped iteration because 'query' and '%s' not found in api
response."
- % (self.__class__.__name__, self.resultkey))
- logger.debug(unicode(self.data))
+ % (self.__class__.__name__, self.resultkey),
+ level=pywikibot.DEBUG)
+ pywikibot.output(unicode(self.data),
+ level=pywikibot.DEBUG)
return
resultdata = self.data["query"][self.resultkey]
if isinstance(resultdata, dict):
- logger.debug(u"%s received %s; limit=%s"
- % (self.__class__.__name__, resultdata.keys(),
- self.limit))
+ pywikibot.output(u"%s received %s; limit=%s"
+ % (self.__class__.__name__,
+ resultdata.keys(),
+ self.limit),
+ level=pywikibot.DEBUG)
resultdata = [resultdata[k] for k in sorted(resultdata.keys())]
else:
- logger.debug(u"%s received %s; limit=%s"
- % (self.__class__.__name__, resultdata,
- self.limit))
+ pywikibot.output(u"%s received %s; limit=%s"
+ % (self.__class__.__name__,
+ resultdata,
+ self.limit),
+ level=pywikibot.DEBUG)
if "normalized" in self.data["query"]:
self.normalized = dict((item['to'], item['from'])
for item in
@@ -581,13 +605,13 @@
This class can be used for any of the query types that are listed in the
API documentation as being able to be used as a generator. Instances of
this class iterate Page objects.
-
+
"""
def __init__(self, generator, **kwargs):
"""
Required and optional parameters are as for C{Request}, except that
action=query is assumed and generator is required.
-
+
@param generator: the "generator=" type from api.php
@type generator: str
@@ -614,7 +638,7 @@
This can be overridden in subclasses to return a different type
of object.
-
+
"""
p = pywikibot.Page(self.site, pagedata['title'], pagedata['ns'])
update_page(p, pagedata)
@@ -657,7 +681,7 @@
"""
Required and optional parameters are as for C{Request}, except that
action=query is assumed and prop is required.
-
+
@param prop: the "property=" type from api.php
@type prop: str
@@ -684,7 +708,7 @@
"""
Required and optional parameters are as for C{Request}, except that
action=query is assumed and listaction is required.
-
+
@param listaction: the "list=" type from api.php
@type listaction: str
@@ -700,7 +724,7 @@
def __init__(self, logtype, **kwargs):
ListGenerator.__init__(self, "logevents", **kwargs)
- import logentries
+ import logentries
self.entryFactory = logentries.LogEntryFactory(logtype)
def result(self, pagedata):
@@ -715,7 +739,7 @@
Parameters are all ignored.
Returns cookie data if succesful, None otherwise.
-
+
"""
if hasattr(self, '_waituntil'):
if datetime.now() < self._waituntil: