Source code for mwparserfromhell.string_mixin

# Copyright (C) 2012-2025 Ben Kurtovic <ben.kurtovic@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""
This module contains the :class:`.StringMixIn` type, which implements the
interface for the ``str`` type in a dynamic manner.
"""

from __future__ import annotations

import sys
from collections.abc import Iterable, Iterator, Mapping
from typing import Any, SupportsIndex

__all__ = ["StringMixIn"]


def inheritdoc(method):
    """Set __doc__ of *method* to __doc__ of *method* in its parent class.

    Since this is used on :class:`.StringMixIn`, the "parent class" used is
    ``str``. This function can be used as a decorator.
    """
    method.__doc__ = getattr(str, method.__name__).__doc__
    return method


[docs] class StringMixIn: """Implement the interface for ``str`` in a dynamic manner. To use this class, inherit from it and override the :meth:`__str__` method to return the string representation of the object. The various string methods will operate on the value of :meth:`__str__` instead of the immutable ``self`` like the regular ``str`` type. """ # This is based on collections.UserString, but: # - Requires overriding __str__ instead of setting .data # - Returns new strings as strs instead of StringMixIns __slots__ = () def __str__(self) -> str: raise NotImplementedError() def __bytes__(self) -> bytes: return bytes(str(self), sys.getdefaultencoding()) def __repr__(self) -> str: return repr(str(self)) def __lt__(self, other: str | StringMixIn) -> bool: return str(self) < other def __le__(self, other: str | StringMixIn) -> bool: return str(self) <= other def __eq__(self, other: Any) -> bool: return str(self) == other def __ne__(self, other: Any) -> bool: return str(self) != other def __gt__(self, other: str | StringMixIn) -> bool: return str(self) > other def __ge__(self, other: str | StringMixIn) -> bool: return str(self) >= other def __bool__(self) -> bool: return bool(str(self)) def __len__(self) -> int: return len(str(self)) def __iter__(self) -> Iterator[str]: yield from str(self) def __getitem__(self, key: SupportsIndex | slice) -> str: return str(self)[key] def __reversed__(self) -> Iterator[str]: return reversed(str(self)) def __contains__(self, item: Any) -> bool: return str(item) in str(self)
[docs] @inheritdoc def capitalize(self) -> str: return str(self).capitalize()
[docs] @inheritdoc def casefold(self) -> str: return str(self).casefold()
[docs] @inheritdoc def center(self, width: int, fillchar: str = " ") -> str: return str(self).center(width, fillchar)
[docs] @inheritdoc def count( self, sub: str | StringMixIn, start: SupportsIndex | None = None, end: SupportsIndex | None = None, ) -> int: if isinstance(sub, StringMixIn): sub = str(sub) return str(self).count(sub, start, end)
[docs] @inheritdoc def encode(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: return str(self).encode(encoding, errors)
[docs] @inheritdoc def endswith( self, suffix: str | tuple[str, ...], start: SupportsIndex | None = None, end: SupportsIndex | None = None, ) -> bool: return str(self).endswith(suffix, start, end)
[docs] @inheritdoc def expandtabs(self, tabsize: int = 8) -> str: return str(self).expandtabs(tabsize)
[docs] @inheritdoc def find( self, sub: str | StringMixIn, start: SupportsIndex | None = None, end: SupportsIndex | None = None, ) -> int: if isinstance(sub, StringMixIn): sub = str(sub) return str(self).find(sub, start, end)
[docs] @inheritdoc def format(self, /, *args: Any, **kwds: Any) -> str: return str(self).format(*args, **kwds)
[docs] @inheritdoc def format_map(self, mapping: Mapping[str, Any]) -> str: return str(self).format_map(mapping)
[docs] @inheritdoc def index( self, sub: str, start: SupportsIndex | None = None, end: SupportsIndex | None = None, ) -> int: return str(self).index(sub, start, end)
[docs] @inheritdoc def isalpha(self) -> bool: return str(self).isalpha()
[docs] @inheritdoc def isalnum(self) -> bool: return str(self).isalnum()
[docs] @inheritdoc def isascii(self) -> bool: return str(self).isascii()
[docs] @inheritdoc def isdecimal(self) -> bool: return str(self).isdecimal()
[docs] @inheritdoc def isdigit(self) -> bool: return str(self).isdigit()
[docs] @inheritdoc def isidentifier(self) -> bool: return str(self).isidentifier()
[docs] @inheritdoc def islower(self) -> bool: return str(self).islower()
[docs] @inheritdoc def isnumeric(self) -> bool: return str(self).isnumeric()
[docs] @inheritdoc def isprintable(self) -> bool: return str(self).isprintable()
[docs] @inheritdoc def isspace(self) -> bool: return str(self).isspace()
[docs] @inheritdoc def istitle(self) -> bool: return str(self).istitle()
[docs] @inheritdoc def isupper(self) -> bool: return str(self).isupper()
[docs] @inheritdoc def join(self, seq: Iterable[str]) -> str: return str(self).join(seq)
[docs] @inheritdoc def ljust(self, width: int, fillchar: str = " ") -> str: return str(self).ljust(width, fillchar)
[docs] @inheritdoc def lower(self) -> str: return str(self).lower()
[docs] @inheritdoc def lstrip(self, chars: str | None = None) -> str: return str(self).lstrip(chars)
maketrans = str.maketrans
[docs] @inheritdoc def partition(self, sep: str) -> tuple[str, str, str]: return str(self).partition(sep)
[docs] @inheritdoc def removeprefix(self, prefix: str | StringMixIn, /) -> str: if isinstance(prefix, StringMixIn): prefix = str(prefix) return str(self).removeprefix(prefix)
[docs] @inheritdoc def removesuffix(self, suffix: str | StringMixIn, /) -> str: if isinstance(suffix, StringMixIn): suffix = str(suffix) return str(self).removesuffix(suffix)
[docs] @inheritdoc def replace( self, old: str | StringMixIn, new: str | StringMixIn, /, count: SupportsIndex = -1, ): if isinstance(old, StringMixIn): old = str(old) if isinstance(new, StringMixIn): new = str(new) return str(self).replace(old, new, count)
[docs] @inheritdoc def rfind( self, sub: str | StringMixIn, start: SupportsIndex | None = None, end: SupportsIndex | None = None, ) -> int: if isinstance(sub, StringMixIn): sub = str(sub) return str(self).rfind(sub, start, end)
[docs] @inheritdoc def rindex( self, sub: str, start: SupportsIndex | None = None, end: SupportsIndex | None = None, ) -> int: return str(self).rindex(sub, start, end)
[docs] @inheritdoc def rjust(self, width: int, fillchar: str = " ") -> str: return str(self).rjust(width, fillchar)
[docs] @inheritdoc def rpartition(self, sep: str) -> tuple[str, str, str]: return str(self).rpartition(sep)
[docs] @inheritdoc def rstrip(self, chars: str | None = None) -> str: return str(self).rstrip(chars)
[docs] @inheritdoc def split(self, sep: str | None = None, maxsplit: SupportsIndex = -1) -> list[str]: return str(self).split(sep, maxsplit)
[docs] @inheritdoc def rsplit(self, sep: str | None = None, maxsplit: SupportsIndex = -1) -> list[str]: return str(self).rsplit(sep, maxsplit)
[docs] @inheritdoc def splitlines(self, keepends: bool = False) -> list[str]: return str(self).splitlines(keepends)
[docs] @inheritdoc def startswith( self, prefix: str | tuple[str, ...], start: SupportsIndex | None = None, end: SupportsIndex | None = None, ) -> bool: return str(self).startswith(prefix, start, end)
[docs] @inheritdoc def strip(self, chars: str | None = None) -> str: return str(self).strip(chars)
[docs] @inheritdoc def swapcase(self) -> str: return str(self).swapcase()
[docs] @inheritdoc def title(self) -> str: return str(self).title()
[docs] @inheritdoc def translate(self, *args: Any) -> str: return str(self).translate(*args)
[docs] @inheritdoc def upper(self) -> str: return str(self).upper()
[docs] @inheritdoc def zfill(self, width: int) -> str: return str(self).zfill(width)