jenkins-bot submitted this change.

View Change

Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
[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(-)

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'


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

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