PageRenderTime 24ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/test/rql_test/connections/http_support/markupsafe/__init__.py

https://gitlab.com/Mashamba/rethinkdb
Python | 298 lines | 275 code | 7 blank | 16 comment | 4 complexity | 25d1b407fd8bc06b05fe2e05576af586 MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. """
  3. markupsafe
  4. ~~~~~~~~~~
  5. Implements a Markup string.
  6. :copyright: (c) 2010 by Armin Ronacher.
  7. :license: BSD, see LICENSE for more details.
  8. """
  9. import re
  10. import string
  11. from collections import Mapping
  12. from markupsafe._compat import text_type, string_types, int_types, \
  13. unichr, iteritems, PY2
  14. __all__ = ['Markup', 'soft_unicode', 'escape', 'escape_silent']
  15. _striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
  16. _entity_re = re.compile(r'&([^;]+);')
  17. class Markup(text_type):
  18. r"""Marks a string as being safe for inclusion in HTML/XML output without
  19. needing to be escaped. This implements the `__html__` interface a couple
  20. of frameworks and web applications use. :class:`Markup` is a direct
  21. subclass of `unicode` and provides all the methods of `unicode` just that
  22. it escapes arguments passed and always returns `Markup`.
  23. The `escape` function returns markup objects so that double escaping can't
  24. happen.
  25. The constructor of the :class:`Markup` class can be used for three
  26. different things: When passed an unicode object it's assumed to be safe,
  27. when passed an object with an HTML representation (has an `__html__`
  28. method) that representation is used, otherwise the object passed is
  29. converted into a unicode string and then assumed to be safe:
  30. >>> Markup("Hello <em>World</em>!")
  31. Markup(u'Hello <em>World</em>!')
  32. >>> class Foo(object):
  33. ... def __html__(self):
  34. ... return '<a href="#">foo</a>'
  35. ...
  36. >>> Markup(Foo())
  37. Markup(u'<a href="#">foo</a>')
  38. If you want object passed being always treated as unsafe you can use the
  39. :meth:`escape` classmethod to create a :class:`Markup` object:
  40. >>> Markup.escape("Hello <em>World</em>!")
  41. Markup(u'Hello &lt;em&gt;World&lt;/em&gt;!')
  42. Operations on a markup string are markup aware which means that all
  43. arguments are passed through the :func:`escape` function:
  44. >>> em = Markup("<em>%s</em>")
  45. >>> em % "foo & bar"
  46. Markup(u'<em>foo &amp; bar</em>')
  47. >>> strong = Markup("<strong>%(text)s</strong>")
  48. >>> strong % {'text': '<blink>hacker here</blink>'}
  49. Markup(u'<strong>&lt;blink&gt;hacker here&lt;/blink&gt;</strong>')
  50. >>> Markup("<em>Hello</em> ") + "<foo>"
  51. Markup(u'<em>Hello</em> &lt;foo&gt;')
  52. """
  53. __slots__ = ()
  54. def __new__(cls, base=u'', encoding=None, errors='strict'):
  55. if hasattr(base, '__html__'):
  56. base = base.__html__()
  57. if encoding is None:
  58. return text_type.__new__(cls, base)
  59. return text_type.__new__(cls, base, encoding, errors)
  60. def __html__(self):
  61. return self
  62. def __add__(self, other):
  63. if isinstance(other, string_types) or hasattr(other, '__html__'):
  64. return self.__class__(super(Markup, self).__add__(self.escape(other)))
  65. return NotImplemented
  66. def __radd__(self, other):
  67. if hasattr(other, '__html__') or isinstance(other, string_types):
  68. return self.escape(other).__add__(self)
  69. return NotImplemented
  70. def __mul__(self, num):
  71. if isinstance(num, int_types):
  72. return self.__class__(text_type.__mul__(self, num))
  73. return NotImplemented
  74. __rmul__ = __mul__
  75. def __mod__(self, arg):
  76. if isinstance(arg, tuple):
  77. arg = tuple(_MarkupEscapeHelper(x, self.escape) for x in arg)
  78. else:
  79. arg = _MarkupEscapeHelper(arg, self.escape)
  80. return self.__class__(text_type.__mod__(self, arg))
  81. def __repr__(self):
  82. return '%s(%s)' % (
  83. self.__class__.__name__,
  84. text_type.__repr__(self)
  85. )
  86. def join(self, seq):
  87. return self.__class__(text_type.join(self, map(self.escape, seq)))
  88. join.__doc__ = text_type.join.__doc__
  89. def split(self, *args, **kwargs):
  90. return list(map(self.__class__, text_type.split(self, *args, **kwargs)))
  91. split.__doc__ = text_type.split.__doc__
  92. def rsplit(self, *args, **kwargs):
  93. return list(map(self.__class__, text_type.rsplit(self, *args, **kwargs)))
  94. rsplit.__doc__ = text_type.rsplit.__doc__
  95. def splitlines(self, *args, **kwargs):
  96. return list(map(self.__class__, text_type.splitlines(
  97. self, *args, **kwargs)))
  98. splitlines.__doc__ = text_type.splitlines.__doc__
  99. def unescape(self):
  100. r"""Unescape markup again into an text_type string. This also resolves
  101. known HTML4 and XHTML entities:
  102. >>> Markup("Main &raquo; <em>About</em>").unescape()
  103. u'Main \xbb <em>About</em>'
  104. """
  105. from markupsafe._constants import HTML_ENTITIES
  106. def handle_match(m):
  107. name = m.group(1)
  108. if name in HTML_ENTITIES:
  109. return unichr(HTML_ENTITIES[name])
  110. try:
  111. if name[:2] in ('#x', '#X'):
  112. return unichr(int(name[2:], 16))
  113. elif name.startswith('#'):
  114. return unichr(int(name[1:]))
  115. except ValueError:
  116. pass
  117. return u''
  118. return _entity_re.sub(handle_match, text_type(self))
  119. def striptags(self):
  120. r"""Unescape markup into an text_type string and strip all tags. This
  121. also resolves known HTML4 and XHTML entities. Whitespace is
  122. normalized to one:
  123. >>> Markup("Main &raquo; <em>About</em>").striptags()
  124. u'Main \xbb About'
  125. """
  126. stripped = u' '.join(_striptags_re.sub('', self).split())
  127. return Markup(stripped).unescape()
  128. @classmethod
  129. def escape(cls, s):
  130. """Escape the string. Works like :func:`escape` with the difference
  131. that for subclasses of :class:`Markup` this function would return the
  132. correct subclass.
  133. """
  134. rv = escape(s)
  135. if rv.__class__ is not cls:
  136. return cls(rv)
  137. return rv
  138. def make_simple_escaping_wrapper(name):
  139. orig = getattr(text_type, name)
  140. def func(self, *args, **kwargs):
  141. args = _escape_argspec(list(args), enumerate(args), self.escape)
  142. _escape_argspec(kwargs, iteritems(kwargs), self.escape)
  143. return self.__class__(orig(self, *args, **kwargs))
  144. func.__name__ = orig.__name__
  145. func.__doc__ = orig.__doc__
  146. return func
  147. for method in '__getitem__', 'capitalize', \
  148. 'title', 'lower', 'upper', 'replace', 'ljust', \
  149. 'rjust', 'lstrip', 'rstrip', 'center', 'strip', \
  150. 'translate', 'expandtabs', 'swapcase', 'zfill':
  151. locals()[method] = make_simple_escaping_wrapper(method)
  152. # new in python 2.5
  153. if hasattr(text_type, 'partition'):
  154. def partition(self, sep):
  155. return tuple(map(self.__class__,
  156. text_type.partition(self, self.escape(sep))))
  157. def rpartition(self, sep):
  158. return tuple(map(self.__class__,
  159. text_type.rpartition(self, self.escape(sep))))
  160. # new in python 2.6
  161. if hasattr(text_type, 'format'):
  162. def format(*args, **kwargs):
  163. self, args = args[0], args[1:]
  164. formatter = EscapeFormatter(self.escape)
  165. kwargs = _MagicFormatMapping(args, kwargs)
  166. return self.__class__(formatter.vformat(self, args, kwargs))
  167. def __html_format__(self, format_spec):
  168. if format_spec:
  169. raise ValueError('Unsupported format specification '
  170. 'for Markup.')
  171. return self
  172. # not in python 3
  173. if hasattr(text_type, '__getslice__'):
  174. __getslice__ = make_simple_escaping_wrapper('__getslice__')
  175. del method, make_simple_escaping_wrapper
  176. class _MagicFormatMapping(Mapping):
  177. """This class implements a dummy wrapper to fix a bug in the Python
  178. standard library for string formatting.
  179. See http://bugs.python.org/issue13598 for information about why
  180. this is necessary.
  181. """
  182. def __init__(self, args, kwargs):
  183. self._args = args
  184. self._kwargs = kwargs
  185. self._last_index = 0
  186. def __getitem__(self, key):
  187. if key == '':
  188. idx = self._last_index
  189. self._last_index += 1
  190. try:
  191. return self._args[idx]
  192. except LookupError:
  193. pass
  194. key = str(idx)
  195. return self._kwargs[key]
  196. def __iter__(self):
  197. return iter(self._kwargs)
  198. def __len__(self):
  199. return len(self._kwargs)
  200. if hasattr(text_type, 'format'):
  201. class EscapeFormatter(string.Formatter):
  202. def __init__(self, escape):
  203. self.escape = escape
  204. def format_field(self, value, format_spec):
  205. if hasattr(value, '__html_format__'):
  206. rv = value.__html_format__(format_spec)
  207. elif hasattr(value, '__html__'):
  208. if format_spec:
  209. raise ValueError('No format specification allowed '
  210. 'when formatting an object with '
  211. 'its __html__ method.')
  212. rv = value.__html__()
  213. else:
  214. rv = string.Formatter.format_field(self, value, format_spec)
  215. return text_type(self.escape(rv))
  216. def _escape_argspec(obj, iterable, escape):
  217. """Helper for various string-wrapped functions."""
  218. for key, value in iterable:
  219. if hasattr(value, '__html__') or isinstance(value, string_types):
  220. obj[key] = escape(value)
  221. return obj
  222. class _MarkupEscapeHelper(object):
  223. """Helper for Markup.__mod__"""
  224. def __init__(self, obj, escape):
  225. self.obj = obj
  226. self.escape = escape
  227. __getitem__ = lambda s, x: _MarkupEscapeHelper(s.obj[x], s.escape)
  228. __unicode__ = __str__ = lambda s: text_type(s.escape(s.obj))
  229. __repr__ = lambda s: str(s.escape(repr(s.obj)))
  230. __int__ = lambda s: int(s.obj)
  231. __float__ = lambda s: float(s.obj)
  232. # we have to import it down here as the speedups and native
  233. # modules imports the markup type which is define above.
  234. try:
  235. from markupsafe._speedups import escape, escape_silent, soft_unicode
  236. except ImportError:
  237. from markupsafe._native import escape, escape_silent, soft_unicode
  238. if not PY2:
  239. soft_str = soft_unicode
  240. __all__.append('soft_str')