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

Change subject: Add Citoid API to pywikibot
......................................................................

Add Citoid API to pywikibot

Bug: T401690
Change-Id: I272a838d604967d8b84c70a03c92e1f4aaa91029
Signed-off-by: Strainu <[email protected]>
---
A pywikibot/data/citoid.py
M pywikibot/exceptions.py
M pywikibot/families/wikipedia_family.py
A tests/citoid_tests.py
4 files changed, 127 insertions(+), 0 deletions(-)

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




diff --git a/pywikibot/data/citoid.py b/pywikibot/data/citoid.py
new file mode 100644
index 0000000..ee4a930
--- /dev/null
+++ b/pywikibot/data/citoid.py
@@ -0,0 +1,59 @@
+"""Superset Query interface.
+
+.. versionadded:: 10.6
+"""
+#
+# (C) Pywikibot team, 2025
+#
+# Distributed under the terms of the MIT license.
+#
+from __future__ import annotations
+
+import urllib.parse
+
+import pywikibot
+from pywikibot.comms import http
+from pywikibot.exceptions import ApiNotAvailableError, Error
+from pywikibot.site import BaseSite
+
+
+VALID_FORMAT = [
+    'mediawiki', 'wikibase', 'zotero', 'bibtex', 'mediawiki-basefields'
+]
+
+
+class CitoidClient:
+
+    """Citoid client class.
+
+    This class allows to call the Citoid API used in production.
+    """
+
+    def __init__(self, site: BaseSite):
+        """Initialize the CitoidClient."""
+        self.site = site
+
+    def get_citation(self, response_format: str, ref_url: str) -> dict:
+        """Get a citation from the citoid service.
+
+        :param response_format: Return format, e.g. 'bibtex', 'wikibase', etc.
+        :param ref_url: The URL to get the citation for.
+        :return: A dictionary with the citation data.
+        """
+        if response_format not in VALID_FORMAT:
+            raise ValueError(f'Invalid format {response_format}, '
+                             f'must be one of {VALID_FORMAT}')
+        if (not hasattr(self.site.family, 'citoid_endpoint')
+                or not self.site.family.citoid_endpoint):
+            raise ApiNotAvailableError(
+                f'Citoid endpoint not configured for {self.site.family.name}')
+        base_url = self.site.family.citoid_endpoint
+        ref_url = urllib.parse.quote(ref_url, safe='')
+        api_url = urllib.parse.urljoin(base_url,
+                                       f'{response_format}/{ref_url}')
+        try:
+            json = http.request(self.site, api_url).json()
+            return json
+        except Error as e:
+            pywikibot.log(f'Caught pywikibot error {e}')
+            raise
diff --git a/pywikibot/exceptions.py b/pywikibot/exceptions.py
index 00f1a26..d1a095a 100644
--- a/pywikibot/exceptions.py
+++ b/pywikibot/exceptions.py
@@ -728,6 +728,11 @@
     """Request failed with a maxlag timeout error."""


+class ApiNotAvailableError(Error):
+
+    """API is not available, e.g. due to a network error or configuration."""
+
+
 wrapper = ModuleDeprecationWrapper(__name__)
 wrapper.add_deprecated_attr(
     'Server414Error', Client414Error, since='8.1.0')
diff --git a/pywikibot/families/wikipedia_family.py 
b/pywikibot/families/wikipedia_family.py
index cb80610..8f960fe 100644
--- a/pywikibot/families/wikipedia_family.py
+++ b/pywikibot/families/wikipedia_family.py
@@ -223,6 +223,8 @@
         'ro': ('Arhivă',),
     }

+    citoid_endpoint = '/api/rest_v1/data/citation/'
+
     @classmethod
     def __post_init__(cls) -> None:
         """Add 'yue' code alias due to :phab:`T341960`.
diff --git a/tests/citoid_tests.py b/tests/citoid_tests.py
new file mode 100755
index 0000000..b4a6c96
--- /dev/null
+++ b/tests/citoid_tests.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+"""Unit tests for citoid script."""
+#
+# (C) Pywikibot team, 2025
+#
+# Distributed under the terms of the MIT license.
+#
+from __future__ import annotations
+
+import datetime
+
+import pywikibot
+from pywikibot.data import citoid
+from pywikibot.exceptions import ApiNotAvailableError
+from tests.aspects import TestCase
+
+
+class TestCitoid(TestCase):
+
+    """Test the Citoid client."""
+
+    family = 'wikipedia'
+    code = 'test'
+    login = False
+
+    def test_citoid_positive(self):
+        """Test citoid script."""
+        client = citoid.CitoidClient(self.site)
+        resp = client.get_citation(
+            'mediawiki',
+            'https://ro.wikipedia.org/wiki/România'
+        )
+        self.assertLength(resp, 1)
+        self.assertEqual(resp[0]['title'], 'România')
+        self.assertEqual(
+            resp[0]['rights'],
+            'Creative Commons Attribution-ShareAlike License'
+        )
+        self.assertIsNotEmpty(resp[0]['url'])
+        self.assertEqual(
+            resp[0]['accessDate'],
+            datetime.datetime.now().strftime('%Y-%m-%d')
+        )
+
+    def test_citoid_no_config(self):
+        """Test citoid script with no citoid endpoint configured."""
+        client = citoid.CitoidClient(pywikibot.Site('pl', 'wikiquote'))
+        with self.assertRaises(ApiNotAvailableError):
+            client.get_citation(
+                'mediawiki',
+                'https://ro.wikipedia.org/wiki/România'
+            )
+
+    def test_citoid_no_valid_format(self):
+        """Test citoid script with invalid format provided."""
+        client = citoid.CitoidClient(self.site)
+        with self.assertRaises(ValueError):
+            client.get_citation(
+                'mediawiki2',
+                'https://ro.wikipedia.org/wiki/România'
+            )

--
To view, visit 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1195215?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: I272a838d604967d8b84c70a03c92e1f4aaa91029
Gerrit-Change-Number: 1195215
Gerrit-PatchSet: 8
Gerrit-Owner: Strainu <[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