# -*- coding: utf-8 -*- # # Copyright (C) 2012-2013 Ben Kurtovic # # 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 :py:class:`~.StringMixIn` type, which implements the interface for the ``unicode`` type (``str`` on py3k) in a dynamic manner. """ from __future__ import unicode_literals from .compat import py3k, str __all__ = ["StringMixIn"] def inheritdoc(method): """Set __doc__ of *method* to __doc__ of *method* in its parent class. Since this is used on :py: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 class StringMixIn(object): """Implement the interface for ``unicode``/``str`` in a dynamic manner. To use this class, inherit from it and override the :py:meth:`__unicode__` method (same on py3k) to return the string representation of the object. The various string methods will operate on the value of :py:meth:`__unicode__` instead of the immutable ``self`` like the regular ``str`` type. """ if py3k: def __str__(self): return self.__unicode__() def __bytes__(self): return self.__unicode__().encode("utf8") else: def __str__(self): return self.__unicode__().encode("utf8") def __unicode__(self): raise NotImplementedError() def __repr__(self): return repr(self.__unicode__()) def __lt__(self, other): if isinstance(other, StringMixIn): return self.__unicode__() < other.__unicode__() return self.__unicode__() < other def __le__(self, other): if isinstance(other, StringMixIn): return self.__unicode__() <= other.__unicode__() return self.__unicode__() <= other def __eq__(self, other): if isinstance(other, StringMixIn): return self.__unicode__() == other.__unicode__() return self.__unicode__() == other def __ne__(self, other): if isinstance(other, StringMixIn): return self.__unicode__() != other.__unicode__() return self.__unicode__() != other def __gt__(self, other): if isinstance(other, StringMixIn): return self.__unicode__() > other.__unicode__() return self.__unicode__() > other def __ge__(self, other): if isinstance(other, StringMixIn): return self.__unicode__() >= other.__unicode__() return self.__unicode__() >= other if py3k: def __bool__(self): return bool(self.__unicode__()) else: def __nonzero__(self): return bool(self.__unicode__()) def __len__(self): return len(self.__unicode__()) def __iter__(self): for char in self.__unicode__(): yield char def __getitem__(self, key): return self.__unicode__()[key] def __reversed__(self): return reversed(self.__unicode__()) def __contains__(self, item): if isinstance(item, StringMixIn): return str(item) in self.__unicode__() return item in self.__unicode__() @inheritdoc def capitalize(self): return self.__unicode__().capitalize() if py3k: @inheritdoc def casefold(self): return self.__unicode__().casefold() @inheritdoc def center(self, width, fillchar=None): if fillchar is None: return self.__unicode__().center(width) return self.__unicode__().center(width, fillchar) @inheritdoc def count(self, sub, start=None, end=None): return self.__unicode__().count(sub, start, end) if not py3k: @inheritdoc def decode(self, encoding=None, errors=None): kwargs = {} if encoding is not None: kwargs["encoding"] = encoding if errors is not None: kwargs["errors"] = errors return self.__unicode__().decode(**kwargs) @inheritdoc def encode(self, encoding=None, errors=None): kwargs = {} if encoding is not None: kwargs["encoding"] = encoding if errors is not None: kwargs["errors"] = errors return self.__unicode__().encode(**kwargs) @inheritdoc def endswith(self, prefix, start=None, end=None): return self.__unicode__().endswith(prefix, start, end) @inheritdoc def expandtabs(self, tabsize=None): if tabsize is None: return self.__unicode__().expandtabs() return self.__unicode__().expandtabs(tabsize) @inheritdoc def find(self, sub, start=None, end=None): return self.__unicode__().find(sub, start, end) @inheritdoc def format(self, *args, **kwargs): return self.__unicode__().format(*args, **kwargs) if py3k: @inheritdoc def format_map(self, mapping): return self.__unicode__().format_map(mapping) @inheritdoc def index(self, sub, start=None, end=None): return self.__unicode__().index(sub, start, end) @inheritdoc def isalnum(self): return self.__unicode__().isalnum() @inheritdoc def isalpha(self): return self.__unicode__().isalpha() @inheritdoc def isdecimal(self): return self.__unicode__().isdecimal() @inheritdoc def isdigit(self): return self.__unicode__().isdigit() if py3k: @inheritdoc def isidentifier(self): return self.__unicode__().isidentifier() @inheritdoc def islower(self): return self.__unicode__().islower() @inheritdoc def isnumeric(self): return self.__unicode__().isnumeric() if py3k: @inheritdoc def isprintable(self): return self.__unicode__().isprintable() @inheritdoc def isspace(self): return self.__unicode__().isspace() @inheritdoc def istitle(self): return self.__unicode__().istitle() @inheritdoc def isupper(self): return self.__unicode__().isupper() @inheritdoc def join(self, iterable): return self.__unicode__().join(iterable) @inheritdoc def ljust(self, width, fillchar=None): if fillchar is None: return self.__unicode__().ljust(width) return self.__unicode__().ljust(width, fillchar) @inheritdoc def lower(self): return self.__unicode__().lower() @inheritdoc def lstrip(self, chars=None): return self.__unicode__().lstrip(chars) if py3k: @staticmethod @inheritdoc def maketrans(x, y=None, z=None): if z is None: if y is None: return str.maketrans(x) return str.maketrans(x, y) return str.maketrans(x, y, z) @inheritdoc def partition(self, sep): return self.__unicode__().partition(sep) @inheritdoc def replace(self, old, new, count=None): if count is None: return self.__unicode__().replace(old, new) return self.__unicode__().replace(old, new, count) @inheritdoc def rfind(self, sub, start=None, end=None): return self.__unicode__().rfind(sub, start, end) @inheritdoc def rindex(self, sub, start=None, end=None): return self.__unicode__().rindex(sub, start, end) @inheritdoc def rjust(self, width, fillchar=None): if fillchar is None: return self.__unicode__().rjust(width) return self.__unicode__().rjust(width, fillchar) @inheritdoc def rpartition(self, sep): return self.__unicode__().rpartition(sep) if py3k: @inheritdoc def rsplit(self, sep=None, maxsplit=None): kwargs = {} if sep is not None: kwargs["sep"] = sep if maxsplit is not None: kwargs["maxsplit"] = maxsplit return self.__unicode__().rsplit(**kwargs) else: @inheritdoc def rsplit(self, sep=None, maxsplit=None): if maxsplit is None: if sep is None: return self.__unicode__().rsplit() return self.__unicode__().rsplit(sep) return self.__unicode__().rsplit(sep, maxsplit) @inheritdoc def rstrip(self, chars=None): return self.__unicode__().rstrip(chars) if py3k: @inheritdoc def split(self, sep=None, maxsplit=None): kwargs = {} if sep is not None: kwargs["sep"] = sep if maxsplit is not None: kwargs["maxsplit"] = maxsplit return self.__unicode__().split(**kwargs) else: @inheritdoc def split(self, sep=None, maxsplit=None): if maxsplit is None: if sep is None: return self.__unicode__().split() return self.__unicode__().split(sep) return self.__unicode__().split(sep, maxsplit) @inheritdoc def splitlines(self, keepends=None): if keepends is None: return self.__unicode__().splitlines() return self.__unicode__().splitlines(keepends) @inheritdoc def startswith(self, prefix, start=None, end=None): return self.__unicode__().startswith(prefix, start, end) @inheritdoc def strip(self, chars=None): return self.__unicode__().strip(chars) @inheritdoc def swapcase(self): return self.__unicode__().swapcase() @inheritdoc def title(self): return self.__unicode__().title() @inheritdoc def translate(self, table): return self.__unicode__().translate(table) @inheritdoc def upper(self): return self.__unicode__().upper() @inheritdoc def zfill(self, width): return self.__unicode__().zfill(width) del inheritdoc