Xqt has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1307599?usp=email )

Change subject: Rename TimeoutError to ApiTimeoutError, keep old name as 
deprecated alias
......................................................................

Rename TimeoutError to ApiTimeoutError, keep old name as deprecated alias

Bug: T431174
Change-Id: Ie36effbc761510c1b1a9efffe0d1dbd2087a652b
---
M ROADMAP.rst
M pywikibot/data/__init__.py
M pywikibot/exceptions.py
M pywikibot/page/_toolforge.py
M tests/__init__.py
A tests/exceptions_tests.py
M tests/page_tests.py
M tests/site_generators_tests.py
M tests/sparql_tests.py
9 files changed, 105 insertions(+), 18 deletions(-)

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




diff --git a/ROADMAP.rst b/ROADMAP.rst
index 7d1d12e..f7d7322 100644
--- a/ROADMAP.rst
+++ b/ROADMAP.rst
@@ -1,6 +1,7 @@
 Release 11.5
 ============

+* Rename :exc:`exceptions.TimeoutError` exception to 
:class:`exceptions.ApiTimeoutError` to avoid collision with Python's built-in 
exception (:phab:`T431174`)
 * Drop :mod:`config` ``textfile_encoding`` variable and use 'utf-8' directly 
instead (:phab:`T430454`)
 * Use pyclean package with :mod:`make_dist` script.
 * Fix redirected link for :class:`pagegenerators.PetScanPageGenerator`
@@ -107,6 +108,7 @@
 Pending removal in Pywikibot 14
 -------------------------------

+* 11.5.0: :exc:`exceptions.TimeoutError` is deprecated in favour of 
:class:`exceptions.ApiTimeoutError`
 * 11.5.0: :mod:`config` ``textfile_encoding`` variable will be removed; use 
'utf-8' directly instead
   (:phab:`T430454`)
 * 11.4.0: The signature of :meth:`APISite.allusers()
diff --git a/pywikibot/data/__init__.py b/pywikibot/data/__init__.py
index aa58b00..19270cc 100644
--- a/pywikibot/data/__init__.py
+++ b/pywikibot/data/__init__.py
@@ -44,7 +44,7 @@
             self.current_retries += 1

         if self.current_retries > self.max_retries:
-            raise pywikibot.exceptions.TimeoutError(
+            raise pywikibot.exceptions.ApiTimeoutError(
                 'Maximum retries attempted without success.')

         # double the next wait, but do not exceed config.retry_max seconds
diff --git a/pywikibot/exceptions.py b/pywikibot/exceptions.py
index 7c00ac5..7aa1831 100644
--- a/pywikibot/exceptions.py
+++ b/pywikibot/exceptions.py
@@ -54,7 +54,7 @@
           +-- SiteDefinitionError
           |    +-- UnknownFamilyError
           |    +-- UnknownSiteError
-          +-- TimeoutError
+          +-- ApiTimeoutError
           |    +-- MaxlagTimeoutError
           +-- TranslationError
           +-- UserRightsError
@@ -143,7 +143,7 @@
   - CoordinateGlobeUnknownError: globe is not implemented yet.
   - EntityTypeUnknownError: entity type is not available on the site.

-TimeoutError: request failed with a timeout
+ApiTimeoutError: request failed with a timeout

   - MaxlagTimeoutError: request failed with a maxlag timeout

@@ -182,7 +182,10 @@
 from typing import Any

 import pywikibot
-from pywikibot.tools._deprecate import _NotImplementedWarning
+from pywikibot.tools._deprecate import (
+    ModuleDeprecationWrapper,
+    _NotImplementedWarning,
+)


 class NotImplementedWarning(_NotImplementedWarning):
@@ -720,12 +723,12 @@
     """The requested entity type is not recognised on this site."""


-class TimeoutError(Error):
+class ApiTimeoutError(Error):

     """Request failed with a timeout error."""


-class MaxlagTimeoutError(TimeoutError):
+class MaxlagTimeoutError(ApiTimeoutError):

     """Request failed with a maxlag timeout error."""

@@ -733,3 +736,11 @@
 class ApiNotAvailableError(Error):

     """API is not available, e.g. due to a network error or configuration."""
+
+
+wrapper = ModuleDeprecationWrapper(__name__)
+wrapper.add_deprecated_attr(
+    'TimeoutError',
+    replacement=ApiTimeoutError,
+    since='11.5.0',
+)
diff --git a/pywikibot/page/_toolforge.py b/pywikibot/page/_toolforge.py
index 84437b0..1e2426e 100644
--- a/pywikibot/page/_toolforge.py
+++ b/pywikibot/page/_toolforge.py
@@ -72,7 +72,7 @@
         :raise NotImplementedError: unsupported site or unsupported
             namespace.
         :raise NoPageError: The page does not exist.
-        :raise TimeoutError: WikiHistory timeout
+        :raise ApiTimeoutError: WikiHistory timeout
         """
         return collections.Counter(
             {user: int(cnt) for user, (_, cnt) in self.authorship(5).items()})
@@ -166,7 +166,7 @@
         :raise NotImplementedError: unsupported site or unsupported
             namespace.
         :raise NoPageError: The page does not exist.
-        :raise TimeoutError: WikiHistory timeout
+        :raise ApiTimeoutError: WikiHistory timeout
         """
         if n and n > 5:
             warn('Only the first 5 authors can be given.', stacklevel=2)
@@ -190,7 +190,7 @@

             pywikibot.sleep(pywikibot.config.retry_wait)
         else:
-            raise pywikibot.exceptions.TimeoutError('WikiHistory Timeout')
+            raise pywikibot.exceptions.ApiTimeoutError('WikiHistory Timeout')

         length = len(self.text)
         result: list[list[str]] = []
diff --git a/tests/__init__.py b/tests/__init__.py
index 7c1fb7d..851a402 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -81,6 +81,7 @@
     'echo',
     'edit',
     'edit_failure',
+    'exceptions',
     'eventstreams',
     'family',
     'file',
diff --git a/tests/exceptions_tests.py b/tests/exceptions_tests.py
new file mode 100755
index 0000000..96d1925
--- /dev/null
+++ b/tests/exceptions_tests.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+#
+# (C) Pywikibot team, 2026
+#
+# Distributed under the terms of the MIT license.
+#
+"""Tests for the exceptions module."""
+from __future__ import annotations
+
+import unittest
+from contextlib import suppress
+
+import pywikibot
+from pywikibot.exceptions import ApiTimeoutError, Error, MaxlagTimeoutError
+from tests.aspects import DeprecationTestCase, TestCase
+
+
+class TestApiTimeoutError(TestCase):
+
+    """Test ApiTimeoutError exceptions."""
+
+    net = False
+
+    def test_hierarchy(self) -> None:
+        """Test inheritance hierarchy."""
+        self.assertTrue(issubclass(ApiTimeoutError, Error))
+        self.assertTrue(issubclass(MaxlagTimeoutError, ApiTimeoutError))
+
+    def test_raise_catch(self) -> None:
+        """Test raising and catching ApiTimeoutError."""
+        with self.assertRaises(ApiTimeoutError):
+            raise ApiTimeoutError('Test timeout')
+
+        with self.assertRaises(ApiTimeoutError):
+            raise MaxlagTimeoutError('Test maxlag timeout')
+
+
+class TestTimeoutErrorDeprecation(DeprecationTestCase):
+
+    """Test deprecation of TimeoutError alias."""
+
+    net = False
+
+    def test_deprecation(self) -> None:
+        """Test that accessing TimeoutError triggers a deprecation warning."""
+        # Accessing the deprecated attribute
+        exc_class = pywikibot.exceptions.TimeoutError
+        self.assertIs(exc_class, ApiTimeoutError)
+        self.assertOneDeprecationParts(
+            'pywikibot.exceptions.TimeoutError',
+            'pywikibot.exceptions.ApiTimeoutError'
+        )
+
+    def test_raise_catch_deprecated(self) -> None:
+        """Test raising and catching using the deprecated alias."""
+        # Reset any messages from previous tests
+        self._reset_messages()
+
+        # Catch ApiTimeoutError using the TimeoutError alias
+        try:
+            raise ApiTimeoutError('Test raise')
+        except pywikibot.exceptions.TimeoutError:
+            pass
+
+        self.assertOneDeprecationParts(
+            'pywikibot.exceptions.TimeoutError',
+            'pywikibot.exceptions.ApiTimeoutError'
+        )
+
+
+if __name__ == '__main__':
+    with suppress(SystemExit):
+        unittest.main()
diff --git a/tests/page_tests.py b/tests/page_tests.py
index 8309042..2aef677 100755
--- a/tests/page_tests.py
+++ b/tests/page_tests.py
@@ -19,13 +19,13 @@
 from pywikibot import config
 from pywikibot.exceptions import (
     APIError,
+    ApiTimeoutError,
     Error,
     InvalidTitleError,
     IsNotRedirectPageError,
     IsRedirectPageError,
     NoPageError,
     SectionError,
-    TimeoutError,
     UnknownExtensionError,
 )
 from pywikibot.tools import suppress_warnings
@@ -523,7 +523,7 @@
         for p in mainpage.backlinks(follow_redirects=False, total=10):
             self.assertIsInstance(p, pywikibot.Page)

-        with skipping(TimeoutError):
+        with skipping(ApiTimeoutError):
             for p in mainpage.embeddedin(total=10):
                 self.assertIsInstance(p, pywikibot.Page)

diff --git a/tests/site_generators_tests.py b/tests/site_generators_tests.py
index 2e8676e..4f4feb3 100755
--- a/tests/site_generators_tests.py
+++ b/tests/site_generators_tests.py
@@ -15,11 +15,11 @@
 from pywikibot.data import api
 from pywikibot.exceptions import (
     APIError,
+    ApiTimeoutError,
     Error,
     HiddenKeyError,
     InvalidTitleError,
     NoPageError,
-    TimeoutError,
 )
 from pywikibot.tools import suppress_warnings
 from tests import WARN_SITE_CODE, unittest_print
@@ -65,7 +65,7 @@
         """Test Site.pagereferences."""
         # pagereferences includes both backlinks and embeddedin
         backlinks = set(self.site.pagebacklinks(self.mainpage, namespaces=[0]))
-        with skipping(TimeoutError):
+        with skipping(ApiTimeoutError):
             embedded = set(self.site.page_embeddedin(self.mainpage,
                                                      namespaces=[0]))
         refs = set(self.site.pagereferences(self.mainpage, namespaces=[0]))
@@ -105,7 +105,7 @@

     def test_embeddedin(self) -> None:
         """Test Site.page_embeddedin."""
-        with skipping(TimeoutError):
+        with skipping(ApiTimeoutError):
             embedded_ns_0 = set(self.site.page_embeddedin(
                 self.mainpage, namespaces=[0]))
             embedded_ns_0_2 = set(self.site.page_embeddedin(
diff --git a/tests/sparql_tests.py b/tests/sparql_tests.py
index 6ae2d13..ffb985f 100755
--- a/tests/sparql_tests.py
+++ b/tests/sparql_tests.py
@@ -109,7 +109,7 @@
         """Test SELECT query."""
         mock_method.return_value = Container(
             SQL_RESPONSE_CONTAINER % f'{ITEM_Q498787}, {ITEM_Q677525}')
-        with skipping(pywikibot.exceptions.TimeoutError):
+        with skipping(pywikibot.exceptions.ApiTimeoutError):
             q = sparql.SparqlQuery()
         res = q.select('SELECT * WHERE { ?x ?y ?z }')
         self.assertIsInstance(res, list, 'Result is not a list')
@@ -131,7 +131,7 @@
         """Test SELECT query with full data."""
         mock_method.return_value = Container(
             SQL_RESPONSE_CONTAINER % f'{ITEM_Q498787}, {ITEM_Q677525}')
-        with skipping(pywikibot.exceptions.TimeoutError):
+        with skipping(pywikibot.exceptions.ApiTimeoutError):
             q = sparql.SparqlQuery()
         res = q.select('SELECT * WHERE { ?x ?y ?z }', full_data=True)
         self.assertIsInstance(res, list, 'Result is not a list')
@@ -162,7 +162,7 @@
             SQL_RESPONSE_CONTAINER % (f'{ITEM_Q498787}, {ITEM_Q677525}, '
                                       f'{ITEM_Q677525}')
         )
-        with skipping(pywikibot.exceptions.TimeoutError):
+        with skipping(pywikibot.exceptions.ApiTimeoutError):
             q = sparql.SparqlQuery()
         res = q.get_items('SELECT * WHERE { ?x ?y ?z }', 'cat')
         self.assertEqual(res, {'Q498787', 'Q677525'})
@@ -174,7 +174,7 @@
     def testQueryAsk(self, mock_method) -> None:
         """Test ASK query."""
         mock_method.return_value = Container(RESPONSE_TRUE)
-        with skipping(pywikibot.exceptions.TimeoutError):
+        with skipping(pywikibot.exceptions.ApiTimeoutError):
             q = sparql.SparqlQuery()

         res = q.ask('ASK { ?x ?y ?z }')

--
To view, visit 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1307599?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: Ie36effbc761510c1b1a9efffe0d1dbd2087a652b
Gerrit-Change-Number: 1307599
Gerrit-PatchSet: 2
Gerrit-Owner: Prakhar0804 <[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