jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/334908 )
Change subject: Support adding units to WbQuantity through ItemPage or entity url ......................................................................
Support adding units to WbQuantity through ItemPage or entity url
This is backwards compatible so either ItemPages or entity urls may be provided as a unit.
Provided urls are not validated (outside of limiting it to the http(s) protocols) since items need not be in the same repo as the claim.
Bug: T143594 Change-Id: I0ef7249d7a8f31ab62aa57d4f661062e889d9585 --- M pywikibot/__init__.py M tests/wikibase_edit_tests.py M tests/wikibase_tests.py 3 files changed, 183 insertions(+), 53 deletions(-)
Approvals: Dalba: Looks good to me, approved jenkins-bot: Verified
diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py index 42b93ec..0233583 100644 --- a/pywikibot/__init__.py +++ b/pywikibot/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """The initialization file for the Pywikibot framework.""" # -# (C) Pywikibot team, 2008-2016 +# (C) Pywikibot team, 2008-2017 # # Distributed under the terms of the MIT license. # @@ -23,6 +23,7 @@ if sys.version_info[0] > 2: from queue import Queue long = int + basestring = str else: from Queue import Queue
@@ -256,7 +257,7 @@ @type dim: int @param site: The Wikibase site @type site: pywikibot.site.DataSite - @param entity: The URL entity of a Wikibase item + @param entity: The URL entity of a Wikibase item for the globe @type entity: str """ self.lat = lat @@ -644,6 +645,16 @@ return None return format(value, "+g")
+ def __eq__(self, other): + """Override equality to handle different unit representations.""" + if isinstance(other, self.__class__): + self_dict = self.__dict__.copy() + other_dict = other.__dict__.copy() + self_dict['_unit'] = self.unit + other_dict['_unit'] = other.unit + return self_dict == other_dict + return NotImplemented + def __init__(self, amount, unit=None, error=None, site=None): u""" Create a new WbQuantity object. @@ -651,7 +662,9 @@ @param amount: number representing this quantity @type amount: string or Decimal. Other types are accepted, and converted via str to Decimal. - @param unit: not used (only unit-less quantities are supported) + @param unit: the Wikibase item for the unit or the URL entity of this + Wikibase item. + @type unit: pywikibot.ItemPage, str or None @param error: the uncertainty of the amount (e.g. ±1) @type error: same as amount, or tuple of two values, where the first value is the upper error and the second is the lower error value. @@ -660,11 +673,14 @@ """ if amount is None: raise ValueError('no amount given') - if unit is None: - unit = '1'
self.amount = self._todecimal(amount) - self.unit = unit + self._unit = unit + + # also allow entity urls to be provided via unit parameter + if isinstance(unit, basestring) and \ + unit.partition('://')[0] not in ('http', 'https'): + raise ValueError("'unit' must be an ItemPage or entity url.")
if error is None and not self._require_errors(site): self.upperBound = self.lowerBound = None @@ -679,6 +695,13 @@
self.upperBound = self.amount + upperError self.lowerBound = self.amount - lowerError + + @property + def unit(self): + """Return _unit's entity url or '1' if _unit is None.""" + if isinstance(self._unit, ItemPage): + return self._unit.concept_url() + return self._unit or '1'
def toWikibase(self): """ @@ -709,7 +732,11 @@ error = None if (upperBound and lowerBound) or cls._require_errors(site): error = (upperBound - amount, amount - lowerBound) - return cls(amount, wb['unit'], error, site) + if wb['unit'] == '1': + unit = None + else: + unit = wb['unit'] + return cls(amount, unit, error, site)
class WbMonolingualText(_WbRepresentation): diff --git a/tests/wikibase_edit_tests.py b/tests/wikibase_edit_tests.py index 621146b..670eab9 100644 --- a/tests/wikibase_edit_tests.py +++ b/tests/wikibase_edit_tests.py @@ -6,7 +6,7 @@ class in edit_failiure_tests.py """ # -# (C) Pywikibot team, 2014 +# (C) Pywikibot team, 2014-2017 # # Distributed under the terms of the MIT license. # @@ -224,7 +224,7 @@
def test_WbMonolingualText_edit(self): """Attempt adding a monolingual text with valid input.""" - # Clean the slate in preparation for test.""" + # Clean the slate in preparation for test. testsite = self.get_repo() item = self._clean_item(testsite, 'P271')
@@ -245,7 +245,7 @@ testsite = self.get_repo() item = self._clean_item(testsite, 'P69')
- # Make sure the wiki supports wikibase-conceptbaseuri + # Make sure the wiki supports unbound uncertainties if MediaWikiVersion(testsite.version()) < MediaWikiVersion('1.29.0-wmf.2'): raise unittest.SkipTest('Wiki version must be 1.29.0-wmf.2 or ' 'newer to support unbound uncertainties.') @@ -261,6 +261,29 @@ claim = item.claims['P69'][0] self.assertEqual(claim.getTarget(), target)
+ def test_WbQuantity_edit(self): + """Attempt adding a quantity with valid input.""" + # Clean the slate in preparation for test. + testsite = self.get_repo() + item = self._clean_item(testsite, 'P69') + + # Make sure the wiki supports wikibase-conceptbaseuri + version = testsite.version() + if MediaWikiVersion(version) < MediaWikiVersion('1.28-wmf.23'): + raise unittest.SkipTest('Wiki version must be 1.28-wmf.23 or ' + 'newer to expose wikibase-conceptbaseuri.') + + # set new claim + claim = pywikibot.page.Claim(testsite, 'P69', datatype='quantity') + target = pywikibot.WbQuantity(amount=1234, error=1, unit=item) + claim.setTarget(target) + item.addClaim(claim) + + # confirm new claim + item.get(force=True) + claim = item.claims['P69'][0] + self.assertEqual(claim.getTarget(), target) + def test_identifier_edit(self): """Attempt adding a math claim with valid input.""" testsite = self.get_repo() diff --git a/tests/wikibase_tests.py b/tests/wikibase_tests.py index 8a18771..0bf0c54 100644 --- a/tests/wikibase_tests.py +++ b/tests/wikibase_tests.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Tests for the Wikidata parts of the page module.""" # -# (C) Pywikibot team, 2008-2016 +# (C) Pywikibot team, 2008-2017 # # Distributed under the terms of the MIT license. # @@ -214,16 +214,6 @@ 'upperBound': '+0.044405586', 'unit': '1', } self.assertEqual(q.toWikibase(), q_dict)
- def test_WbQuantity_unbound(self): - """Test WbQuantity for integer value without bounds.""" - repo = self.get_repo() - if MediaWikiVersion(repo.version()) < MediaWikiVersion('1.29.0-wmf.2'): - raise unittest.SkipTest('Wiki version must be 1.29.0-wmf.2 or ' - 'newer to support unbound uncertainties.') - q = pywikibot.WbQuantity(amount=1234.5, site=repo) - self.assertEqual(q.toWikibase(), - {'amount': '+1234.5', 'unit': '1', }) - def test_WbQuantity_formatting(self): """Test other WbQuantity methods.""" q = pywikibot.WbQuantity(amount='0.044405586', error='0') @@ -237,25 +227,6 @@ self.assertEqual("%r" % q, "WbQuantity(amount=%(val)s, " "upperBound=%(val)s, lowerBound=%(val)s, " - "unit=1)" % {'val': '0.044405586'}) - - def test_WbQuantity_formatting_unbound(self): - """Test WbQuantity formatting without bounds.""" - repo = self.get_repo() - if MediaWikiVersion(repo.version()) < MediaWikiVersion('1.29.0-wmf.2'): - raise unittest.SkipTest('Wiki version must be 1.29.0-wmf.2 or ' - 'newer to support unbound uncertainties.') - q = pywikibot.WbQuantity(amount='0.044405586', site=repo) - self.assertEqual("%s" % q, - '{\n' - ' "amount": "+%(val)s",\n' - ' "lowerBound": null,\n' - ' "unit": "1",\n' - ' "upperBound": null\n' - '}' % {'val': '0.044405586'}) - self.assertEqual("%r" % q, - "WbQuantity(amount=%(val)s, " - "upperBound=None, lowerBound=None, " "unit=1)" % {'val': '0.044405586'})
def test_WbQuantity_equality(self): @@ -274,23 +245,29 @@ {'amount': '+0.0229', 'lowerBound': '+0.0000', 'upperBound': '+1.0000', 'unit': '1', })
- def test_WbQuantity_fromWikibase_unbound(self): - """Test WbQuantity.fromWikibase() instantiating without bounds.""" - repo = self.get_repo() - if MediaWikiVersion(repo.version()) < MediaWikiVersion('1.29.0-wmf.2'): - raise unittest.SkipTest('Wiki version must be 1.29.0-wmf.2 or ' - 'newer to support unbound uncertainties.') - q = pywikibot.WbQuantity.fromWikibase({u'amount': u'+0.0229', - u'unit': u'1'}, - site=repo) - self.assertEqual(q.toWikibase(), - {'amount': '+0.0229', 'lowerBound': None, - 'upperBound': None, 'unit': '1', }) - def test_WbQuantity_errors(self): """Test WbQuantity error handling.""" self.assertRaises(ValueError, pywikibot.WbQuantity, amount=None, error=1) + + def test_WbQuantity_entity_unit(self): + """Test WbQuantity with entity url unit.""" + q = pywikibot.WbQuantity(amount=1234, error=1, + unit='http://www.wikidata.org/entity/Q712226') + self.assertEqual(q.toWikibase(), + {'amount': '+1234', 'lowerBound': '+1233', + 'upperBound': '+1235', + 'unit': 'http://www.wikidata.org/entity/Q712226', }) + + def test_WbQuantity_unit_fromWikibase(self): + """Test WbQuantity recognising unit from Wikibase output.""" + q = pywikibot.WbQuantity.fromWikibase({ + 'amount': '+1234', 'lowerBound': '+1233', 'upperBound': '+1235', + 'unit': 'http://www.wikidata.org/entity/Q712226', }) + self.assertEqual(q.toWikibase(), + {'amount': '+1234', 'lowerBound': '+1233', + 'upperBound': '+1235', + 'unit': 'http://www.wikidata.org/entity/Q712226', })
def test_WbMonolingualText_string(self): """Test WbMonolingualText string.""" @@ -324,6 +301,97 @@ text='Test this!', language='') self.assertRaises(ValueError, pywikibot.WbMonolingualText, text=None, language='sv') + + +class TestWikibaseTypesNonDry(WikidataTestCase): + + """ + Test Wikibase data types (non-dry). + + These can be moved to TestWikibaseTypes once DrySite has been bumped to + the appropriate version. + """ + + def test_WbQuantity_unbound(self): + """Test WbQuantity for integer value without bounds.""" + repo = self.get_repo() + if MediaWikiVersion(repo.version()) < MediaWikiVersion('1.29.0-wmf.2'): + raise unittest.SkipTest('Wiki version must be 1.29.0-wmf.2 or ' + 'newer to support unbound uncertainties.') + q = pywikibot.WbQuantity(amount=1234.5, site=repo) + self.assertEqual(q.toWikibase(), + {'amount': '+1234.5', 'unit': '1', + 'upperBound': None, 'lowerBound': None}) + + def test_WbQuantity_formatting_unbound(self): + """Test WbQuantity formatting without bounds.""" + repo = self.get_repo() + if MediaWikiVersion(repo.version()) < MediaWikiVersion('1.29.0-wmf.2'): + raise unittest.SkipTest('Wiki version must be 1.29.0-wmf.2 or ' + 'newer to support unbound uncertainties.') + q = pywikibot.WbQuantity(amount='0.044405586', site=repo) + self.assertEqual("%s" % q, + '{\n' + ' "amount": "+%(val)s",\n' + ' "lowerBound": null,\n' + ' "unit": "1",\n' + ' "upperBound": null\n' + '}' % {'val': '0.044405586'}) + self.assertEqual("%r" % q, + "WbQuantity(amount=%(val)s, " + "upperBound=None, lowerBound=None, " + "unit=1)" % {'val': '0.044405586'}) + + def test_WbQuantity_fromWikibase_unbound(self): + """Test WbQuantity.fromWikibase() instantiating without bounds.""" + repo = self.get_repo() + if MediaWikiVersion(repo.version()) < MediaWikiVersion('1.29.0-wmf.2'): + raise unittest.SkipTest('Wiki version must be 1.29.0-wmf.2 or ' + 'newer to support unbound uncertainties.') + q = pywikibot.WbQuantity.fromWikibase({u'amount': u'+0.0229', + u'unit': u'1'}, + site=repo) + self.assertEqual(q.toWikibase(), + {'amount': '+0.0229', 'lowerBound': None, + 'upperBound': None, 'unit': '1', }) + + def test_WbQuantity_ItemPage_unit(self): + """Test WbQuantity with ItemPage unit.""" + repo = self.get_repo() + if MediaWikiVersion(repo.version()) < MediaWikiVersion('1.28-wmf.23'): + raise unittest.SkipTest('Wiki version must be 1.28-wmf.23 or ' + 'newer to expose wikibase-conceptbaseuri.') + + q = pywikibot.WbQuantity(amount=1234, error=1, + unit=pywikibot.ItemPage(repo, 'Q712226')) + self.assertEqual(q.toWikibase(), + {'amount': '+1234', 'lowerBound': '+1233', + 'upperBound': '+1235', + 'unit': 'http://www.wikidata.org/entity/Q712226', }) + + def test_WbQuantity_equality(self): + """Test WbQuantity equality with different unit representations.""" + repo = self.get_repo() + if MediaWikiVersion(repo.version()) < MediaWikiVersion('1.28-wmf.23'): + raise unittest.SkipTest('Wiki version must be 1.28-wmf.23 or ' + 'newer to expose wikibase-conceptbaseuri.') + + a = pywikibot.WbQuantity( + amount=1234, error=1, + unit=pywikibot.ItemPage(repo, 'Q712226')) + b = pywikibot.WbQuantity( + amount=1234, error=1, + unit='http://www.wikidata.org/entity/Q712226') + c = pywikibot.WbQuantity( + amount=1234, error=1, + unit='http://test.wikidata.org/entity/Q712226') + d = pywikibot.WbQuantity( + amount=1234, error=2, + unit='http://www.wikidata.org/entity/Q712226') + self.assertEqual(a, b) + self.assertNotEqual(a, c) + self.assertNotEqual(b, c) + self.assertNotEqual(b, d)
class TestItemPageExtensibility(TestCase): @@ -789,6 +857,16 @@ claim.setTarget(target) self.assertEqual(claim.target, target)
+ def test_set_WbQuantity(self): + """Test setting claim of quantity type.""" + wikidata = self.get_repo() + claim = pywikibot.Claim(wikidata, 'P1106') + self.assertEqual(claim.type, 'quantity') + target = pywikibot.WbQuantity( + amount=1234, error=1, unit='http://www.wikidata.org/entity/Q11573') + claim.setTarget(target) + self.assertEqual(claim.target, target) + def test_set_math(self): """Test setting claim of math type.""" wikidata = self.get_repo() @@ -824,6 +902,8 @@ self.assertRaises(ValueError, url_claim.setTarget, pywikibot.WbTime(2001, site=wikidata)) mono_claim = pywikibot.Claim(wikidata, 'P1450') self.assertRaises(ValueError, mono_claim.setTarget, 'foo') + quantity_claim = pywikibot.Claim(wikidata, 'P1106') + self.assertRaises(ValueError, quantity_claim.setTarget, 'foo')
class TestItemBasePageMethods(WikidataTestCase, BasePageMethodsTestBase):
pywikibot-commits@lists.wikimedia.org