jenkins-bot submitted this change.

View Change

Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
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(-)

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 change 1149817. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I25c7d154caf0de551f3f99c0309214040295eb74
Gerrit-Change-Number: 1149817
Gerrit-PatchSet: 3
Gerrit-Owner: Xqt <info@gno.de>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot