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

Change subject: IMPR: move tools.threading.RLock to backports module
......................................................................

IMPR: move tools.threading.RLock to backports module

- move tools.threading.RLock to backports and enable it for Python < 3.14
- deprecate tools.threading.RLock
- deprecate RLock.count property
- use backports.RLock in terminal_interface_base
- update documentation

Bug: T395182
Change-Id: I25c7d154caf0de551f3f99c0309214040295eb74
---
M docs/api_ref/tools/tools.threading.rst
M pywikibot/backports.py
M pywikibot/tools/threading.py
M pywikibot/userinterfaces/terminal_interface_base.py
4 files changed, 105 insertions(+), 69 deletions(-)

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




diff --git a/docs/api_ref/tools/tools.threading.rst 
b/docs/api_ref/tools/tools.threading.rst
index 20350a5..c1ef728 100644
--- a/docs/api_ref/tools/tools.threading.rst
+++ b/docs/api_ref/tools/tools.threading.rst
@@ -3,3 +3,8 @@
 ***********************************************
 .. automodule:: tools.threading
    :synopsis: Threading classes
+
+.. autoclass:: RLock
+
+   .. deprecated:: 10.2
+      use :mod:`backports.RLock` instead
diff --git a/pywikibot/backports.py b/pywikibot/backports.py
index ab18130..a3b64f7 100644
--- a/pywikibot/backports.py
+++ b/pywikibot/backports.py
@@ -14,6 +14,7 @@
 #
 from __future__ import annotations

+import re
 import sys
 from typing import Any

@@ -206,3 +207,86 @@
                 yield group
 else:
     from itertools import batched  # type: ignore[no-redef]
+
+
+# gh-115942, gh-134323
+if PYTHON_VERSION < (3, 14) or SPHINX_RUNNING:
+    import threading as _threading
+
+    from pywikibot.tools import deprecated, issue_deprecation_warning
+
+    class RLock:
+
+        """Context manager which implements extended reentrant lock objects.
+
+        This RLock is implicit derived from threading.RLock but provides a
+        locked() method like in threading.Lock and a count attribute which
+        gives the active recursion level of locks.
+
+        Usage:
+
+        >>> lock = RLock()
+        >>> lock.acquire()
+        True
+        >>> with lock: print(lock.count)  # nested lock
+        2
+        >>> lock.locked()
+        True
+        >>> lock.release()
+        >>> lock.locked()
+        False
+
+        .. versionadded:: 6.2
+        .. versionchanged:: 10.2
+           moved from :mod:`tools.threading` to :mod:`backports`.
+        .. note:: Passing any arguments has no effect and has been
+           deprecated since Python 3.14 and was removed in Python 3.15.
+        """
+
+        def __init__(self, *args, **kwargs) -> None:
+            """Initializer."""
+            if args or kwargs:
+                issue_deprecation_warning('Passing arguments to RLock',
+                                          since='10.2.0')
+            self._lock = _threading.RLock()
+            self._block = _threading.Lock()
+
+        def __enter__(self):
+            """Acquire lock and call atenter."""
+            return self._lock.__enter__()
+
+        def __exit__(self, *exc):
+            """Call atexit and release lock."""
+            return self._lock.__exit__(*exc)
+
+        def __getattr__(self, name):
+            """Delegate attributes and methods to self._lock."""
+            return getattr(self._lock, name)
+
+        def __repr__(self) -> str:
+            """Representation of tools.RLock instance."""
+            return repr(self._lock).replace(
+                '_thread.RLock',
+                f'{self.__module__}.{type(self).__name__}'
+            )
+
+        @property
+        @deprecated(since='10.2.0')
+        def count(self):
+            """Return number of acquired locks.
+
+            .. deprecated:: 10.2
+            """
+            with self._block:
+                counter = re.search(r'count=(\d+) ', repr(self))
+                return int(counter[1])
+
+        def locked(self):
+            """Return true if the lock is acquired."""
+            with self._block:
+                status = repr(self).split(maxsplit=1)[0][1:]
+                assert status in ('locked', 'unlocked')
+                return status == 'locked'
+
+else:
+    from threading import RLock
diff --git a/pywikibot/tools/threading.py b/pywikibot/tools/threading.py
index 679bb37..0692c05 100644
--- a/pywikibot/tools/threading.py
+++ b/pywikibot/tools/threading.py
@@ -1,6 +1,6 @@
 """Classes which can be used for threading."""
 #
-# (C) Pywikibot team, 2008-2024
+# (C) Pywikibot team, 2008-2025
 #
 # Distributed under the terms of the MIT license.
 #
@@ -9,87 +9,22 @@
 import dataclasses
 import importlib
 import queue
-import re
 import threading
 import time
 from concurrent import futures
 from typing import Any

 import pywikibot  # T306760
-from pywikibot.tools import SPHINX_RUNNING
+from pywikibot.tools import SPHINX_RUNNING, ModuleDeprecationWrapper


 __all__ = (
     'BoundedPoolExecutor',
-    'RLock',
     'ThreadedGenerator',
     'ThreadList',
 )


-class RLock:
-
-    """Context manager which implements extended reentrant lock objects.
-
-    This RLock is implicit derived from threading.RLock but provides a
-    locked() method like in threading.Lock and a count attribute which
-    gives the active recursion level of locks.
-
-    Usage:
-
-    >>> lock = RLock()
-    >>> lock.acquire()
-    True
-    >>> with lock: print(lock.count)  # nested lock
-    2
-    >>> lock.locked()
-    True
-    >>> lock.release()
-    >>> lock.locked()
-    False
-
-    .. versionadded:: 6.2
-    """
-
-    def __init__(self, *args, **kwargs) -> None:
-        """Initializer."""
-        self._lock = threading.RLock(*args, **kwargs)
-        self._block = threading.Lock()
-
-    def __enter__(self):
-        """Acquire lock and call atenter."""
-        return self._lock.__enter__()
-
-    def __exit__(self, *exc):
-        """Call atexit and release lock."""
-        return self._lock.__exit__(*exc)
-
-    def __getattr__(self, name):
-        """Delegate attributes and methods to self._lock."""
-        return getattr(self._lock, name)
-
-    def __repr__(self) -> str:
-        """Representation of tools.RLock instance."""
-        return repr(self._lock).replace(
-            '_thread.RLock',
-            f'{self.__module__}.{type(self).__name__}'
-        )
-
-    @property
-    def count(self):
-        """Return number of acquired locks."""
-        with self._block:
-            counter = re.search(r'count=(\d+) ', repr(self))
-            return int(counter[1])
-
-    def locked(self):
-        """Return true if the lock is acquired."""
-        with self._block:
-            status = repr(self).split(maxsplit=1)[0][1:]
-            assert status in ('locked', 'unlocked')
-            return status == 'locked'
-
-
 class ThreadedGenerator(threading.Thread):

     """Look-ahead generator class.
@@ -354,3 +289,10 @@
         """
         base, executor = type(self).__bases__
         return f'{base.__name__}({executor.__name__!r}{self._bound(", ")})'
+
+
+wrapper = ModuleDeprecationWrapper(__name__)
+wrapper.add_deprecated_attr(
+    'RLock',
+    replacement_name='pywikibot.backports.RLock',
+    since='10.2.0')
diff --git a/pywikibot/userinterfaces/terminal_interface_base.py 
b/pywikibot/userinterfaces/terminal_interface_base.py
index c3cc545..6b2994c 100644
--- a/pywikibot/userinterfaces/terminal_interface_base.py
+++ b/pywikibot/userinterfaces/terminal_interface_base.py
@@ -15,7 +15,13 @@

 import pywikibot
 from pywikibot import config
-from pywikibot.backports import Iterable, Sequence, batched, removeprefix
+from pywikibot.backports import (
+    Iterable,
+    RLock,
+    Sequence,
+    batched,
+    removeprefix,
+)
 from pywikibot.bot_choice import (
     ChoiceException,
     Option,
@@ -24,7 +30,6 @@
     StandardOption,
 )
 from pywikibot.logging import INFO, INPUT, STDOUT, VERBOSE, WARNING
-from pywikibot.tools.threading import RLock
 from pywikibot.userinterfaces import transliteration
 from pywikibot.userinterfaces._interface_base import ABUIC


--
To view, visit 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1149817?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: I25c7d154caf0de551f3f99c0309214040295eb74
Gerrit-Change-Number: 1149817
Gerrit-PatchSet: 3
Gerrit-Owner: Xqt <[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