Esempio n. 1
0
    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
Esempio n. 2
0
    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
Esempio n. 3
0
    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
Esempio n. 4
0
    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
Esempio n. 5
0
    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']
Esempio n. 6
0
    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
Esempio n. 7
0
    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']
Esempio n. 8
0
    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
Esempio n. 9
0
    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
Esempio n. 10
0
    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
Esempio n. 11
0
	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')
Esempio n. 12
0
    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
Esempio n. 13
0
    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
Esempio n. 14
0
    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
Esempio n. 15
0
    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)
Esempio n. 16
0
    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)
Esempio n. 17
0
 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')
Esempio n. 18
0
 def test_parse_empty_timestamp(self):
     assert (0, 0, 0, 0, 0, 0, 0, 0, 0) == parse_timestamp('0000-00-00T00:00:00Z')
Esempio n. 19
0
    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"]
Esempio n. 20
0
    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']
Esempio n. 21
0
 def test_parse_missing_timestamp(self):
     assert time.struct_time((0, 0, 0, 0, 0, 0, 0, 0, 0)) == parse_timestamp(None)
Esempio n. 22
0
 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')
Esempio n. 23
0
 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")
Esempio n. 24
0
 def test_parse_empty_timestamp(self):
     assert (0, 0, 0, 0, 0, 0, 0, 0, 0) == parse_timestamp("0000-00-00T00:00:00Z")
Esempio n. 25
0
    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']
Esempio n. 26
0
    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']