jenkins-bot has submitted this change. (
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1343242?usp=email )
Change subject: Add PageViewInfo extension support
......................................................................
Add PageViewInfo extension support
Expose daily page and site view counts through the extension Action API
modules. Add a generator for the most-viewed pages.
Bug: T325473
Change-Id: If2f8459167c45b010cab9325a75313f16b33e03a
---
M pywikibot/page/_basepage.py
M pywikibot/site/_apisite.py
M pywikibot/site/_extensions.py
A tests/pageviewinfo_tests.py
4 files changed, 220 insertions(+), 0 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/page/_basepage.py b/pywikibot/page/_basepage.py
index 62cfc3a..9ebfc4f 100644
--- a/pywikibot/page/_basepage.py
+++ b/pywikibot/page/_basepage.py
@@ -2037,6 +2037,26 @@
return self._pageimage
+ def pageviews(
+ self,
+ days: int | None = None,
+ *,
+ metric: str = 'pageviews',
+ ) -> dict[str, int | None]:
+ """Return daily page views for this page.
+
+ Uses the MediaWiki extension PageViewInfo.
+
+ .. version-added:: 11.8
+
+ :param days: Number of days to return, up to the site-configured
+ maximum. If ``None``, use the site's default.
+ :param metric: Page view metric supported by the site.
+ :return: Mapping of ISO date strings to view counts. A count may
+ be ``None`` when data is unavailable.
+ """
+ return self.site.pageviews(self, days, metric=metric)
+
def getRedirectTarget(self, *,
ignore_section: bool = True) -> pywikibot.Page:
"""Return a Page object for the target this Page redirects to.
diff --git a/pywikibot/site/_apisite.py b/pywikibot/site/_apisite.py
index 7f9a4f9..c14ec44 100644
--- a/pywikibot/site/_apisite.py
+++ b/pywikibot/site/_apisite.py
@@ -56,6 +56,7 @@
GlobalUsageMixin,
LinterMixin,
PageImagesMixin,
+ PageViewInfoMixin,
ProofreadPageMixin,
TextExtractsMixin,
ThanksMixin,
@@ -110,6 +111,7 @@
GlobalUsageMixin,
LinterMixin,
PageImagesMixin,
+ PageViewInfoMixin,
ProofreadPageMixin,
TextExtractsMixin,
ThanksMixin,
diff --git a/pywikibot/site/_extensions.py b/pywikibot/site/_extensions.py
index 3a2cdec..7dfa2f9 100644
--- a/pywikibot/site/_extensions.py
+++ b/pywikibot/site/_extensions.py
@@ -238,6 +238,105 @@
self._update_page(page, query)
+class PageViewInfoMixin:
+
+ """APISite mixin for PageViewInfo extension.
+
+ .. version-added:: 11.8
+ """
+
+ @need_extension('PageViewInfo')
+ def pageviews(
+ self: BaseSiteProtocol,
+ page: pywikibot.Page,
+ days: int | None = None,
+ *,
+ metric: str = 'pageviews',
+ ) -> dict[str, int | None]:
+ """Return daily page views for *page*.
+
+ :param page: Page for which to retrieve view counts.
+ :param days: Number of days to return, up to the site-configured
+ maximum. If ``None``, use the site's default.
+ :param metric: Page view metric supported by the site.
+ :raises NoPageError: The page does not exist.
+ :return: Mapping of ISO date strings to view counts. A count may
+ be ``None`` when data is unavailable.
+ """
+ if page.namespace() >= 0 and not page.exists():
+ raise NoPageError(page)
+
+ parameters = {
+ 'titles': page.title(with_section=False),
+ 'pvipmetric': metric,
+ }
+ if days is not None:
+ parameters['pvipdays'] = days
+ query = self._generator(api.PropertyGenerator,
+ type_arg='pageviews', **parameters)
+ try:
+ pagedata = next(iter(query))
+ return pagedata['pageviews']
+ except (KeyError, StopIteration) as e:
+ raise UnexpectedAPIDataError(
+ f'PageViewInfo response contains no data for {page}'
+ ) from e
+
+ @need_extension('PageViewInfo')
+ def siteviews(
+ self: BaseSiteProtocol,
+ days: int | None = None,
+ *,
+ metric: str = 'pageviews',
+ ) -> dict[str, int | None]:
+ """Return daily view totals for this site.
+
+ :param days: Number of days to return, up to the site-configured
+ maximum. If ``None``, use the site's default.
+ :param metric: Site view metric supported by the site.
+ :return: Mapping of ISO date strings to view counts. A count may
+ be ``None`` when data is unavailable.
+ """
+ parameters = {
+ 'action': 'query',
+ 'meta': 'siteviews',
+ 'pvismetric': metric,
+ 'formatversion': 2,
+ }
+ if days is not None:
+ parameters['pvisdays'] = days
+ request = self.simple_request(**parameters)
+ try:
+ return request.submit()['query']['siteviews']
+ except KeyError as e:
+ raise UnexpectedAPIDataError(
+ 'PageViewInfo response contains no site view data'
+ ) from e
+
+ @need_extension('PageViewInfo')
+ def mostviewed(
+ self: BaseSiteProtocol,
+ total: int | None = 10,
+ *,
+ metric: str = 'pageviews',
+ ) -> Generator[tuple[pywikibot.Page, int]]:
+ """Yield the most viewed pages and their view counts.
+
+ :param total: Maximum number of pages to return, or ``None`` for
+ all available pages.
+ :param metric: Page view metric supported by the site.
+ :yield: A page and its view count for the previous day.
+ """
+ query = self._generator(
+ api.ListGenerator,
+ type_arg='mostviewed',
+ total=total,
+ pvimmetric=metric,
+ )
+ for pagedata in query:
+ yield pywikibot.Page(self, pagedata['title']), pagedata['count']
+
+
class GlobalUsageMixin:
"""APISite mixin for Global Usage extension."""
diff --git a/tests/pageviewinfo_tests.py b/tests/pageviewinfo_tests.py
new file mode 100755
index 0000000..7302fc7
--- /dev/null
+++ b/tests/pageviewinfo_tests.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+#
+# (C) Pywikibot team, 2026
+#
+# Distributed under the terms of the MIT license.
+#
+"""Tests for the PageViewInfo extension."""
+from __future__ import annotations
+
+from unittest.mock import Mock, patch
+
+import pywikibot
+from pywikibot.data import api
+from tests.aspects import DefaultSiteTestCase
+
+
+class TestPageViewInfo(DefaultSiteTestCase):
+
+ """Test PageViewInfo methods against mocked API responses."""
+
+ dry = True
+
+ def test_pageviews(self) -> None:
+ """Test retrieving views for a page."""
+ page = pywikibot.Page(self.site, 'Special:Search')
+ response = {
+ 'title': 'Special:Search',
+ 'pageviews': {'2026-09-17': 42, '2026-09-18': None},
+ }
+
+ with (
+ patch.object(self.site, 'has_extension', return_value=True),
+ patch.object(page, 'exists') as exists,
+ patch.object(self.site, '_generator') as generator,
+ ):
+ generator.return_value.__iter__.return_value = iter((response,))
+ result = page.pageviews()
+
+ self.assertEqual(result, response['pageviews'])
+ exists.assert_not_called()
+ generator.assert_called_once_with(
+ api.PropertyGenerator,
+ type_arg='pageviews',
+ titles='Special:Search',
+ pvipmetric='pageviews',
+ )
+
+ def test_siteviews(self) -> None:
+ """Test retrieving site-wide views."""
+ request = Mock()
+ response = {'2026-09-17': 42, '2026-09-18': 43}
+ request.submit.return_value = {'query': {'siteviews': response}}
+
+ with (
+ patch.object(self.site, 'has_extension', return_value=True),
+ patch.object(self.site, 'simple_request', return_value=request)
+ as simple_request,
+ ):
+ result = self.site.siteviews(days=2, metric='uniques')
+
+ self.assertEqual(result, response)
+ simple_request.assert_called_once_with(
+ action='query',
+ meta='siteviews',
+ pvisdays=2,
+ pvismetric='uniques',
+ formatversion=2,
+ )
+
+ def test_mostviewed(self) -> None:
+ """Test retrieving the most viewed pages."""
+ response = (
+ {'title': 'Main Page', 'count': 42},
+ {'title': 'Earth', 'count': 23},
+ )
+
+ with (
+ patch.object(self.site, 'has_extension', return_value=True),
+ patch.object(self.site, '_generator') as generator,
+ ):
+ generator.return_value.__iter__.return_value = iter(response)
+ result = list(self.site.mostviewed(total=2))
+
+ self.assertEqual(
+ [(page.title(), count) for page, count in result],
+ [('Main Page', 42), ('Earth', 23)],
+ )
+ generator.assert_called_once_with(
+ api.ListGenerator,
+ type_arg='mostviewed',
+ total=2,
+ pvimmetric='pageviews',
+ )
+
+
+if __name__ == '__main__':
+ import unittest
+
+ unittest.main()
--
To view, visit
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1343242?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: If2f8459167c45b010cab9325a75313f16b33e03a
Gerrit-Change-Number: 1343242
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]