def __next__(self): if self.max_items is not None: if self.count >= self.max_items: raise StopIteration # For filered lists, we might have to do several requests # to get the next element due to miser mode. # See: https://github.com/mwclient/mwclient/issues/194 while True: try: item = six.next(self._iter) if item is not None: break except StopIteration: if self.last: raise self.load_chunk() self.count += 1 if 'timestamp' in item: item['timestamp'] = parse_timestamp(item['timestamp']) if isinstance(self, GeneratorList): return item if type(self.return_values) is tuple: return tuple((item[i] for i in self.return_values)) if self.return_values is not None: return item[self.return_values] return item
def revisions(self, revids, prop='ids|timestamp|flags|comment|user'): """Get data about a list of revisions. See also the `Page.revisions()` method. API doc: https://www.mediawiki.org/wiki/API:Revisions Example: Get revision text for two revisions: >>> for revision in site.revisions([689697696, 689816909], prop='content'): ... print revision['*'] Args: revids (list): A list of (max 50) revisions. prop (str): Which properties to get for each revision. Returns: A list of revisions """ kwargs = { 'prop': 'revisions', 'rvprop': prop, 'revids': '|'.join(map(text_type, revids)) } revisions = [] pages = self.get('query', **kwargs).get('query', {}).get('pages', {}).values() for page in pages: for revision in page.get('revisions', ()): revision['pageid'] = page.get('pageid') revision['pagetitle'] = page.get('title') revision['timestamp'] = parse_timestamp(revision['timestamp']) revisions.append(revision) return revisions
def save(self, text, summary=u'', minor=False, bot=True, section=None, **kwargs): """Update the text of a section or the whole page by performing an edit operation. """ if not self.site.logged_in and self.site.force_login: raise mwclient.errors.AssertUserFailedError() if self.site.blocked: raise mwclient.errors.UserBlocked(self.site.blocked) if not self.can('edit'): raise mwclient.errors.ProtectedPageError(self) if not self.site.writeapi: raise mwclient.errors.NoWriteApi(self) data = {} if minor: data['minor'] = '1' if not minor: data['notminor'] = '1' if self.last_rev_time: data['basetimestamp'] = time.strftime('%Y%m%d%H%M%S', self.last_rev_time) if self.edit_time: data['starttimestamp'] = time.strftime('%Y%m%d%H%M%S', self.edit_time) if bot: data['bot'] = '1' if section: data['section'] = section data.update(kwargs) if self.site.force_login: data['assert'] = 'user' def do_edit(): result = self.site.post('edit', title=self.name, text=text, summary=summary, token=self.get_token('edit'), **data) if result['edit'].get('result').lower() == 'failure': raise mwclient.errors.EditError(self, result['edit']) return result try: result = do_edit() except mwclient.errors.APIError as e: if e.code == 'badtoken': # Retry, but only once to avoid an infinite loop self.get_token('edit', force=True) try: result = do_edit() except mwclient.errors.APIError as e: self.handle_edit_error(e, summary) else: self.handle_edit_error(e, summary) # 'newtimestamp' is not included if no change was made if 'newtimestamp' in result['edit'].keys(): self.last_rev_time = parse_timestamp(result['edit'].get('newtimestamp')) # clear the page text cache self._textcache = {} return result['edit']
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 type(name) is 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 mwclient.errors.InvalidPageTitle(info.get('invalidreason')) self.namespace = info.get('ns', 0) self.name = info.get('title', u'') if self.namespace: self.page_title = self.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
def revisions(self, revids, prop='ids|timestamp|flags|comment|user', expandtemplates=False, diffto='prev'): """Get data about a list of revisions. See also the `Page.revisions()` method. API doc: https://www.mediawiki.org/wiki/API:Revisions Example: Get revision text for two revisions: >>> for revision in site.revisions([689697696, 689816909], prop='content'): ... print revision['*'] Args: revids (list): A list of (max 50) revisions. prop (str): Which properties to get for each revision. expandtemplates (bool): Expand templates in `rvprop=content` output. diffto (str): Revision ID to diff each revision to. Use "prev", "next" and "cur" for the previous, next and current revision respectively. Returns: A list of revisions """ kwargs = { 'prop': 'revisions', 'rvprop': prop, 'revids': '|'.join(map(text_type, revids)) } if expandtemplates: kwargs['rvexpandtemplates'] = '1' if diffto: kwargs['rvdiffto'] = diffto revisions = [] pages = self.get('query', **kwargs).get('query', {}).get('pages', {}).values() for page in pages: for revision in page.get('revisions', ()): revision['pageid'] = page.get('pageid') revision['pagetitle'] = page.get('title') revision['timestamp'] = parse_timestamp(revision['timestamp']) revisions.append(revision) return revisions
def __init__(self, site, name, info=None, extra_properties=None): if type(name) is type(self): return self.__dict__.update(name.__dict__) self.site = site self.name = name self.section = None if not info: if extra_properties: prop = "info|" + "|".join(six.iterkeys(extra_properties)) extra_props = [] [extra_props.extend(extra_prop) for extra_prop in six.itervalues(extra_properties)] else: prop = "info" extra_props = () if type(name) is int: info = self.site.api("query", prop=prop, pageids=name, inprop="protection", *extra_props) else: info = self.site.api("query", prop=prop, titles=name, inprop="protection", *extra_props) info = six.next(six.itervalues(info["query"]["pages"])) self._info = info self.namespace = info.get("ns", 0) self.name = info.get("title", u"") if self.namespace: self.page_title = self.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 = dict([(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
def __init__(self, site, name, info=None): self.site = site self.name = name if not info: prop = 'blockinfo|groups|rights|editcount|registration|emailable' info = self.site.get('query', list='users', usprop=prop, ususers=name) info = info['query']['users'][0] self._info = info if 'invalid' in info: raise mwclient.errors.InvalidPageTitle(info.get('invalidreason')) self.id = info.get('userid') self.editcount = info.get('editcount', 0) self.registration = parse_timestamp(info.get('registration')) self.groups = info.get('groups', []) self.rights = info.get('rights', []) self.emailable = info.get('emailable')
def __next__(self): if self.max_items is not None: if self.count >= self.max_items: raise StopIteration try: item = six.next(self._iter) except StopIteration: if self.last: raise self.load_chunk() item = six.next(self._iter) self.count += 1 if 'timestamp' in item: item['timestamp'] = parse_timestamp(item['timestamp']) if isinstance(self, GeneratorList): return item if type(self.return_values) is tuple: return tuple((item[i] for i in self.return_values)) if self.return_values is not None: return item[self.return_values] return item
def __next__(self, full=False): if self.max_items is not None: if self.count >= self.max_items: raise StopIteration try: item = six.next(self._iter) self.count += 1 if 'timestamp' in item: item['timestamp'] = parse_timestamp(item['timestamp']) if full: return item if type(self.return_values) is tuple: return tuple((item[i] for i in self.return_values)) elif self.return_values is None: return item else: return item[self.return_values] except StopIteration: if self.last: raise StopIteration self.load_chunk() return self.__next__(full=full)
def __next__(self, full=False): if self.max_items is not None: if self.count >= self.max_items: raise StopIteration try: item = six.next(self._iter) self.count += 1 if 'timestamp' in item: item['timestamp'] = parse_timestamp(item['timestamp']) if full: return item if type(self.return_values) is tuple: return tuple((item[i] for i in self.return_values)) elif self.return_values is None: return item else: return item[self.return_values] except StopIteration: if self.last: raise StopIteration self.load_chunk() return List.__next__(self, full=full)
def test_parse_nonempty_timestamp(self): assert time.struct_time([2015, 1, 2, 20, 18, 36, 4, 2, -1]) == parse_timestamp('2015-01-02T20:18:36Z')
def test_parse_empty_timestamp(self): assert (0, 0, 0, 0, 0, 0, 0, 0, 0) == parse_timestamp('0000-00-00T00:00:00Z')
def save(self, text, summary=u"", minor=False, bot=True, section=None, **kwargs): """ Update the text of a section or the whole page by performing an edit operation. """ if not self.site.logged_in and self.site.force_login: # Should we really check for this? raise mwclient.errors.LoginError( self.site, "By default, mwclient protects you from " + "accidentally editing without being logged in. If you " + "actually want to edit without logging in, you can set " + "force_login on the Site object to False.", ) if self.site.blocked: raise mwclient.errors.UserBlocked(self.site.blocked) if not self.can("edit"): raise mwclient.errors.ProtectedPageError(self) if self.section is not None and section is None: warnings.warn( "From mwclient version 0.8.0, the `save()` method will no longer " + "implicitly use the `section` parameter from the last `text()` or " + "`edit()` call. Please pass the `section` parameter explicitly to " + "the save() method to save only a single section.", category=DeprecationWarning, stacklevel=2, ) section = self.section if not self.site.writeapi: raise mwclient.errors.NoWriteApi(self) data = {} if minor: data["minor"] = "1" if not minor: data["notminor"] = "1" if self.last_rev_time: data["basetimestamp"] = time.strftime("%Y%m%d%H%M%S", self.last_rev_time) if self.edit_time: data["starttimestamp"] = time.strftime("%Y%m%d%H%M%S", self.edit_time) if bot: data["bot"] = "1" if section: data["section"] = section data.update(kwargs) def do_edit(): result = self.site.api( "edit", title=self.name, text=text, summary=summary, token=self.get_token("edit"), **data ) if result["edit"].get("result").lower() == "failure": raise mwclient.errors.EditError(self, result["edit"]) return result try: result = do_edit() except mwclient.errors.APIError as e: if e.code == "badtoken": # Retry, but only once to avoid an infinite loop self.get_token("edit", force=True) try: result = do_edit() except mwclient.errors.APIError as e: self.handle_edit_error(e, summary) else: self.handle_edit_error(e, summary) # 'newtimestamp' is not included if no change was made if "newtimestamp" in result["edit"].keys(): self.last_rev_time = parse_timestamp(result["edit"].get("newtimestamp")) return result["edit"]
def save(self, text, summary=u'', minor=False, bot=True, section=None, **kwargs): """ Update the text of a section or the whole page by performing an edit operation. """ if not self.site.logged_in and self.site.force_login: # Should we really check for this? raise mwclient.errors.LoginError( self.site, 'By default, mwclient protects you from ' + 'accidentally editing without being logged in. If you ' + 'actually want to edit without logging in, you can set ' + 'force_login on the Site object to False.') if self.site.blocked: raise mwclient.errors.UserBlocked(self.site.blocked) if not self.can('edit'): raise mwclient.errors.ProtectedPageError(self) if not self.site.writeapi: raise mwclient.errors.NoWriteApi(self) data = {} if minor: data['minor'] = '1' if not minor: data['notminor'] = '1' if self.last_rev_time: data['basetimestamp'] = time.strftime('%Y%m%d%H%M%S', self.last_rev_time) if self.edit_time: data['starttimestamp'] = time.strftime('%Y%m%d%H%M%S', self.edit_time) if bot: data['bot'] = '1' if section: data['section'] = section data.update(kwargs) def do_edit(): result = self.site.api('edit', title=self.name, text=text, summary=summary, token=self.get_token('edit'), **data) if result['edit'].get('result').lower() == 'failure': raise mwclient.errors.EditError(self, result['edit']) return result try: result = do_edit() except mwclient.errors.APIError as e: if e.code == 'badtoken': # Retry, but only once to avoid an infinite loop self.get_token('edit', force=True) try: result = do_edit() except mwclient.errors.APIError as e: self.handle_edit_error(e, summary) else: self.handle_edit_error(e, summary) # 'newtimestamp' is not included if no change was made if 'newtimestamp' in result['edit'].keys(): self.last_rev_time = parse_timestamp( result['edit'].get('newtimestamp')) # clear the page text cache self._textcache = {} return result['edit']
def test_parse_missing_timestamp(self): assert time.struct_time((0, 0, 0, 0, 0, 0, 0, 0, 0)) == parse_timestamp(None)
def test_parse_empty_timestamp(self): assert time.struct_time((0, 0, 0, 0, 0, 0, 0, 0, 0)) == parse_timestamp('0000-00-00T00:00:00Z')
def test_parse_nonempty_timestamp(self): assert time.struct_time([2015, 1, 2, 20, 18, 36, 4, 2, -1]) == parse_timestamp("2015-01-02T20:18:36Z")
def test_parse_empty_timestamp(self): assert (0, 0, 0, 0, 0, 0, 0, 0, 0) == parse_timestamp("0000-00-00T00:00:00Z")
def _edit(self, summary, minor, bot, section, **kwargs): if not self.site.logged_in and self.site.force_login: raise mwclient.errors.AssertUserFailedError() if self.site.blocked: raise mwclient.errors.UserBlocked(self.site.blocked) if not self.can('edit'): raise mwclient.errors.ProtectedPageError(self) if not self.site.writeapi: raise mwclient.errors.NoWriteApi(self) data = {} if minor: data['minor'] = '1' if not minor: data['notminor'] = '1' if self.last_rev_time: data['basetimestamp'] = time.strftime('%Y%m%d%H%M%S', self.last_rev_time) if self.edit_time: data['starttimestamp'] = time.strftime('%Y%m%d%H%M%S', self.edit_time) if bot: data['bot'] = '1' if section is not None: data['section'] = section data.update(kwargs) if self.site.force_login: data['assert'] = 'user' def do_edit(): result = self.site.post('edit', title=self.name, summary=summary, token=self.get_token('edit'), **data) if result['edit'].get('result').lower() == 'failure': raise mwclient.errors.EditError(self, result['edit']) return result try: result = do_edit() except mwclient.errors.APIError as e: if e.code == 'badtoken': # Retry, but only once to avoid an infinite loop self.get_token('edit', force=True) try: result = do_edit() except mwclient.errors.APIError as e: self.handle_edit_error(e, summary) else: self.handle_edit_error(e, summary) # 'newtimestamp' is not included if no change was made if 'newtimestamp' in result['edit'].keys(): self.last_rev_time = parse_timestamp( result['edit'].get('newtimestamp')) # Workaround for https://phabricator.wikimedia.org/T211233 for cookie in self.site.connection.cookies: if 'PostEditRevision' in cookie.name: self.site.connection.cookies.clear(cookie.domain, cookie.path, cookie.name) # clear the page text cache self._textcache = {} return result['edit']
def save(self, text, summary=u'', minor=False, bot=True, section=None, **kwargs): """ Update the text of a section or the whole page by performing an edit operation. """ if not self.site.logged_in and self.site.force_login: # Should we really check for this? raise mwclient.errors.LoginError(self.site, 'By default, mwclient protects you from ' + 'accidentally editing without being logged in. If you ' + 'actually want to edit without logging in, you can set ' + 'force_login on the Site object to False.') if self.site.blocked: raise mwclient.errors.UserBlocked(self.site.blocked) if not self.can('edit'): raise mwclient.errors.ProtectedPageError(self) if not self.site.writeapi: raise mwclient.errors.NoWriteApi(self) data = {} if minor: data['minor'] = '1' if not minor: data['notminor'] = '1' if self.last_rev_time: data['basetimestamp'] = time.strftime('%Y%m%d%H%M%S', self.last_rev_time) if self.edit_time: data['starttimestamp'] = time.strftime('%Y%m%d%H%M%S', self.edit_time) if bot: data['bot'] = '1' if section: data['section'] = section data.update(kwargs) def do_edit(): result = self.site.api('edit', title=self.name, text=text, summary=summary, token=self.get_token('edit'), **data) if result['edit'].get('result').lower() == 'failure': raise mwclient.errors.EditError(self, result['edit']) return result try: result = do_edit() except mwclient.errors.APIError as e: if e.code == 'badtoken': # Retry, but only once to avoid an infinite loop self.get_token('edit', force=True) try: result = do_edit() except mwclient.errors.APIError as e: self.handle_edit_error(e, summary) else: self.handle_edit_error(e, summary) # 'newtimestamp' is not included if no change was made if 'newtimestamp' in result['edit'].keys(): self.last_rev_time = parse_timestamp(result['edit'].get('newtimestamp')) # clear the page text cache self._textcache = {} return result['edit']