import six
from mwklient.util import parse_timestamp, strip_namespace
import mwklient.listing
import mwklient.errors
from mwklient.pages import read as READ, link as LINK
from mwklient.pages import edit as EDIT, hazard as HAZARD
[docs]class Page(READ.Mixin, EDIT.Mixin, LINK.Mixin, HAZARD.Mixin):
def __init__(self, site, name, info=None, extra_properties=None):
if type(name) is type(self):
self.__dict__.update(name.__dict__)
return
self.site = site
self.name = name
self._textcache = {}
if not info:
if extra_properties:
prop = 'info|' + '|'.join(six.iterkeys(extra_properties))
extra_props = []
for extra_prop in six.itervalues(extra_properties):
extra_props.extend(extra_prop)
else:
prop = 'info'
extra_props = ()
if isinstance(name, int):
info = self.site.get(
'query',
prop=prop,
pageids=name,
inprop='protection',
*extra_props)
else:
info = self.site.get(
'query',
prop=prop,
titles=name,
inprop='protection',
*extra_props)
info = six.next(six.itervalues(info['query']['pages']))
self._info = info
if 'invalid' in info:
raise mwklient.errors.InvalidPageTitle(info.get('invalidreason'))
self.namespace = info.get('ns', 0)
self.name = info.get('title', u'')
if self.namespace:
self.page_title = strip_namespace(self.name)
else:
self.page_title = self.name
self.touched = parse_timestamp(info.get('touched'))
self.revision = info.get('lastrevid', 0)
self.exists = 'missing' not in info
self.length = info.get('length')
self.protection = {
i['type']: (i['level'], i['expiry'])
for i in info.get('protection', ()) if i
}
self.redirect = 'redirect' in info
self.pageid = info.get('pageid', None)
self.contentmodel = info.get('contentmodel', None)
self.pagelanguage = info.get('pagelanguage', None)
self.restrictiontypes = info.get('restrictiontypes', None)
self.last_rev_time = None
self.edit_time = None
[docs] def redirects_to(self):
""" Returns the redirect target page, or None if the page is not a
redirect page."""
info = self.site.get(
'query', prop='pageprops', titles=self.name, redirects='')['query']
if 'redirects' in info:
for page in info['redirects']:
if page['from'] == self.name:
return Page(self.site, page['to'])
return None
[docs] def resolve_redirect(self):
""" Returns the redirect target page, or the current page if it's not a
redirect page."""
target_page = self.redirects_to()
if target_page is None:
return self
return target_page
def __repr__(self):
return "<Page object '%s' for %s>" % (self.name.encode('utf-8'),
self.site)
def __unicode__(self):
return self.name
[docs] def can(self, action):
"""Check if the current user has the right to carry out some action
with the current page.
Example:
>>> page.can('edit')
True
"""
level = self.protection.get(action, (action, ))[0]
if level == 'sysop':
level = 'editprotected'
return level in self.site.rights
[docs] def cannot(self, action):
"""Check if the current user has not the right to carry out some action
with the current page.
Example:
>>> page.cannot('edit')
True
"""
return not self.can(action)
def __get_token__(self, type_t, force=False):
return self.site.get_token(type_t, force, title=self.name)
[docs] def purge(self):
"""Purge server-side cache of page. This will re-render templates and
other dynamic content.
"""
self.site.post('purge', titles=self.name)
# def watch: requires 1.14
[docs] def revisions(self,
startid=None,
endid=None,
start=None,
end=None,
direc='older',
user=None,
excludeuser=None,
limit=50,
prop='ids|timestamp|flags|comment|user',
expandtemplates=False,
section=None,
diffto=None,
slots=None, uselang=None):
"""List revisions of the current page.
API doc: https://www.mediawiki.org/wiki/API:Revisions
Args:
startid (int): Revision ID to start listing from.
endid (int): Revision ID to stop listing at.
start (str): Timestamp to start listing from.
end (str): Timestamp to end listing at.
direc (str): Direction to list in: 'older' (default) or 'newer'.
user (str): Only list revisions made by this user.
excludeuser (str): Exclude revisions made by this user.
limit (int): The maximum number of revisions to return per request.
prop (str): Which properties to get for each revision,
default: 'ids|timestamp|flags|comment|user'
expandtemplates (bool): Expand templates in rvprop=content output
section (int): If rvprop=content is set, only retrieve the contents
of this section.
diffto (str): Revision ID to diff each revision to. Use "prev",
"next" and "cur" for the previous, next and current
revision respectively.
slots (str): The content slot (Mediawiki >= 1.32) to retrieve
content from.
uselang (str): Language to use for parsed edit comments and other
localized messages.
Returns:
mwklient.listings.List: Revision iterator
"""
kwargs = dict(
mwklient.listing.List.generate_kwargs(
'rv',
startid=startid,
endid=endid,
start=start,
end=end,
user=user,
excludeuser=excludeuser,
diffto=diffto,
slots=slots))
if self.site.version[:2] < (1, 32) and 'rvslots' in kwargs:
# https://github.com/mwclient/mwclient/issues/199
del kwargs['rvslots']
kwargs['rvdir'] = direc
kwargs['rvprop'] = prop
kwargs['uselang'] = uselang
if expandtemplates:
kwargs['rvexpandtemplates'] = '1'
if section is not None:
kwargs['rvsection'] = section
return mwklient.listing.RevisionsIterator(
self, 'revisions', 'rv', limit=limit, **kwargs)