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

Change subject: backports: provide sentinel implementation backported from 
Python 3.15
......................................................................

backports: provide sentinel implementation backported from Python 3.15

Change-Id: Ib6a3be2bb8a5b8c08f1e9551906b2ca18f68673a
---
M pywikibot/backports.py
1 file changed, 140 insertions(+), 1 deletion(-)

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




diff --git a/pywikibot/backports.py b/pywikibot/backports.py
index 01ce70e..7f54057 100644
--- a/pywikibot/backports.py
+++ b/pywikibot/backports.py
@@ -15,7 +15,8 @@
 from __future__ import annotations

 import re
-from typing import TYPE_CHECKING
+import sys
+from typing import TYPE_CHECKING, Any, Union

 from pywikibot.tools import PYTHON_VERSION, SPHINX_RUNNING

@@ -37,6 +38,7 @@
            <library/itertools.html#itertools.pairwise>`,
            backported from Python 3.10.
         .. version-added:: 7.6
+        .. version-removed:: 12.0
         """
         a, b = tee(iterable)
         next(b, None)
@@ -84,6 +86,7 @@
         .. version-added:: 8.2
         .. version-changed:: 9.0
            Added *strict* option, backported from Python 3.13
+        .. version-removed:: 15.0

         :param n: How many items of the iterable to get in one chunk
         :param strict: Raise a ValueError if the final batch is shorter
@@ -151,6 +154,10 @@
         .. version-added:: 6.2
         .. version-changed:: 10.2
            moved from :mod:`tools.threading` to :mod:`backports`.
+        .. version-deprecated:: 10.2
+           Passing any arguments is deprecated; a TypeError will be
+           raised with Pywikibot 13.0.
+        .. version-removed:: 16.0
         .. note:: Passing any arguments has no effect and has been
            deprecated since Python 3.14 and was removed in Python 3.15.
         """
@@ -202,3 +209,135 @@

 else:
     from threading import RLock  # type: ignore[assignment]
+
+
+if PYTHON_VERSION < (3, 15) or SPHINX_RUNNING:
+
+    class sentinel:  # noqa: N801
+
+        """Implementation of a unique sentinel object.
+
+        Usage:
+
+        >>> MISSING = sentinel('MISSING')
+        >>> MISSING
+        MISSING
+        >>> MISSING = sentinel('MISSING', repr="'MISSING'")
+        >>> MISSING
+        'MISSING'
+        >>> import copy
+        >>> value = copy.copy(MISSING)
+        >>> value is MISSING
+        True
+
+        .. version-added:: 11.6
+        .. version-removed:: 17.0
+        .. seealso::
+           - :pylib:`sentinel<functions#sentinel>` backported
+             from Python 3.15.
+           - :pep:`661`
+
+        :param name: Name of the sentinel object; it should be the name
+            of the variable to which the sentinel shall be assigned.
+        :param repr: Representation returned by :func:`repr`.
+        :raises TypeError: If *name* is not a string or subclassing is
+            attempted.
+        :raises AttributeError: If an attribute other than ``__module__``
+            is assigned.
+        """
+
+        if TYPE_CHECKING:
+            __name__: str
+            _repr: str
+            __module__: str
+
+        def __init__(self, name: str, /, *, repr: str | None = None) -> None:
+            """Initializer."""
+            if not isinstance(name, str):
+                raise TypeError(f'sentinel name must be a string, '
+                                f'not {type(name).__name__}')
+            object.__setattr__(self, '__name__', name)
+            object.__setattr__(self, '_repr',
+                               repr if repr is not None else name)
+            object.__setattr__(
+                self,
+                '__module__',
+                self._get_module_name()
+            )
+
+        def __init_subclass__(cls):
+            """Prevent subclassing of sentinel objects.
+
+            :raises TypeError: Always, as sentinel objects cannot be
+                subclassed.
+            """
+            raise TypeError(
+                "type 'sentinel' is not an acceptable base type")
+
+        def __repr__(self) -> str:
+            """Return the representation of the sentinel."""
+            return self._repr
+
+        def __reduce__(self) -> str:
+            """Return the name used to restore the sentinel object.
+
+            The returned name is resolved in the original module during
+            unpickling.
+
+            :return: The sentinel name.
+            """
+            return self.__name__
+
+        def __copy__(self) -> sentinel:
+            """Return the same instance when shallow-copied."""
+            return self
+
+        def __deepcopy__(self, memo: dict[int, Any]) -> sentinel:
+            """Return the same instance when deep-copied.
+
+            :param memo: Deep-copy memo dictionary.
+
+            :return: The sentinel instance itself.
+            """
+            return self
+
+        def __setattr__(self, attr: str, value: object) -> None:
+            """Prevent modification of sentinel attributes.
+
+             Sentinel objects are immutable after initialization. The
+            ``__module__`` attribute is excluded to support pickle
+            compatibility.
+
+            :param attr: Attribute name.
+            :param value: Attribute value.
+            :raises AttributeError: If an attribute other than
+                ``__module__`` is assigned.
+            """
+            if attr == '__module__':
+                object.__setattr__(self, attr, value)
+                return
+
+            raise AttributeError(
+                "'sentinel' object has no attribute assignment")
+
+        @staticmethod
+        def _get_module_name(depth: int = 1, default: str = '__main__') -> str:
+            """Return the module name of a caller frame."""
+            d = depth + 1
+            if PYTHON_VERSION >= (3, 12):
+                return (
+                    sys._getframemodulename(d)  # type: ignore[attr-defined]
+                    or default
+                )
+
+            return sys._getframe(d).f_globals.get('__name__', default)
+
+        if PYTHON_VERSION >= (3, 10):
+            def __or__(self, other: object) -> Any:
+                return Union[self, other]
+
+            def __ror__(self, other: object) -> Any:
+                return Union[other, self]
+
+else:
+    from builtins import sentinel  # type: ignore[no-redef, attr-defined]

--
To view, visit 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1309853?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: Ib6a3be2bb8a5b8c08f1e9551906b2ca18f68673a
Gerrit-Change-Number: 1309853
Gerrit-PatchSet: 5
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