jenkins-bot submitted this change.

View Change

Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
[IMPR] add support for some 'wbset' actions in DataSite

It can be useful for atomic operations as the API add automatic summary,
which creates a cleaner page history.

To be decided: add support also at page level or not, given that
method for supporting such actions are present via editEntity.

Change-Id: Idfd5de485d2b5aab8d8b1960ceb3c3a3c6b64315
---
M pywikibot/site/__init__.py
M tests/wikibase_edit_tests.py
2 files changed, 199 insertions(+), 0 deletions(-)

diff --git a/pywikibot/site/__init__.py b/pywikibot/site/__init__.py
index c21feb2..f33c42e 100644
--- a/pywikibot/site/__init__.py
+++ b/pywikibot/site/__init__.py
@@ -7637,6 +7637,146 @@
total=total, parameters=parameters)
return gen

+ def _wbset_action(self, itemdef, action, action_data, **kwargs):
+ """
+ Execute wbset{action}' on a Wikibase item.
+
+ Supported actions are:
+ wbsetaliases, wbsetdescription, wbsetlabel and wbsetsitelink
+
+ @param itemdef: Item to modify or create
+ @type itemdef: str, WikibasePage or Page coonected to such item
+ @param action: wbset{action] to perform:
+ 'wbsetaliases', 'wbsetdescription', 'wbsetlabel', 'wbsetsitelink'
+ @type action: str
+ @param data: data to be used in API request, see API help
+ @type data: SiteLink or dict
+ wbsetaliases:
+ dict shall have the following structure:
+ {'language': value (str),
+ 'add': list of language codes (str),
+ 'remove': list of language codes (str),
+ 'set' list of language codes (str)
+ }
+ 'add' and 'remove' are alternative to 'set'
+ wbsetdescription and wbsetlabel:
+ dict shall have keys 'language', 'value'
+ wbsetsitelink:
+ dict shall have keys 'linksite', 'linktitle' and
+ optionally 'badges'
+ @kwargs bot: Whether to mark the edit as a bot edit, default is False
+ @type bot: bool
+ @return: query result
+ @rtype: dict
+ @raises AssertionError, TypeError
+ """
+ def format_sitelink(sitelink):
+ """Convert SiteLink to a dict accepted by wbsetsitelink API."""
+ if isinstance(sitelink, pywikibot.page.SiteLink):
+ _dict = {
+ 'linksite': sitelink._sitekey,
+ 'linktitle': sitelink._rawtitle,
+ 'badges': '|'.join([b.title() for b in sitelink.badges]),
+ }
+ else:
+ _dict = sitelink
+
+ return _dict
+
+ def prepare_data(action, data):
+ """Prepare data as expected by API."""
+ if action == 'wbsetaliases':
+ res = data
+ keys = set(res)
+ assert keys < {'language', 'add', 'remove', 'set'}
+ assert keys & {'add', 'set'} == {}
+ assert keys & {'remove', 'set'} == {}
+ elif action in ('wbsetlabel', 'wbsetdescription'):
+ res = data
+ keys = set(res)
+ assert keys == {'language', 'value'}
+ elif action == 'wbsetsitelink':
+ res = format_sitelink(data)
+ keys = set(res)
+ assert keys >= {'linksite'}
+ assert keys <= {'linksite', 'linktitle', 'badges'}
+ else:
+ raise ValueError('Something has gone wrong ...')
+
+ return res
+
+ # Supported actions
+ assert action in ('wbsetaliases', 'wbsetdescription',
+ 'wbsetlabel', 'wbsetsitelink'), \
+ 'action {} not supported.'.format(action)
+
+ # prefer ID over (site, title)
+ if isinstance(itemdef, str):
+ itemdef = pywikibot.ItemPage(self, itemdef)
+ elif isinstance(itemdef, pywikibot.Page):
+ try:
+ itemdef = itemdef.data_item()
+ except pywikibot.NoPage:
+ itemdef = pywikibot.ItemPage(self)
+ if not isinstance(itemdef, pywikibot.page.WikibasePage):
+ raise TypeError('itemdef shall be str, WikibasePage or Page')
+
+ params = itemdef._defined_by(singular=True)
+ # TODO: support 'new'
+ baserevid = kwargs.pop('baserevid', 0) or itemdef.latest_revision_id
+ params.update(
+ {'id': itemdef.id,
+ 'baserevid': baserevid,
+ 'action': action,
+ 'token': self.tokens['edit'],
+ 'bot': kwargs.pop('bot', False),
+ })
+ params.update(prepare_data(action, action_data))
+
+ for arg in kwargs:
+ if arg in ['summary']:
+ params[arg] = kwargs[arg]
+ else:
+ warn('Unknown parameter {} for action {}, ignored'
+ .format(arg, action), UserWarning, 2)
+
+ req = self._simple_request(**params)
+ data = req.submit()
+ return data
+
+ def wbsetaliases(self, itemdef, aliases, **kwargs):
+ """
+ Set aliases for a single Wikibase entity.
+
+ See self._wbset_action(self, itemdef, action, action_data, **kwargs)
+ """
+ return self._wbset_action(itemdef, 'wbsetaliases', aliases, **kwargs)
+
+ def wbsetdescription(self, itemdef, description, **kwargs):
+ """
+ Set description for a single Wikibase entity.
+
+ See self._wbset_action(self, itemdef, action, action_data, **kwargs)
+ """
+ return self._wbset_action(itemdef, 'wbsetdescription', description,
+ **kwargs)
+
+ def wbsetlabel(self, itemdef, label, **kwargs):
+ """
+ Set label for a single Wikibase entity.
+
+ See self._wbset_action(self, itemdef, action, action_data, **kwargs)
+ """
+ return self._wbset_action(itemdef, 'wbsetlabel', label, **kwargs)
+
+ def wbsetsitelink(self, itemdef, sitelink, **kwargs):
+ """
+ Set, remove or modify a sitelink on a Wikibase item.
+
+ See self._wbset_action(self, itemdef, action, action_data, **kwargs)
+ """
+ return self._wbset_action(itemdef, 'wbsetsitelink', sitelink, **kwargs)
+

wrapper = ModuleDeprecationWrapper(__name__)
# Note: use LoginStatus instead of _LoginStatus
diff --git a/tests/wikibase_edit_tests.py b/tests/wikibase_edit_tests.py
index e8ece10..a75fd81 100644
--- a/tests/wikibase_edit_tests.py
+++ b/tests/wikibase_edit_tests.py
@@ -458,6 +458,65 @@
self.assertNotIn('P88', claim.qualifiers.keys())


+class TestWikibaseDataSiteWbsetActions(WikibaseTestCase):
+
+ """Run general wikibase write tests."""
+
+ family = 'wikidata'
+ code = 'test'
+
+ user = True
+ write = True
+
+ def setUp(self):
+ """Setup tests."""
+ self.testsite = self.get_repo()
+ self.item = pywikibot.ItemPage(self.testsite, 'Q68')
+ badge = pywikibot.ItemPage(self.testsite, 'Q608')
+ self.sitelink = pywikibot.page.SiteLink('Test page',
+ site='enwikisource',
+ badges=[badge])
+ super().setUp()
+
+ def tearDown(self):
+ """Tear down tests."""
+ self.item = None
+ self.sitelink = None
+ super().tearDown()
+
+ def test_wbsetlabel_set_from_id(self):
+ """Test setting an Italian label using id."""
+ self.assertEqual(self.item.getID(), 'Q68')
+ self.testsite.wbsetlabel('Q68', {'language': 'it', 'value': 'Test123'})
+ self.item.get(force=True)
+ self.assertEqual(self.item.labels['it'], 'Test123')
+
+ def test_wbsetlabel_remove_from_item(self):
+ """Test removing an Italian label using item."""
+ self.assertEqual(self.item.getID(), 'Q68')
+ self.testsite.wbsetlabel(self.item, {'language': 'it', 'value': ''})
+ # Check 'it' label is removed
+ self.item.get(force=True)
+ self.assertNotIn('it', self.item.labels.keys())
+
+ def test_wbsetsitelink_set_remove(self):
+ """Test setting a sitelink using id."""
+ self.assertEqual(self.item.getID(), 'Q68')
+ # add sitelink
+ self.testsite.wbsetsitelink(
+ 'Q68',
+ {'linksite': 'enwikisource',
+ 'linktitle': 'Test page',
+ 'badges': 'Q608'
+ })
+ self.item.get(force=True)
+ self.assertEqual(self.item.sitelinks['enwikisource'], self.sitelink)
+ # remove sitelink
+ self.testsite.wbsetsitelink(self.item, {'linksite': 'enwikisource'})
+ self.item.get(force=True)
+ self.assertIsNone(self.item.sitelinks.get('enwikisource'))
+
+
if __name__ == '__main__': # pragma: no cover
with suppress(SystemExit):
unittest.main()

To view, visit change 637872. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Idfd5de485d2b5aab8d8b1960ceb3c3a3c6b64315
Gerrit-Change-Number: 637872
Gerrit-PatchSet: 5
Gerrit-Owner: Mpaa <mpaa.wiki@gmail.com>
Gerrit-Reviewer: Matěj Suchánek <matejsuchanek97@gmail.com>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged