jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/626640 )
Change subject: [IMPR] Load entities when necessary ......................................................................
[IMPR] Load entities when necessary
Wikibase entities are now loaded when their data attributes are accessed. Calling WikibaseEntity.get isn't necessary anymore (analogous to BasePage.get and BasePage.text).
New empty entities have special handling. Expand tests accordingly.
Bug: T245809 Change-Id: I45202d0c4fd882b5bff3c66e8dd69e36ee303f3f --- M pywikibot/page/__init__.py M tests/wikibase_tests.py 2 files changed, 72 insertions(+), 7 deletions(-)
Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
diff --git a/pywikibot/page/__init__.py b/pywikibot/page/__init__.py index e6dbf17..2e1dd67 100644 --- a/pywikibot/page/__init__.py +++ b/pywikibot/page/__init__.py @@ -3316,6 +3316,10 @@ this = cls({key: value['value'] for key, value in data.items()}) return this
+ @classmethod + def new_empty(cls, repo): + return cls() + def __getitem__(self, key): key = self.normalizeKey(key) return self._data[key] @@ -3393,6 +3397,10 @@ this[key] = [val['value'] for val in value] return this
+ @classmethod + def new_empty(cls, repo): + return cls() + def __getitem__(self, key): key = LanguageDict.normalizeKey(key) return self._data[key] @@ -3463,6 +3471,10 @@ this[key] = [Claim.fromJSON(repo, claim) for claim in claims] return this
+ @classmethod + def new_empty(cls, repo): + return cls(repo) + def __getitem__(self, key): return self._data[key]
@@ -3552,6 +3564,16 @@ if data: self.update(data)
+ @classmethod + def new_empty(cls, repo): + """Construct a new empty SiteLinkCollection.""" + return cls(repo) + + @classmethod + def fromJSON(cls, data, repo): + """Construct a new SiteLinkCollection from JSON.""" + return cls(repo, data) + @staticmethod def getdbName(site): """ @@ -3607,11 +3629,6 @@ return key in self._data
@classmethod - def fromJSON(cls, data, repo): - """Construct a new SiteLinkCollection from JSON.""" - return cls(repo, data) - - @classmethod def _extract_JSON(cls, obj): if isinstance(obj, SiteLink): return obj.toJSON() @@ -3756,6 +3773,17 @@ # todo: use re.fullmatch when Python 3.4+ required return bool(re.match(cls.title_pattern + '$', entity_id))
+ def __getattr__(self, name): + if name in self.DATA_ATTRIBUTES: + if self.getID() == '-1': + for key, cls in self.DATA_ATTRIBUTES.items(): + setattr(self, key, cls.new_empty(self.repo)) + return getattr(self, name) + else: + return self.get()[name] + + return super().__getattr__(name) + def _defined_by(self, singular: bool = False) -> dict: """ Internal function to provide the API parameters to identify the entity. @@ -3866,6 +3894,8 @@ raise pywikibot.NoWikibaseEntity(self)
data = {} + # todo: this initializes all data, + # make use of lazy initialization (T245809) for key, cls in self.DATA_ATTRIBUTES.items(): value = cls.fromJSON(self._content.get(key, {}), self.repo) setattr(self, key, value) diff --git a/tests/wikibase_tests.py b/tests/wikibase_tests.py index 7c24600..fdae3c1 100644 --- a/tests/wikibase_tests.py +++ b/tests/wikibase_tests.py @@ -55,6 +55,19 @@ self.assertLength(set(list_of_dupes), 1)
+class DataCollectionTestCase(WikidataTestCase): + + """Test case for a Wikibase collection class.""" + + collection_class = None + + def test_new_empty(self): + """Test that new_empty method returns empty collection.""" + cls = self.collection_class + result = cls.new_empty(self.get_repo()) + self.assertLength(result, 0) + + class TestLoadRevisionsCaching(BasePageLoadRevisionsCachingTestBase, WikidataTestCase):
@@ -949,6 +962,19 @@ item.get() self.assertTrue(hasattr(item, '_content'))
+ def test_item_lazy_initialization(self): + """Test that Wikibase items are properly initialized lazily.""" + wikidata = self.get_repo() + item = ItemPage(wikidata, 'Q60') + attrs = ['_content', 'labels', 'descriptions', 'aliases', + 'claims', 'sitelinks'] + for attr in attrs: + self.assertFalse(hasattr(item, attr)) + + item.labels # trigger loading + for attr in attrs: + self.assertTrue(hasattr(item, attr)) + def test_load_item_set_id(self): """Test setting item.id attribute on empty item.""" wikidata = self.get_repo() @@ -1001,6 +1027,11 @@ wikidata = self.get_repo() item = ItemPage(wikidata) self.assertEqual(item._link._title, '-1') + self.assertLength(item.labels, 0) + self.assertLength(item.descriptions, 0) + self.assertLength(item.aliases, 0) + self.assertLength(item.claims, 0) + self.assertLength(item.sitelinks, 0)
def test_item_invalid_titles(self): """Test invalid titles of wikibase items.""" @@ -1758,10 +1789,12 @@ self.assertLength(wvlinks, 2)
-class TestLanguageDict(TestCase): +class TestLanguageDict(DataCollectionTestCase):
"""Test cases covering LanguageDict methods."""
+ collection_class = LanguageDict + family = 'wikipedia' code = 'en'
@@ -1833,10 +1866,12 @@ {'en': {'language': 'en', 'value': 'foo'}})
-class TestAliasesDict(TestCase): +class TestAliasesDict(DataCollectionTestCase):
"""Test cases covering AliasesDict methods."""
+ collection_class = AliasesDict + family = 'wikipedia' code = 'en'
pywikibot-commits@lists.wikimedia.org