jenkins-bot has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1333925?usp=email )

Change subject: pagegenerators: Support selective page preloading
......................................................................

pagegenerators: Support selective page preloading

Forward opt-in page properties through the shared preload generators and add
batched GeoData support to APISite.preloadpages.

Use it in coordinate_import and illustrate_wikidata to batch the properties
they consume without loading unused page content.

Change-Id: I5bc293683b322e16c70eb7ac1db47ec021a81f43
---
M pywikibot/data/api/_generators.py
M pywikibot/pagegenerators/__init__.py
M pywikibot/site/_generators.py
M scripts/coordinate_import.py
M scripts/illustrate_wikidata.py
M tests/pagegenerators_tests.py
M tests/site_generators_tests.py
7 files changed, 141 insertions(+), 16 deletions(-)

Approvals:
  Xqt: Looks good to me, approved
  jenkins-bot: Verified




diff --git a/pywikibot/data/api/_generators.py 
b/pywikibot/data/api/_generators.py
index 002b35c..fcbf3d0 100644
--- a/pywikibot/data/api/_generators.py
+++ b/pywikibot/data/api/_generators.py
@@ -1122,11 +1122,13 @@

     props = props or []

-    # test for pagedict content only and call updater function
-    for element in ('coordinates', 'revisions'):
-        if element in pagedict:
-            updater = globals()['_update_' + element]
-            updater(page, pagedict[element])
+    if 'coordinates' in pagedict:
+        _update_coordinates(page, pagedict['coordinates'])
+    elif 'coordinates' in props:
+        page._coords = []
+
+    if 'revisions' in pagedict:
+        _update_revisions(page, pagedict['revisions'])

     # test for pagedict and props contents, call updater or set attribute
     for element in ('categories', 'langlinks', 'templates'):
diff --git a/pywikibot/pagegenerators/__init__.py 
b/pywikibot/pagegenerators/__init__.py
index 06acdec..eacee9b 100644
--- a/pywikibot/pagegenerators/__init__.py
+++ b/pywikibot/pagegenerators/__init__.py
@@ -670,17 +670,49 @@
         yield from reversed(list(filtered_generator()))


-def PreloadingGenerator(generator: Iterable[pywikibot.page.Page],
-                        groupsize: int = 50,
-                        quiet: bool = False
-                        ) -> Generator[pywikibot.page.Page]:
+def PreloadingGenerator(
+    generator: Iterable[pywikibot.page.Page],
+    groupsize: int = 50,
+    quiet: bool = False,
+    *,
+    templates: bool = False,
+    langlinks: bool = False,
+    pageprops: bool = False,
+    categories: bool = False,
+    content: bool = True,
+    coordinates: bool = False,
+) -> Generator[pywikibot.page.Page]:
     """Yield preloaded pages taken from another generator.

+    .. version-changed:: 11.8
+       Optional page properties can be selected for preloading.
+
     :param generator: Pages to iterate over
     :param groupsize: How many pages to preload at once
     :param quiet: If False (default), show the "Retrieving pages"
         message
+    :param templates: Preload transcluded pages
+    :param langlinks: Preload language links
+    :param pageprops: Preload page properties
+    :param categories: Preload page categories
+    :param content: Preload page content
+    :param coordinates: Preload page coordinates when the GeoData
+        extension is available
     """
+    preload_options = {}
+    if templates:
+        preload_options['templates'] = True
+    if langlinks:
+        preload_options['langlinks'] = True
+    if pageprops:
+        preload_options['pageprops'] = True
+    if categories:
+        preload_options['categories'] = True
+    if not content:
+        preload_options['content'] = False
+    if coordinates:
+        preload_options['coordinates'] = True
+
     # pages may be on more than one site, for example if an interwiki
     # generator is used, so use a separate preloader for each site
     sites: PRELOAD_SITE_TYPE = {}
@@ -694,26 +726,43 @@
             # if this site is at the groupsize, process it
             group = sites.pop(site)
             yield from site.preloadpages(group, groupsize=site_groupsize,
-                                         quiet=quiet)
+                                         quiet=quiet, **preload_options)

     for site, pages in sites.items():
         # process any leftover sites that never reached the groupsize
         site_groupsize = min(groupsize, site.maxlimit)
         yield from site.preloadpages(pages, groupsize=site_groupsize,
-                                     quiet=quiet)
+                                     quiet=quiet, **preload_options)


 def DequePreloadingGenerator(
     generator: DequeGenerator,
     groupsize: int = 50,
     quiet: bool = False,
+    *,
+    templates: bool = False,
+    langlinks: bool = False,
+    pageprops: bool = False,
+    categories: bool = False,
+    content: bool = True,
+    coordinates: bool = False,
 ) -> Generator[pywikibot.page.Page]:
     """Preload generator of type DequeGenerator.

+    .. version-changed:: 11.8
+       Optional page properties can be selected for preloading.
+
     :param generator: Pages to iterate over
     :param groupsize: How many pages to preload at once
     :param quiet: If False (default), show the "Retrieving pages"
         message
+    :param templates: Preload transcluded pages
+    :param langlinks: Preload language links
+    :param pageprops: Preload page properties
+    :param categories: Preload page categories
+    :param content: Preload page content
+    :param coordinates: Preload page coordinates when the GeoData
+        extension is available
     """
     assert isinstance(generator, DequeGenerator), \
         'generator must be a DequeGenerator object'
@@ -723,7 +772,17 @@
         if not page_count:
             return

-        yield from PreloadingGenerator(generator, page_count, quiet)
+        yield from PreloadingGenerator(
+            generator,
+            page_count,
+            quiet,
+            templates=templates,
+            langlinks=langlinks,
+            pageprops=pageprops,
+            categories=categories,
+            content=content,
+            coordinates=coordinates,
+        )


 def PreloadingEntityGenerator(
diff --git a/pywikibot/site/_generators.py b/pywikibot/site/_generators.py
index 4667fe9..ff1a48e 100644
--- a/pywikibot/site/_generators.py
+++ b/pywikibot/site/_generators.py
@@ -132,6 +132,7 @@
         pageprops: bool = False,
         categories: bool = False,
         content: bool = True,
+        coordinates: bool = False,
         quiet: bool = True,
     ) -> Generator[pywikibot.Page]:
         """Return a generator to a list of preloaded pages.
@@ -148,6 +149,8 @@
            *groupsize* is maxlimit by default. *quiet* parameter was
            added. No longer show the "Retrieving pages from site"
            message by default.
+        .. version-changed:: 11.8
+           *coordinates* parameter was added.

         :param pagelist: An iterable that returns Page objects
         :param groupsize: How many Pages to query at a time. If None
@@ -161,6 +164,8 @@
             content
         :param categories: Preload page categories
         :param content: Preload page content
+        :param coordinates: Preload page coordinates when the GeoData
+            extension is available
         :param quiet: If True (default), do not show the "Retrieving
             pages" message
         """
@@ -173,6 +178,9 @@
             props += '|pageprops'
         if categories:
             props += '|categories'
+        coordinates = coordinates and self.has_extension('GeoData')
+        if coordinates:
+            props += '|coordinates'

         groupsize_ = min(groupsize or self.maxlimit, self.maxlimit)
         for batch in batched(pagelist, groupsize_):
@@ -200,6 +208,10 @@
             else:
                 rvgen.request['titles'] = list(cache.keys())
             rvgen.request['rvprop'] = self._rvprops(content=content)
+            if coordinates:
+                rvgen.request['coprop'] = [
+                    'type', 'name', 'dim', 'country', 'region', 'globe']
+                rvgen.request['coprimary'] = 'all'
             if not quiet:
                 pywikibot.info(f'Retrieving {len(cache)} pages from {self}.')

diff --git a/scripts/coordinate_import.py b/scripts/coordinate_import.py
index e71c9ac..96a19f7 100755
--- a/scripts/coordinate_import.py
+++ b/scripts/coordinate_import.py
@@ -167,9 +167,10 @@
         if arg == '-create':
             create_new = True

-    # FIXME: this preloading preloads neither coordinates nor Wikibase items
-    # but preloads wikitext which we don't need
-    generator = generator_factory.getCombinedGenerator(preload=True)
+    generator = generator_factory.getCombinedGenerator()
+    if generator is not None and not generator_factory.nopreload:
+        generator = pagegenerators.PreloadingGenerator(
+            generator, quiet=True, content=False, coordinates=True)
     coordbot = CoordImportRobot(generator=generator, create=create_new)
     coordbot.run()

diff --git a/scripts/illustrate_wikidata.py b/scripts/illustrate_wikidata.py
index 6a36693..df73210 100755
--- a/scripts/illustrate_wikidata.py
+++ b/scripts/illustrate_wikidata.py
@@ -101,7 +101,11 @@
         else:
             generator_factory.handle_arg(arg)

-    options['generator'] = generator_factory.getCombinedGenerator(preload=True)
+    generator = generator_factory.getCombinedGenerator()
+    if generator is not None and not generator_factory.nopreload:
+        generator = pagegenerators.PreloadingGenerator(
+            generator, quiet=True, content=False, pageprops=True)
+    options['generator'] = generator
     bot = IllustrateRobot(**options)
     bot.run()

diff --git a/tests/pagegenerators_tests.py b/tests/pagegenerators_tests.py
index 29b7f4f..69dba1f 100755
--- a/tests/pagegenerators_tests.py
+++ b/tests/pagegenerators_tests.py
@@ -679,6 +679,20 @@
         high_site.preloadpages.assert_called_once_with(
             high_pages, groupsize=5, quiet=False)

+    def test_preload_options(self) -> None:
+        """Test that preload options are passed to the site."""
+        site = mock.Mock(maxlimit=5)
+        site.preloadpages.side_effect = lambda pages, **kwargs: iter(pages)
+        page = mock.Mock(site=site)
+
+        pages = list(PreloadingGenerator(
+            [page], content=False, coordinates=True, pageprops=True))
+
+        self.assertEqual(pages, [page])
+        site.preloadpages.assert_called_once_with(
+            [page], groupsize=5, quiet=False, pageprops=True,
+            content=False, coordinates=True)
+

 class TestPreloadingGenerator(DefaultSiteTestCase):

diff --git a/tests/site_generators_tests.py b/tests/site_generators_tests.py
index fb753a9..da7f393 100755
--- a/tests/site_generators_tests.py
+++ b/tests/site_generators_tests.py
@@ -138,6 +138,39 @@

         set_query_increment.assert_called_once_with(5)

+    def test_preloadpages_coordinates(self) -> None:
+        """Test that coordinate preloading populates an empty cache."""
+        page = pywikibot.Page(self.site, 'Main Page')
+        pagedata = {'title': page.title(), 'ns': 0, 'pageid': 1}
+
+        with (
+            patch.object(type(self.site), 'maxlimit', 50),
+            patch.object(self.site, 'has_extension', return_value=True),
+            patch.object(self.site, '_rvprops', return_value=['ids'])
+            as rvprops,
+            patch.object(api, 'PropertyGenerator') as generator,
+        ):
+            rvgen = generator.return_value
+            rvgen.request = {}
+            rvgen.props = frozenset(
+                {'revisions', 'info', 'categoryinfo', 'coordinates'})
+            rvgen.__iter__.return_value = iter((pagedata,))
+
+            pages = list(self.site.preloadpages(
+                [page], content=False, coordinates=True))
+
+        self.assertEqual(pages, [page])
+        generator.assert_called_once_with(
+            'revisions|info|categoryinfo|coordinates', site=self.site)
+        self.assertEqual(
+            rvgen.request['coprop'],
+            ['type', 'name', 'dim', 'country', 'region', 'globe'])
+        self.assertEqual(rvgen.request['coprimary'], 'all')
+        rvprops.assert_called_once_with(content=False)
+        with patch.object(self.site, 'loadcoordinfo') as loadcoordinfo:
+            self.assertEqual(page.coordinates(), [])
+        loadcoordinfo.assert_not_called()
+

 class TestSiteGenerators(DefaultSiteTestCase):


--
To view, visit 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1333925?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.wikimedia.org/r/settings?usp=email

Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I5bc293683b322e16c70eb7ac1db47ec021a81f43
Gerrit-Change-Number: 1333925
Gerrit-PatchSet: 2
Gerrit-Owner: Mahveotm <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to