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