diff --git a/pywikibot/page.py b/pywikibot/page.py index bb8b2247f8..da09fcfc86 100644 --- a/pywikibot/page.py +++ b/pywikibot/page.py @@ -3914,7 +3914,22 @@ def latest_revision_id(self): self.clear_cache() @staticmethod - def _normalizeLanguages(data): + def _normalizeLanguage(value): + """ + Helper function to replace a site object with its language code. + + @param value: The value to normalize + @type value: str|pywikibot.site.BaseSite + + @return: the language string + @rtype: str + """ + if isinstance(value, pywikibot.site.BaseSite): + return value.lang + return value + + @classmethod + def _normalizeLanguages(cls, data): """ Helper function to replace site objects with their language codes. @@ -3924,11 +3939,10 @@ def _normalizeLanguages(data): @return: the altered dict from parameter data. @rtype: dict """ - for key in data: - if isinstance(key, pywikibot.site.BaseSite): - data[key.lang] = data[key] - del data[key] - return data + return { + cls._normalizeLanguage(key): value + for key, value in data.items() + } @classmethod def _normalizeData(cls, data): @@ -4013,17 +4027,70 @@ def editEntity(self, data=None, **kwargs): self._content = updates['entity'] self.get() + @allow_asynchronous + def setLabel(self, language, value, **kwargs): + """ + Set/edit a label using the Wikibase wbsetlabel API. + + To set labels in multiple languages, use the editLabels method instead. + + @param language: Label language code or Site + @type language: str or L{pywikibot.site.BaseSite} + @param value: Label value string + @type value: str + @keyword asynchronous: if True, launch a separate thread to add claim + asynchronously + @type asynchronous: bool + @keyword callback: a callable object that will be called after the entity + has been updated. It must take two arguments: (1) a WikibasePage + object, and (2) an exception instance, which will be None if the + page was saved successfully. This is intended for use by bots that + need to keep track of which saves were successful. + @type callback: callable + """ + self.repo.setLabel(self, self._normalizeLanguage(language), value, + **kwargs) + def editLabels(self, labels, **kwargs): """ Edit entity labels. - Labels should be a dict, with the key - as a language or a site object. The - value should be the string to set it to. - You can set it to '' to remove the label. + @param labels: Dict with the key as a language or a site object. + The value should be the string to set it to. You can set it + to '' to remove the label. + @type labels: dict """ data = {'labels': labels} - self.editEntity(data, **kwargs) + if len(labels.items()) == 1: + language, value = list(labels.items())[0] + self.setLabel(language, value) + else: + self.editEntity(data, **kwargs) + + @allow_asynchronous + def setDescription(self, language, value, **kwargs): + """ + Set/edit a description using the Wikibase wbsetdescription API. + + To set descriptions in multiple languages, use the editDescriptions + method instead. + + @param language: Description language code or Site + @type language: str or L{pywikibot.site.BaseSite} + @param value: Description value string + @type value: str + @keyword asynchronous: if True, launch a separate thread to add claim + asynchronously + @type asynchronous: bool + @keyword callback: a callable object that will be called after the entity + has been updated. It must take two arguments: (1) a WikibasePage + object, and (2) an exception instance, which will be None if the + page was saved successfully. This is intended for use by bots that + need to keep track of which saves were successful. + @type callback: callable + """ + self.repo.setDescription(self, self._normalizeLanguage(language), value, + **kwargs) def editDescriptions(self, descriptions, **kwargs): """ @@ -4035,7 +4102,11 @@ def editDescriptions(self, descriptions, **kwargs): You can set it to '' to remove the description. """ data = {'descriptions': descriptions} - self.editEntity(data, **kwargs) + if len(descriptions.items()) == 1: + language, value = list(descriptions.items())[0] + self.setDescription(language, value) + else: + self.editEntity(data, **kwargs) def editAliases(self, aliases, **kwargs): """ diff --git a/pywikibot/site.py b/pywikibot/site.py index e2bc6ccded..f49279af08 100644 --- a/pywikibot/site.py +++ b/pywikibot/site.py @@ -7928,3 +7928,57 @@ def search_entities(self, search, language, limit=None, **kwargs): if limit is not None: gen.set_maximum_items(limit) return gen + + @must_be(group='user') + def setLabel(self, item, language, value, bot=True, summary=None): + """ + Set or edit a label. + + @param item: Entity to modify + @type item: WikibasePage + @param language: Label language code + @type language: str + @param value: Label value + @type value: str + @param bot: Whether to mark the edit as a bot edit + @type bot: bool + @param summary: Edit summary + @type summary: str + """ + params = {'action': 'wbsetlabel', 'id': item.getID(), + 'baserevid': item.latest_revision_id, + 'language': language, 'value': value, + 'summary': summary, 'bot': bot, + 'token': self.tokens['edit']} + req = self._simple_request(**params) + data = req.submit() + # Update the item + item.labels[language] = value + item.latest_revision_id = data['entity']['lastrevid'] + + @must_be(group='user') + def setDescription(self, item, language, value, bot=True, summary=None): + """ + Set or edit a description. + + @param item: Entity to modify + @type item: WikibasePage + @param language: Description language code + @type language: str + @param value: Description value + @type value: str + @param bot: Whether to mark the edit as a bot edit + @type bot: bool + @param summary: Edit summary + @type summary: str + """ + params = {'action': 'wbsetdescription', 'id': item.getID(), + 'baserevid': item.latest_revision_id, + 'language': language, 'value': value, + 'summary': summary, 'bot': bot, + 'token': self.tokens['edit']} + req = self._simple_request(**params) + data = req.submit() + # Update the item + item.descriptions[language] = value + item.latest_revision_id = data['entity']['lastrevid'] diff --git a/tests/wikibase_edit_tests.py b/tests/wikibase_edit_tests.py index 5c508937b6..6b3137b5a9 100644 --- a/tests/wikibase_edit_tests.py +++ b/tests/wikibase_edit_tests.py @@ -40,6 +40,27 @@ def test_label_set(self): item.get(force=True) self.assertEqual(item.labels['en'], 'Test123') + def test_label_set_using_wbsetlabel(self): + """Test setting a Bokmål label using the wbsetlabel endpoint.""" + item = pywikibot.ItemPage(self.get_repo(), 'Q68') + self.assertIsInstance(item, pywikibot.ItemPage) + item.setLabel('nb', 'Testetikett æøå') + self.assertEqual(item.labels['nb'], 'Testetikett æøå') + item.get(force=True) + self.assertEqual(item.labels['nb'], 'Testetikett æøå') + + def test_label_set_using_wbsetlabel_with_invalid_language_code(self): + """Test setting a Bokmål label using wbsetlabel.""" + item = pywikibot.ItemPage(self.get_repo(), 'Q68') + self.assertIsInstance(item, pywikibot.ItemPage) + try: + item.setLabel('123', 'Test') + except pywikibot.exceptions.OtherPageSaveError as err: + self.assertEqual('unknown_language', err.reason.code) + self.assertEqual('Unrecognized value for parameter "language": 123.', + err.reason.info) + self.assertIsNone(item.labels.get('123')) + def test_label_remove(self): """Test adding a Farsi and English label and removing the Farsi one.""" testsite = self.get_repo() @@ -59,6 +80,15 @@ def test_label_remove(self): item.get() self.assertNotIn('fa', item.labels.keys()) + def test_description_set_using_wbsetdescription(self): + """Test setting a Bokmål description using wbsetdescription.""" + item = pywikibot.ItemPage(self.get_repo(), 'Q68') + self.assertIsInstance(item, pywikibot.ItemPage) + item.setDescription('nb', 'testbeskrivelse æøå') + self.assertEqual(item.descriptions['nb'], 'testbeskrivelse æøå') + item.get(force=True) + self.assertEqual(item.descriptions['nb'], 'testbeskrivelse æøå') + def test_alias_set(self): """Test setting an English alias.""" testsite = self.get_repo()