jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/346700 )
Change subject: Add support for geo-shape Wikibase data type ......................................................................
Add support for geo-shape Wikibase data type
Introduces the WbGeoShape class to provide handling of geo-shape data and do some basic validation on indata.
Also add a comment to commonsMedia to the task explaining how come site is hard-coded to Wikimedia Commons for all Wikibase installations (which is not the case for geo-shapes).
Bug:T161726 Change-Id: Ia96d35519163307227159ccece5981783ce8b558 --- M pywikibot/__init__.py M pywikibot/families/wikidata_family.py M pywikibot/page.py M pywikibot/site.py M tests/wikibase_edit_tests.py M tests/wikibase_tests.py 6 files changed, 171 insertions(+), 3 deletions(-)
Approvals: jenkins-bot: Verified Xqt: Looks good to me, approved
diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py index eff852a..1b6ce51 100644 --- a/pywikibot/__init__.py +++ b/pywikibot/__init__.py @@ -812,6 +812,73 @@ return cls(wb['text'], wb['language'])
+class WbGeoShape(_WbRepresentation): + """ + A Wikibase geo-shape representation. + + A temporary implementation until T162336 has been resolved. + """ + + _items = ('page', ) + + def __init__(self, page, site=None): + """ + Create a new WbGeoShape object. + + @param page: page containing the map data + @type text: pywikibot.Page + @param site: The Wikibase site + @type site: pywikibot.site.DataSite + """ + site = site or Site().data_repository() + if not isinstance(page, Page): + raise ValueError('page must be a pywikibot.Page object.') + + # validate page exists + if not page.exists(): + raise ValueError('page must exist.') + + # validate page is on the right site, and that site supports geo-shapes + geo_shape_site = site.geo_shape_repository() + if not geo_shape_site: + raise ValueError('the provided site does not support geo-shapes.') + if page.site != geo_shape_site: + raise ValueError('page must be on the image repository site.') + + # validate page title fulfills hard-coded Wikibase requirement + # pcre regexp: '/^Data:[^\[\]#\:{|}]+.map$/u' + # As we have already checked for existence the following simplified + # check should be enough. + if not page.title().startswith('Data:') or \ + not page.title().endswith('.map'): + raise ValueError( + "page must be a '.map' page in the 'Data:' namespace.") + + self.page = page + + def toWikibase(self): + """ + Convert the data to the value required by the Wikibase API. + + @return: title of the geo-shape page incl. namespace + @rtype: str + """ + return self.page.title() + + @classmethod + def fromWikibase(cls, page_name, site): + """ + Create a WbGeoShape from the JSON data given by the Wikibase API. + + @param page_name: page name from Wikibase value + @type page_name: str + @rtype: pywikibot.WbGeoShape + """ + geo_shape_site = site.geo_shape_repository() + page = Page(geo_shape_site, page_name) + return cls(page, site) + + _sites = {} _url_cache = {} # The code/fam pair for each URL
diff --git a/pywikibot/families/wikidata_family.py b/pywikibot/families/wikidata_family.py index f695a20..4b30106 100644 --- a/pywikibot/families/wikidata_family.py +++ b/pywikibot/families/wikidata_family.py @@ -50,6 +50,11 @@ """Default calendar model for WbTime datatype.""" return 'http://www.wikidata.org/entity/Q1985727'
+ def shared_geo_shape_repository(self, code): + """Return Wikimedia Commons as the repository for geo-shapes.""" + # Per geoShapeStorageFrontendUrl settings in Wikibase + return ('commons', 'commons') + def globes(self, code): """Supported globes for Coordinate datatype.""" return { diff --git a/pywikibot/page.py b/pywikibot/page.py index 1885aef..e95bab3 100644 --- a/pywikibot/page.py +++ b/pywikibot/page.py @@ -4318,6 +4318,7 @@ 'monolingualtext': pywikibot.WbMonolingualText, 'math': basestring, 'external-id': basestring, + 'geo-shape': pywikibot.WbGeoShape, }
value_types = {'wikibase-item': 'wikibase-entityid', @@ -4327,6 +4328,7 @@ 'globe-coordinate': 'globecoordinate', 'math': 'string', 'external-id': 'string', + 'geo-shape': 'string', }
def __init__(self, site, id, datatype=None): @@ -4457,8 +4459,9 @@ 'wikibase-property': lambda value, site: PropertyPage(site, 'P' + str(value['numeric-id'])), 'commonsMedia': lambda value, site: - FilePage(pywikibot.Site('commons', 'commons'), value), + FilePage(pywikibot.Site('commons', 'commons'), value), # T90492 'globe-coordinate': pywikibot.Coordinate.fromWikibase, + 'geo-shape': pywikibot.WbGeoShape.fromWikibase, 'time': lambda value, site: pywikibot.WbTime.fromWikibase(value), 'quantity': pywikibot.WbQuantity.fromWikibase, 'monolingualtext': lambda value, site: @@ -4884,7 +4887,8 @@ elif self.type == 'commonsMedia': value = self.getTarget().title(withNamespace=False) elif self.type in ('globe-coordinate', 'time', - 'quantity', 'monolingualtext'): + 'quantity', 'monolingualtext', + 'geo-shape'): value = self.getTarget().toWikibase() else: raise NotImplementedError('%s datatype is not supported yet.' diff --git a/pywikibot/site.py b/pywikibot/site.py index c715902..7c04551 100644 --- a/pywikibot/site.py +++ b/pywikibot/site.py @@ -7231,6 +7231,13 @@ """ return self
+ def geo_shape_repository(self): + """Return Site object for the geo-shapes repository e.g. commons.""" + # Do this via API instead if T162561 is implemented. + code, fam = self.shared_geo_shape_repository() + if bool(code or fam): + return pywikibot.Site(code, fam, self.username()) + def loadcontent(self, identification, *props): """ Fetch the current content of a Wikibase item. diff --git a/tests/wikibase_edit_tests.py b/tests/wikibase_edit_tests.py index 670eab9..1361c98 100644 --- a/tests/wikibase_edit_tests.py +++ b/tests/wikibase_edit_tests.py @@ -300,6 +300,25 @@ claim = item.claims['P718'][0] self.assertEqual(claim.getTarget(), target)
+ def test_WbGeoShape_edit(self): + """Attempt adding a geo-shape with valid input.""" + # Clean the slate in preparation for test. + testsite = self.get_repo() + item = self._clean_item(testsite, 'P27199') + + # set new claim + claim = pywikibot.page.Claim(testsite, 'P27199', datatype='geo-shape') + commons_site = pywikibot.Site('commons', 'commons') + page = pywikibot.Page(commons_site, 'Data:Lyngby Hovedgade.map') + target = pywikibot.WbGeoShape(page) + claim.setTarget(target) + item.addClaim(claim) + + # confirm new claim + item.get(force=True) + claim = item.claims['P27199'][0] + self.assertEqual(claim.getTarget(), target) +
class TestWikibaseRemoveQualifier(WikibaseTestCase):
diff --git a/tests/wikibase_tests.py b/tests/wikibase_tests.py index 0006172..98c542d 100644 --- a/tests/wikibase_tests.py +++ b/tests/wikibase_tests.py @@ -18,7 +18,7 @@ import pywikibot
from pywikibot import pagegenerators -from pywikibot.page import WikibasePage, ItemPage, PropertyPage +from pywikibot.page import WikibasePage, ItemPage, PropertyPage, Page from pywikibot.site import Namespace, NamespacesDict from pywikibot.tools import MediaWikiVersion
@@ -490,6 +490,72 @@ text=None, language='sv')
+class TestWbGeoShapeNonDry(WikidataTestCase): + + """ + Test Wikibase WbGeoShape data type (non-dry). + + These require non dry tests due to the page.exists() call. + """ + + def setUp(self): + """Setup tests.""" + self.commons = pywikibot.Site('commons', 'commons') + self.page = Page(self.commons, 'Data:Lyngby Hovedgade.map') + super(TestWbGeoShapeNonDry, self).setUp() + + def test_WbGeoShape_page(self): + """Test WbGeoShape page.""" + q = pywikibot.WbGeoShape(self.page) + q_val = u'Data:Lyngby Hovedgade.map' + self.assertEqual(q.toWikibase(), q_val) + + def test_WbGeoShape_page_and_site(self): + """Test WbGeoShape from page and site.""" + q = pywikibot.WbGeoShape(self.page, self.get_repo()) + q_val = u'Data:Lyngby Hovedgade.map' + self.assertEqual(q.toWikibase(), q_val) + + def test_WbGeoShape_equality(self): + """Test WbGeoShape equality.""" + q = pywikibot.WbGeoShape(self.page, self.get_repo()) + self.assertEqual(q, q) + + def test_WbGeoShape_fromWikibase(self): + """Test WbGeoShape.fromWikibase() instantiating.""" + repo = self.get_repo() + q = pywikibot.WbGeoShape.fromWikibase( + 'Data:Lyngby Hovedgade.map', repo) + self.assertEqual(q.toWikibase(), 'Data:Lyngby Hovedgade.map') + + def test_WbGeoShape_error_on_non_page(self): + """Test WbGeoShape error handling when given a non-page.""" + self.assertRaises(ValueError, pywikibot.WbGeoShape, + 'A string', self.get_repo()) + + def test_WbGeoShape_error_on_non_exitant_page(self): + """Test WbGeoShape error handling of a non-existant page.""" + page = Page(self.commons, 'Non-existant page... really') + self.assertRaises(ValueError, pywikibot.WbGeoShape, + page, self.get_repo()) + + def test_WbGeoShape_error_on_wrong_site(self): + """Test WbGeoShape error handling of a page on non-filerepo site.""" + repo = self.get_repo() + page = Page(repo, 'Q123') + self.assertRaises(ValueError, pywikibot.WbGeoShape, + page, self.get_repo()) + + def test_WbGeoShape_error_on_wrong_page_type(self): + """Test WbGeoShape error handling of a non-map page.""" + non_data_page = Page(self.commons, 'File:Foo.jpg') + non_map_page = Page(self.commons, 'Data:Templatedata/Graph:Lines.tab') + self.assertRaises(ValueError, pywikibot.WbGeoShape, + non_data_page, self.get_repo()) + self.assertRaises(ValueError, pywikibot.WbGeoShape, + non_map_page, self.get_repo()) + + class TestItemPageExtensibility(TestCase):
"""Test ItemPage extensibility."""
pywikibot-commits@lists.wikimedia.org