Imported Upstream version 1.0 75/123275/1 upstream upstream/1.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 5 Apr 2017 06:14:09 +0000 (15:14 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 5 Apr 2017 06:14:29 +0000 (15:14 +0900)
Change-Id: If1db63a92310975642b8f7d7e70ce3d5e3d3cde7
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
19 files changed:
AUTHORS [new file with mode: 0644]
CHANGES [new file with mode: 0644]
LICENSE [new file with mode: 0644]
MANIFEST.in [new file with mode: 0644]
MarkupSafe.egg-info/PKG-INFO [new file with mode: 0644]
MarkupSafe.egg-info/SOURCES.txt [new file with mode: 0644]
MarkupSafe.egg-info/dependency_links.txt [new file with mode: 0644]
MarkupSafe.egg-info/not-zip-safe [new file with mode: 0644]
MarkupSafe.egg-info/top_level.txt [new file with mode: 0644]
PKG-INFO [new file with mode: 0644]
README.rst [new file with mode: 0644]
markupsafe/__init__.py [new file with mode: 0644]
markupsafe/_compat.py [new file with mode: 0644]
markupsafe/_constants.py [new file with mode: 0644]
markupsafe/_native.py [new file with mode: 0644]
markupsafe/_speedups.c [new file with mode: 0644]
setup.cfg [new file with mode: 0644]
setup.py [new file with mode: 0755]
tests.py [new file with mode: 0755]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..f7e2942
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,13 @@
+MarkupSafe is written and maintained by Armin Ronacher and
+various contributors:
+
+Development Lead
+````````````````
+
+- Armin Ronacher <armin.ronacher@active-4.com>
+
+Patches and Suggestions
+```````````````````````
+
+- Georg Brandl
+- Mickaël Guérin
diff --git a/CHANGES b/CHANGES
new file mode 100644 (file)
index 0000000..706a230
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,48 @@
+MarkupSafe Changelog
+====================
+
+Version 1.0
+-----------
+
+- Fixed custom types not invoking `__unicode__` when used
+  with `format()`.
+- Added `__version__` module attribute
+- Improve unescape code to leave lone ampersands alone.
+
+Version 0.18
+------------
+
+- Fixed `__mul__` and string splitting on Python 3.
+
+Version 0.17
+------------
+
+- Fixed a bug with broken interpolation on tuples.
+
+Version 0.16
+------------
+
+- Improved Python 3 Support and removed 2to3
+- Removed support for Python 3.2 and 2.5
+
+Version 0.15
+------------
+
+- Fixed a typo that caused the library to fail to install
+  on pypy and jython -.-
+
+Version 0.14
+------------
+
+- Release fix for 0.13.
+
+Version 0.13
+------------
+
+- Do not attempt to compile extension for PyPy or Jython.
+- Work around some 64bit Windows issues.
+
+Version 0.12
+------------
+
+- improved PyPy compatibility
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..5d26938
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,33 @@
+Copyright (c) 2010 by Armin Ronacher and contributors.  See AUTHORS
+for more details.
+
+Some rights reserved.
+
+Redistribution and use in source and binary forms of the software as well
+as documentation, with or without modification, are permitted provided
+that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following
+  disclaimer in the documentation and/or other materials provided
+  with the distribution.
+
+* The names of the contributors may not be used to endorse or
+  promote products derived from this software without specific
+  prior written permission.
+
+THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644 (file)
index 0000000..c9a1952
--- /dev/null
@@ -0,0 +1,2 @@
+include AUTHORS CHANGES LICENSE tests.py
+recursive-include markupsafe *.c
diff --git a/MarkupSafe.egg-info/PKG-INFO b/MarkupSafe.egg-info/PKG-INFO
new file mode 100644 (file)
index 0000000..6f2568f
--- /dev/null
@@ -0,0 +1,133 @@
+Metadata-Version: 1.1
+Name: MarkupSafe
+Version: 1.0
+Summary: Implements a XML/HTML/XHTML Markup safe string for Python
+Home-page: http://github.com/pallets/markupsafe
+Author: Armin Ronacher
+Author-email: armin.ronacher@active-4.com
+License: BSD
+Description: MarkupSafe
+        ==========
+        
+        Implements a unicode subclass that supports HTML strings:
+        
+        .. code-block:: python
+        
+            >>> from markupsafe import Markup, escape
+            >>> escape("<script>alert(document.cookie);</script>")
+            Markup(u'&lt;script&gt;alert(document.cookie);&lt;/script&gt;')
+            >>> tmpl = Markup("<em>%s</em>")
+            >>> tmpl % "Peter > Lustig"
+            Markup(u'<em>Peter &gt; Lustig</em>')
+        
+        If you want to make an object unicode that is not yet unicode
+        but don't want to lose the taint information, you can use the
+        ``soft_unicode`` function.  (On Python 3 you can also use ``soft_str`` which
+        is a different name for the same function).
+        
+        .. code-block:: python
+        
+            >>> from markupsafe import soft_unicode
+            >>> soft_unicode(42)
+            u'42'
+            >>> soft_unicode(Markup('foo'))
+            Markup(u'foo')
+        
+        HTML Representations
+        --------------------
+        
+        Objects can customize their HTML markup equivalent by overriding
+        the ``__html__`` function:
+        
+        .. code-block:: python
+        
+            >>> class Foo(object):
+            ...  def __html__(self):
+            ...   return '<strong>Nice</strong>'
+            ...
+            >>> escape(Foo())
+            Markup(u'<strong>Nice</strong>')
+            >>> Markup(Foo())
+            Markup(u'<strong>Nice</strong>')
+        
+        Silent Escapes
+        --------------
+        
+        Since MarkupSafe 0.10 there is now also a separate escape function
+        called ``escape_silent`` that returns an empty string for ``None`` for
+        consistency with other systems that return empty strings for ``None``
+        when escaping (for instance Pylons' webhelpers).
+        
+        If you also want to use this for the escape method of the Markup
+        object, you can create your own subclass that does that:
+        
+        .. code-block:: python
+        
+            from markupsafe import Markup, escape_silent as escape
+        
+            class SilentMarkup(Markup):
+                __slots__ = ()
+        
+                @classmethod
+                def escape(cls, s):
+                    return cls(escape(s))
+        
+        New-Style String Formatting
+        ---------------------------
+        
+        Starting with MarkupSafe 0.21 new style string formats from Python 2.6 and
+        3.x are now fully supported.  Previously the escape behavior of those
+        functions was spotty at best.  The new implementations operates under the
+        following algorithm:
+        
+        1.  if an object has an ``__html_format__`` method it is called as
+            replacement for ``__format__`` with the format specifier.  It either
+            has to return a string or markup object.
+        2.  if an object has an ``__html__`` method it is called.
+        3.  otherwise the default format system of Python kicks in and the result
+            is HTML escaped.
+        
+        Here is how you can implement your own formatting:
+        
+        .. code-block:: python
+        
+            class User(object):
+        
+                def __init__(self, id, username):
+                    self.id = id
+                    self.username = username
+        
+                def __html_format__(self, format_spec):
+                    if format_spec == 'link':
+                        return Markup('<a href="/user/{0}">{1}</a>').format(
+                            self.id,
+                            self.__html__(),
+                        )
+                    elif format_spec:
+                        raise ValueError('Invalid format spec')
+                    return self.__html__()
+        
+                def __html__(self):
+                    return Markup('<span class=user>{0}</span>').format(self.username)
+        
+        And to format that user:
+        
+        .. code-block:: python
+        
+            >>> user = User(1, 'foo')
+            >>> Markup('<p>User: {0:link}').format(user)
+            Markup(u'<p>User: <a href="/user/1"><span class=user>foo</span></a>')
+        
+        Markupsafe supports Python 2.6, 2.7 and Python 3.3 and higher.
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Text Processing :: Markup :: HTML
diff --git a/MarkupSafe.egg-info/SOURCES.txt b/MarkupSafe.egg-info/SOURCES.txt
new file mode 100644 (file)
index 0000000..210b339
--- /dev/null
@@ -0,0 +1,18 @@
+AUTHORS
+CHANGES
+LICENSE
+MANIFEST.in
+README.rst
+setup.cfg
+setup.py
+tests.py
+MarkupSafe.egg-info/PKG-INFO
+MarkupSafe.egg-info/SOURCES.txt
+MarkupSafe.egg-info/dependency_links.txt
+MarkupSafe.egg-info/not-zip-safe
+MarkupSafe.egg-info/top_level.txt
+markupsafe/__init__.py
+markupsafe/_compat.py
+markupsafe/_constants.py
+markupsafe/_native.py
+markupsafe/_speedups.c
\ No newline at end of file
diff --git a/MarkupSafe.egg-info/dependency_links.txt b/MarkupSafe.egg-info/dependency_links.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/MarkupSafe.egg-info/not-zip-safe b/MarkupSafe.egg-info/not-zip-safe
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/MarkupSafe.egg-info/top_level.txt b/MarkupSafe.egg-info/top_level.txt
new file mode 100644 (file)
index 0000000..75bf729
--- /dev/null
@@ -0,0 +1 @@
+markupsafe
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644 (file)
index 0000000..6f2568f
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,133 @@
+Metadata-Version: 1.1
+Name: MarkupSafe
+Version: 1.0
+Summary: Implements a XML/HTML/XHTML Markup safe string for Python
+Home-page: http://github.com/pallets/markupsafe
+Author: Armin Ronacher
+Author-email: armin.ronacher@active-4.com
+License: BSD
+Description: MarkupSafe
+        ==========
+        
+        Implements a unicode subclass that supports HTML strings:
+        
+        .. code-block:: python
+        
+            >>> from markupsafe import Markup, escape
+            >>> escape("<script>alert(document.cookie);</script>")
+            Markup(u'&lt;script&gt;alert(document.cookie);&lt;/script&gt;')
+            >>> tmpl = Markup("<em>%s</em>")
+            >>> tmpl % "Peter > Lustig"
+            Markup(u'<em>Peter &gt; Lustig</em>')
+        
+        If you want to make an object unicode that is not yet unicode
+        but don't want to lose the taint information, you can use the
+        ``soft_unicode`` function.  (On Python 3 you can also use ``soft_str`` which
+        is a different name for the same function).
+        
+        .. code-block:: python
+        
+            >>> from markupsafe import soft_unicode
+            >>> soft_unicode(42)
+            u'42'
+            >>> soft_unicode(Markup('foo'))
+            Markup(u'foo')
+        
+        HTML Representations
+        --------------------
+        
+        Objects can customize their HTML markup equivalent by overriding
+        the ``__html__`` function:
+        
+        .. code-block:: python
+        
+            >>> class Foo(object):
+            ...  def __html__(self):
+            ...   return '<strong>Nice</strong>'
+            ...
+            >>> escape(Foo())
+            Markup(u'<strong>Nice</strong>')
+            >>> Markup(Foo())
+            Markup(u'<strong>Nice</strong>')
+        
+        Silent Escapes
+        --------------
+        
+        Since MarkupSafe 0.10 there is now also a separate escape function
+        called ``escape_silent`` that returns an empty string for ``None`` for
+        consistency with other systems that return empty strings for ``None``
+        when escaping (for instance Pylons' webhelpers).
+        
+        If you also want to use this for the escape method of the Markup
+        object, you can create your own subclass that does that:
+        
+        .. code-block:: python
+        
+            from markupsafe import Markup, escape_silent as escape
+        
+            class SilentMarkup(Markup):
+                __slots__ = ()
+        
+                @classmethod
+                def escape(cls, s):
+                    return cls(escape(s))
+        
+        New-Style String Formatting
+        ---------------------------
+        
+        Starting with MarkupSafe 0.21 new style string formats from Python 2.6 and
+        3.x are now fully supported.  Previously the escape behavior of those
+        functions was spotty at best.  The new implementations operates under the
+        following algorithm:
+        
+        1.  if an object has an ``__html_format__`` method it is called as
+            replacement for ``__format__`` with the format specifier.  It either
+            has to return a string or markup object.
+        2.  if an object has an ``__html__`` method it is called.
+        3.  otherwise the default format system of Python kicks in and the result
+            is HTML escaped.
+        
+        Here is how you can implement your own formatting:
+        
+        .. code-block:: python
+        
+            class User(object):
+        
+                def __init__(self, id, username):
+                    self.id = id
+                    self.username = username
+        
+                def __html_format__(self, format_spec):
+                    if format_spec == 'link':
+                        return Markup('<a href="/user/{0}">{1}</a>').format(
+                            self.id,
+                            self.__html__(),
+                        )
+                    elif format_spec:
+                        raise ValueError('Invalid format spec')
+                    return self.__html__()
+        
+                def __html__(self):
+                    return Markup('<span class=user>{0}</span>').format(self.username)
+        
+        And to format that user:
+        
+        .. code-block:: python
+        
+            >>> user = User(1, 'foo')
+            >>> Markup('<p>User: {0:link}').format(user)
+            Markup(u'<p>User: <a href="/user/1"><span class=user>foo</span></a>')
+        
+        Markupsafe supports Python 2.6, 2.7 and Python 3.3 and higher.
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Text Processing :: Markup :: HTML
diff --git a/README.rst b/README.rst
new file mode 100644 (file)
index 0000000..360a087
--- /dev/null
@@ -0,0 +1,113 @@
+MarkupSafe
+==========
+
+Implements a unicode subclass that supports HTML strings:
+
+.. code-block:: python
+
+    >>> from markupsafe import Markup, escape
+    >>> escape("<script>alert(document.cookie);</script>")
+    Markup(u'&lt;script&gt;alert(document.cookie);&lt;/script&gt;')
+    >>> tmpl = Markup("<em>%s</em>")
+    >>> tmpl % "Peter > Lustig"
+    Markup(u'<em>Peter &gt; Lustig</em>')
+
+If you want to make an object unicode that is not yet unicode
+but don't want to lose the taint information, you can use the
+``soft_unicode`` function.  (On Python 3 you can also use ``soft_str`` which
+is a different name for the same function).
+
+.. code-block:: python
+
+    >>> from markupsafe import soft_unicode
+    >>> soft_unicode(42)
+    u'42'
+    >>> soft_unicode(Markup('foo'))
+    Markup(u'foo')
+
+HTML Representations
+--------------------
+
+Objects can customize their HTML markup equivalent by overriding
+the ``__html__`` function:
+
+.. code-block:: python
+
+    >>> class Foo(object):
+    ...  def __html__(self):
+    ...   return '<strong>Nice</strong>'
+    ...
+    >>> escape(Foo())
+    Markup(u'<strong>Nice</strong>')
+    >>> Markup(Foo())
+    Markup(u'<strong>Nice</strong>')
+
+Silent Escapes
+--------------
+
+Since MarkupSafe 0.10 there is now also a separate escape function
+called ``escape_silent`` that returns an empty string for ``None`` for
+consistency with other systems that return empty strings for ``None``
+when escaping (for instance Pylons' webhelpers).
+
+If you also want to use this for the escape method of the Markup
+object, you can create your own subclass that does that:
+
+.. code-block:: python
+
+    from markupsafe import Markup, escape_silent as escape
+
+    class SilentMarkup(Markup):
+        __slots__ = ()
+
+        @classmethod
+        def escape(cls, s):
+            return cls(escape(s))
+
+New-Style String Formatting
+---------------------------
+
+Starting with MarkupSafe 0.21 new style string formats from Python 2.6 and
+3.x are now fully supported.  Previously the escape behavior of those
+functions was spotty at best.  The new implementations operates under the
+following algorithm:
+
+1.  if an object has an ``__html_format__`` method it is called as
+    replacement for ``__format__`` with the format specifier.  It either
+    has to return a string or markup object.
+2.  if an object has an ``__html__`` method it is called.
+3.  otherwise the default format system of Python kicks in and the result
+    is HTML escaped.
+
+Here is how you can implement your own formatting:
+
+.. code-block:: python
+
+    class User(object):
+
+        def __init__(self, id, username):
+            self.id = id
+            self.username = username
+
+        def __html_format__(self, format_spec):
+            if format_spec == 'link':
+                return Markup('<a href="/user/{0}">{1}</a>').format(
+                    self.id,
+                    self.__html__(),
+                )
+            elif format_spec:
+                raise ValueError('Invalid format spec')
+            return self.__html__()
+
+        def __html__(self):
+            return Markup('<span class=user>{0}</span>').format(self.username)
+
+And to format that user:
+
+.. code-block:: python
+
+    >>> user = User(1, 'foo')
+    >>> Markup('<p>User: {0:link}').format(user)
+    Markup(u'<p>User: <a href="/user/1"><span class=user>foo</span></a>')
+
+Markupsafe supports Python 2.6, 2.7 and Python 3.3 and higher.
diff --git a/markupsafe/__init__.py b/markupsafe/__init__.py
new file mode 100644 (file)
index 0000000..68dc85f
--- /dev/null
@@ -0,0 +1,305 @@
+# -*- coding: utf-8 -*-
+"""
+    markupsafe
+    ~~~~~~~~~~
+
+    Implements a Markup string.
+
+    :copyright: (c) 2010 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+import re
+import string
+from collections import Mapping
+from markupsafe._compat import text_type, string_types, int_types, \
+     unichr, iteritems, PY2
+
+__version__ = "1.0"
+
+__all__ = ['Markup', 'soft_unicode', 'escape', 'escape_silent']
+
+
+_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
+_entity_re = re.compile(r'&([^& ;]+);')
+
+
+class Markup(text_type):
+    r"""Marks a string as being safe for inclusion in HTML/XML output without
+    needing to be escaped.  This implements the `__html__` interface a couple
+    of frameworks and web applications use.  :class:`Markup` is a direct
+    subclass of `unicode` and provides all the methods of `unicode` just that
+    it escapes arguments passed and always returns `Markup`.
+
+    The `escape` function returns markup objects so that double escaping can't
+    happen.
+
+    The constructor of the :class:`Markup` class can be used for three
+    different things:  When passed an unicode object it's assumed to be safe,
+    when passed an object with an HTML representation (has an `__html__`
+    method) that representation is used, otherwise the object passed is
+    converted into a unicode string and then assumed to be safe:
+
+    >>> Markup("Hello <em>World</em>!")
+    Markup(u'Hello <em>World</em>!')
+    >>> class Foo(object):
+    ...  def __html__(self):
+    ...   return '<a href="#">foo</a>'
+    ...
+    >>> Markup(Foo())
+    Markup(u'<a href="#">foo</a>')
+
+    If you want object passed being always treated as unsafe you can use the
+    :meth:`escape` classmethod to create a :class:`Markup` object:
+
+    >>> Markup.escape("Hello <em>World</em>!")
+    Markup(u'Hello &lt;em&gt;World&lt;/em&gt;!')
+
+    Operations on a markup string are markup aware which means that all
+    arguments are passed through the :func:`escape` function:
+
+    >>> em = Markup("<em>%s</em>")
+    >>> em % "foo & bar"
+    Markup(u'<em>foo &amp; bar</em>')
+    >>> strong = Markup("<strong>%(text)s</strong>")
+    >>> strong % {'text': '<blink>hacker here</blink>'}
+    Markup(u'<strong>&lt;blink&gt;hacker here&lt;/blink&gt;</strong>')
+    >>> Markup("<em>Hello</em> ") + "<foo>"
+    Markup(u'<em>Hello</em> &lt;foo&gt;')
+    """
+    __slots__ = ()
+
+    def __new__(cls, base=u'', encoding=None, errors='strict'):
+        if hasattr(base, '__html__'):
+            base = base.__html__()
+        if encoding is None:
+            return text_type.__new__(cls, base)
+        return text_type.__new__(cls, base, encoding, errors)
+
+    def __html__(self):
+        return self
+
+    def __add__(self, other):
+        if isinstance(other, string_types) or hasattr(other, '__html__'):
+            return self.__class__(super(Markup, self).__add__(self.escape(other)))
+        return NotImplemented
+
+    def __radd__(self, other):
+        if hasattr(other, '__html__') or isinstance(other, string_types):
+            return self.escape(other).__add__(self)
+        return NotImplemented
+
+    def __mul__(self, num):
+        if isinstance(num, int_types):
+            return self.__class__(text_type.__mul__(self, num))
+        return NotImplemented
+    __rmul__ = __mul__
+
+    def __mod__(self, arg):
+        if isinstance(arg, tuple):
+            arg = tuple(_MarkupEscapeHelper(x, self.escape) for x in arg)
+        else:
+            arg = _MarkupEscapeHelper(arg, self.escape)
+        return self.__class__(text_type.__mod__(self, arg))
+
+    def __repr__(self):
+        return '%s(%s)' % (
+            self.__class__.__name__,
+            text_type.__repr__(self)
+        )
+
+    def join(self, seq):
+        return self.__class__(text_type.join(self, map(self.escape, seq)))
+    join.__doc__ = text_type.join.__doc__
+
+    def split(self, *args, **kwargs):
+        return list(map(self.__class__, text_type.split(self, *args, **kwargs)))
+    split.__doc__ = text_type.split.__doc__
+
+    def rsplit(self, *args, **kwargs):
+        return list(map(self.__class__, text_type.rsplit(self, *args, **kwargs)))
+    rsplit.__doc__ = text_type.rsplit.__doc__
+
+    def splitlines(self, *args, **kwargs):
+        return list(map(self.__class__, text_type.splitlines(
+            self, *args, **kwargs)))
+    splitlines.__doc__ = text_type.splitlines.__doc__
+
+    def unescape(self):
+        r"""Unescape markup again into an text_type string.  This also resolves
+        known HTML4 and XHTML entities:
+
+        >>> Markup("Main &raquo; <em>About</em>").unescape()
+        u'Main \xbb <em>About</em>'
+        """
+        from markupsafe._constants import HTML_ENTITIES
+        def handle_match(m):
+            name = m.group(1)
+            if name in HTML_ENTITIES:
+                return unichr(HTML_ENTITIES[name])
+            try:
+                if name[:2] in ('#x', '#X'):
+                    return unichr(int(name[2:], 16))
+                elif name.startswith('#'):
+                    return unichr(int(name[1:]))
+            except ValueError:
+                pass
+            # Don't modify unexpected input.
+            return m.group()
+        return _entity_re.sub(handle_match, text_type(self))
+
+    def striptags(self):
+        r"""Unescape markup into an text_type string and strip all tags.  This
+        also resolves known HTML4 and XHTML entities.  Whitespace is
+        normalized to one:
+
+        >>> Markup("Main &raquo;  <em>About</em>").striptags()
+        u'Main \xbb About'
+        """
+        stripped = u' '.join(_striptags_re.sub('', self).split())
+        return Markup(stripped).unescape()
+
+    @classmethod
+    def escape(cls, s):
+        """Escape the string.  Works like :func:`escape` with the difference
+        that for subclasses of :class:`Markup` this function would return the
+        correct subclass.
+        """
+        rv = escape(s)
+        if rv.__class__ is not cls:
+            return cls(rv)
+        return rv
+
+    def make_simple_escaping_wrapper(name):
+        orig = getattr(text_type, name)
+        def func(self, *args, **kwargs):
+            args = _escape_argspec(list(args), enumerate(args), self.escape)
+            _escape_argspec(kwargs, iteritems(kwargs), self.escape)
+            return self.__class__(orig(self, *args, **kwargs))
+        func.__name__ = orig.__name__
+        func.__doc__ = orig.__doc__
+        return func
+
+    for method in '__getitem__', 'capitalize', \
+                  'title', 'lower', 'upper', 'replace', 'ljust', \
+                  'rjust', 'lstrip', 'rstrip', 'center', 'strip', \
+                  'translate', 'expandtabs', 'swapcase', 'zfill':
+        locals()[method] = make_simple_escaping_wrapper(method)
+
+    # new in python 2.5
+    if hasattr(text_type, 'partition'):
+        def partition(self, sep):
+            return tuple(map(self.__class__,
+                             text_type.partition(self, self.escape(sep))))
+        def rpartition(self, sep):
+            return tuple(map(self.__class__,
+                             text_type.rpartition(self, self.escape(sep))))
+
+    # new in python 2.6
+    if hasattr(text_type, 'format'):
+        def format(*args, **kwargs):
+            self, args = args[0], args[1:]
+            formatter = EscapeFormatter(self.escape)
+            kwargs = _MagicFormatMapping(args, kwargs)
+            return self.__class__(formatter.vformat(self, args, kwargs))
+
+        def __html_format__(self, format_spec):
+            if format_spec:
+                raise ValueError('Unsupported format specification '
+                                 'for Markup.')
+            return self
+
+    # not in python 3
+    if hasattr(text_type, '__getslice__'):
+        __getslice__ = make_simple_escaping_wrapper('__getslice__')
+
+    del method, make_simple_escaping_wrapper
+
+
+class _MagicFormatMapping(Mapping):
+    """This class implements a dummy wrapper to fix a bug in the Python
+    standard library for string formatting.
+
+    See http://bugs.python.org/issue13598 for information about why
+    this is necessary.
+    """
+
+    def __init__(self, args, kwargs):
+        self._args = args
+        self._kwargs = kwargs
+        self._last_index = 0
+
+    def __getitem__(self, key):
+        if key == '':
+            idx = self._last_index
+            self._last_index += 1
+            try:
+                return self._args[idx]
+            except LookupError:
+                pass
+            key = str(idx)
+        return self._kwargs[key]
+
+    def __iter__(self):
+        return iter(self._kwargs)
+
+    def __len__(self):
+        return len(self._kwargs)
+
+
+if hasattr(text_type, 'format'):
+    class EscapeFormatter(string.Formatter):
+
+        def __init__(self, escape):
+            self.escape = escape
+
+        def format_field(self, value, format_spec):
+            if hasattr(value, '__html_format__'):
+                rv = value.__html_format__(format_spec)
+            elif hasattr(value, '__html__'):
+                if format_spec:
+                    raise ValueError('No format specification allowed '
+                                     'when formatting an object with '
+                                     'its __html__ method.')
+                rv = value.__html__()
+            else:
+                # We need to make sure the format spec is unicode here as
+                # otherwise the wrong callback methods are invoked.  For
+                # instance a byte string there would invoke __str__ and
+                # not __unicode__.
+                rv = string.Formatter.format_field(
+                    self, value, text_type(format_spec))
+            return text_type(self.escape(rv))
+
+
+def _escape_argspec(obj, iterable, escape):
+    """Helper for various string-wrapped functions."""
+    for key, value in iterable:
+        if hasattr(value, '__html__') or isinstance(value, string_types):
+            obj[key] = escape(value)
+    return obj
+
+
+class _MarkupEscapeHelper(object):
+    """Helper for Markup.__mod__"""
+
+    def __init__(self, obj, escape):
+        self.obj = obj
+        self.escape = escape
+
+    __getitem__ = lambda s, x: _MarkupEscapeHelper(s.obj[x], s.escape)
+    __unicode__ = __str__ = lambda s: text_type(s.escape(s.obj))
+    __repr__ = lambda s: str(s.escape(repr(s.obj)))
+    __int__ = lambda s: int(s.obj)
+    __float__ = lambda s: float(s.obj)
+
+
+# we have to import it down here as the speedups and native
+# modules imports the markup type which is define above.
+try:
+    from markupsafe._speedups import escape, escape_silent, soft_unicode
+except ImportError:
+    from markupsafe._native import escape, escape_silent, soft_unicode
+
+if not PY2:
+    soft_str = soft_unicode
+    __all__.append('soft_str')
diff --git a/markupsafe/_compat.py b/markupsafe/_compat.py
new file mode 100644 (file)
index 0000000..62e5632
--- /dev/null
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+"""
+    markupsafe._compat
+    ~~~~~~~~~~~~~~~~~~
+
+    Compatibility module for different Python versions.
+
+    :copyright: (c) 2013 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+import sys
+
+PY2 = sys.version_info[0] == 2
+
+if not PY2:
+    text_type = str
+    string_types = (str,)
+    unichr = chr
+    int_types = (int,)
+    iteritems = lambda x: iter(x.items())
+else:
+    text_type = unicode
+    string_types = (str, unicode)
+    unichr = unichr
+    int_types = (int, long)
+    iteritems = lambda x: x.iteritems()
diff --git a/markupsafe/_constants.py b/markupsafe/_constants.py
new file mode 100644 (file)
index 0000000..919bf03
--- /dev/null
@@ -0,0 +1,267 @@
+# -*- coding: utf-8 -*-
+"""
+    markupsafe._constants
+    ~~~~~~~~~~~~~~~~~~~~~
+
+    Highlevel implementation of the Markup string.
+
+    :copyright: (c) 2010 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+
+
+HTML_ENTITIES = {
+    'AElig': 198,
+    'Aacute': 193,
+    'Acirc': 194,
+    'Agrave': 192,
+    'Alpha': 913,
+    'Aring': 197,
+    'Atilde': 195,
+    'Auml': 196,
+    'Beta': 914,
+    'Ccedil': 199,
+    'Chi': 935,
+    'Dagger': 8225,
+    'Delta': 916,
+    'ETH': 208,
+    'Eacute': 201,
+    'Ecirc': 202,
+    'Egrave': 200,
+    'Epsilon': 917,
+    'Eta': 919,
+    'Euml': 203,
+    'Gamma': 915,
+    'Iacute': 205,
+    'Icirc': 206,
+    'Igrave': 204,
+    'Iota': 921,
+    'Iuml': 207,
+    'Kappa': 922,
+    'Lambda': 923,
+    'Mu': 924,
+    'Ntilde': 209,
+    'Nu': 925,
+    'OElig': 338,
+    'Oacute': 211,
+    'Ocirc': 212,
+    'Ograve': 210,
+    'Omega': 937,
+    'Omicron': 927,
+    'Oslash': 216,
+    'Otilde': 213,
+    'Ouml': 214,
+    'Phi': 934,
+    'Pi': 928,
+    'Prime': 8243,
+    'Psi': 936,
+    'Rho': 929,
+    'Scaron': 352,
+    'Sigma': 931,
+    'THORN': 222,
+    'Tau': 932,
+    'Theta': 920,
+    'Uacute': 218,
+    'Ucirc': 219,
+    'Ugrave': 217,
+    'Upsilon': 933,
+    'Uuml': 220,
+    'Xi': 926,
+    'Yacute': 221,
+    'Yuml': 376,
+    'Zeta': 918,
+    'aacute': 225,
+    'acirc': 226,
+    'acute': 180,
+    'aelig': 230,
+    'agrave': 224,
+    'alefsym': 8501,
+    'alpha': 945,
+    'amp': 38,
+    'and': 8743,
+    'ang': 8736,
+    'apos': 39,
+    'aring': 229,
+    'asymp': 8776,
+    'atilde': 227,
+    'auml': 228,
+    'bdquo': 8222,
+    'beta': 946,
+    'brvbar': 166,
+    'bull': 8226,
+    'cap': 8745,
+    'ccedil': 231,
+    'cedil': 184,
+    'cent': 162,
+    'chi': 967,
+    'circ': 710,
+    'clubs': 9827,
+    'cong': 8773,
+    'copy': 169,
+    'crarr': 8629,
+    'cup': 8746,
+    'curren': 164,
+    'dArr': 8659,
+    'dagger': 8224,
+    'darr': 8595,
+    'deg': 176,
+    'delta': 948,
+    'diams': 9830,
+    'divide': 247,
+    'eacute': 233,
+    'ecirc': 234,
+    'egrave': 232,
+    'empty': 8709,
+    'emsp': 8195,
+    'ensp': 8194,
+    'epsilon': 949,
+    'equiv': 8801,
+    'eta': 951,
+    'eth': 240,
+    'euml': 235,
+    'euro': 8364,
+    'exist': 8707,
+    'fnof': 402,
+    'forall': 8704,
+    'frac12': 189,
+    'frac14': 188,
+    'frac34': 190,
+    'frasl': 8260,
+    'gamma': 947,
+    'ge': 8805,
+    'gt': 62,
+    'hArr': 8660,
+    'harr': 8596,
+    'hearts': 9829,
+    'hellip': 8230,
+    'iacute': 237,
+    'icirc': 238,
+    'iexcl': 161,
+    'igrave': 236,
+    'image': 8465,
+    'infin': 8734,
+    'int': 8747,
+    'iota': 953,
+    'iquest': 191,
+    'isin': 8712,
+    'iuml': 239,
+    'kappa': 954,
+    'lArr': 8656,
+    'lambda': 955,
+    'lang': 9001,
+    'laquo': 171,
+    'larr': 8592,
+    'lceil': 8968,
+    'ldquo': 8220,
+    'le': 8804,
+    'lfloor': 8970,
+    'lowast': 8727,
+    'loz': 9674,
+    'lrm': 8206,
+    'lsaquo': 8249,
+    'lsquo': 8216,
+    'lt': 60,
+    'macr': 175,
+    'mdash': 8212,
+    'micro': 181,
+    'middot': 183,
+    'minus': 8722,
+    'mu': 956,
+    'nabla': 8711,
+    'nbsp': 160,
+    'ndash': 8211,
+    'ne': 8800,
+    'ni': 8715,
+    'not': 172,
+    'notin': 8713,
+    'nsub': 8836,
+    'ntilde': 241,
+    'nu': 957,
+    'oacute': 243,
+    'ocirc': 244,
+    'oelig': 339,
+    'ograve': 242,
+    'oline': 8254,
+    'omega': 969,
+    'omicron': 959,
+    'oplus': 8853,
+    'or': 8744,
+    'ordf': 170,
+    'ordm': 186,
+    'oslash': 248,
+    'otilde': 245,
+    'otimes': 8855,
+    'ouml': 246,
+    'para': 182,
+    'part': 8706,
+    'permil': 8240,
+    'perp': 8869,
+    'phi': 966,
+    'pi': 960,
+    'piv': 982,
+    'plusmn': 177,
+    'pound': 163,
+    'prime': 8242,
+    'prod': 8719,
+    'prop': 8733,
+    'psi': 968,
+    'quot': 34,
+    'rArr': 8658,
+    'radic': 8730,
+    'rang': 9002,
+    'raquo': 187,
+    'rarr': 8594,
+    'rceil': 8969,
+    'rdquo': 8221,
+    'real': 8476,
+    'reg': 174,
+    'rfloor': 8971,
+    'rho': 961,
+    'rlm': 8207,
+    'rsaquo': 8250,
+    'rsquo': 8217,
+    'sbquo': 8218,
+    'scaron': 353,
+    'sdot': 8901,
+    'sect': 167,
+    'shy': 173,
+    'sigma': 963,
+    'sigmaf': 962,
+    'sim': 8764,
+    'spades': 9824,
+    'sub': 8834,
+    'sube': 8838,
+    'sum': 8721,
+    'sup': 8835,
+    'sup1': 185,
+    'sup2': 178,
+    'sup3': 179,
+    'supe': 8839,
+    'szlig': 223,
+    'tau': 964,
+    'there4': 8756,
+    'theta': 952,
+    'thetasym': 977,
+    'thinsp': 8201,
+    'thorn': 254,
+    'tilde': 732,
+    'times': 215,
+    'trade': 8482,
+    'uArr': 8657,
+    'uacute': 250,
+    'uarr': 8593,
+    'ucirc': 251,
+    'ugrave': 249,
+    'uml': 168,
+    'upsih': 978,
+    'upsilon': 965,
+    'uuml': 252,
+    'weierp': 8472,
+    'xi': 958,
+    'yacute': 253,
+    'yen': 165,
+    'yuml': 255,
+    'zeta': 950,
+    'zwj': 8205,
+    'zwnj': 8204
+}
diff --git a/markupsafe/_native.py b/markupsafe/_native.py
new file mode 100644 (file)
index 0000000..5e83f10
--- /dev/null
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+"""
+    markupsafe._native
+    ~~~~~~~~~~~~~~~~~~
+
+    Native Python implementation the C module is not compiled.
+
+    :copyright: (c) 2010 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+from markupsafe import Markup
+from markupsafe._compat import text_type
+
+
+def escape(s):
+    """Convert the characters &, <, >, ' and " in string s to HTML-safe
+    sequences.  Use this if you need to display text that might contain
+    such characters in HTML.  Marks return value as markup string.
+    """
+    if hasattr(s, '__html__'):
+        return s.__html__()
+    return Markup(text_type(s)
+        .replace('&', '&amp;')
+        .replace('>', '&gt;')
+        .replace('<', '&lt;')
+        .replace("'", '&#39;')
+        .replace('"', '&#34;')
+    )
+
+
+def escape_silent(s):
+    """Like :func:`escape` but converts `None` into an empty
+    markup string.
+    """
+    if s is None:
+        return Markup()
+    return escape(s)
+
+
+def soft_unicode(s):
+    """Make a string unicode if it isn't already.  That way a markup
+    string is not converted back to unicode.
+    """
+    if not isinstance(s, text_type):
+        s = text_type(s)
+    return s
diff --git a/markupsafe/_speedups.c b/markupsafe/_speedups.c
new file mode 100644 (file)
index 0000000..d779a68
--- /dev/null
@@ -0,0 +1,239 @@
+/**
+ * markupsafe._speedups
+ * ~~~~~~~~~~~~~~~~~~~~
+ *
+ * This module implements functions for automatic escaping in C for better
+ * performance.
+ *
+ * :copyright: (c) 2010 by Armin Ronacher.
+ * :license: BSD.
+ */
+
+#include <Python.h>
+
+#define ESCAPED_CHARS_TABLE_SIZE 63
+#define UNICHR(x) (PyUnicode_AS_UNICODE((PyUnicodeObject*)PyUnicode_DecodeASCII(x, strlen(x), NULL)));
+
+#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
+typedef int Py_ssize_t;
+#define PY_SSIZE_T_MAX INT_MAX
+#define PY_SSIZE_T_MIN INT_MIN
+#endif
+
+
+static PyObject* markup;
+static Py_ssize_t escaped_chars_delta_len[ESCAPED_CHARS_TABLE_SIZE];
+static Py_UNICODE *escaped_chars_repl[ESCAPED_CHARS_TABLE_SIZE];
+
+static int
+init_constants(void)
+{
+       PyObject *module;
+       /* mapping of characters to replace */
+       escaped_chars_repl['"'] = UNICHR("&#34;");
+       escaped_chars_repl['\''] = UNICHR("&#39;");
+       escaped_chars_repl['&'] = UNICHR("&amp;");
+       escaped_chars_repl['<'] = UNICHR("&lt;");
+       escaped_chars_repl['>'] = UNICHR("&gt;");
+
+       /* lengths of those characters when replaced - 1 */
+       memset(escaped_chars_delta_len, 0, sizeof (escaped_chars_delta_len));
+       escaped_chars_delta_len['"'] = escaped_chars_delta_len['\''] = \
+               escaped_chars_delta_len['&'] = 4;
+       escaped_chars_delta_len['<'] = escaped_chars_delta_len['>'] = 3;
+
+       /* import markup type so that we can mark the return value */
+       module = PyImport_ImportModule("markupsafe");
+       if (!module)
+               return 0;
+       markup = PyObject_GetAttrString(module, "Markup");
+       Py_DECREF(module);
+
+       return 1;
+}
+
+static PyObject*
+escape_unicode(PyUnicodeObject *in)
+{
+       PyUnicodeObject *out;
+       Py_UNICODE *inp = PyUnicode_AS_UNICODE(in);
+       const Py_UNICODE *inp_end = PyUnicode_AS_UNICODE(in) + PyUnicode_GET_SIZE(in);
+       Py_UNICODE *next_escp;
+       Py_UNICODE *outp;
+       Py_ssize_t delta=0, erepl=0, delta_len=0;
+
+       /* First we need to figure out how long the escaped string will be */
+       while (*(inp) || inp < inp_end) {
+               if (*inp < ESCAPED_CHARS_TABLE_SIZE) {
+                       delta += escaped_chars_delta_len[*inp];
+                       erepl += !!escaped_chars_delta_len[*inp];
+               }
+               ++inp;
+       }
+
+       /* Do we need to escape anything at all? */
+       if (!erepl) {
+               Py_INCREF(in);
+               return (PyObject*)in;
+       }
+
+       out = (PyUnicodeObject*)PyUnicode_FromUnicode(NULL, PyUnicode_GET_SIZE(in) + delta);
+       if (!out)
+               return NULL;
+
+       outp = PyUnicode_AS_UNICODE(out);
+       inp = PyUnicode_AS_UNICODE(in);
+       while (erepl-- > 0) {
+               /* look for the next substitution */
+               next_escp = inp;
+               while (next_escp < inp_end) {
+                       if (*next_escp < ESCAPED_CHARS_TABLE_SIZE &&
+                           (delta_len = escaped_chars_delta_len[*next_escp])) {
+                               ++delta_len;
+                               break;
+                       }
+                       ++next_escp;
+               }
+
+               if (next_escp > inp) {
+                       /* copy unescaped chars between inp and next_escp */
+                       Py_UNICODE_COPY(outp, inp, next_escp-inp);
+                       outp += next_escp - inp;
+               }
+
+               /* escape 'next_escp' */
+               Py_UNICODE_COPY(outp, escaped_chars_repl[*next_escp], delta_len);
+               outp += delta_len;
+
+               inp = next_escp + 1;
+       }
+       if (inp < inp_end)
+               Py_UNICODE_COPY(outp, inp, PyUnicode_GET_SIZE(in) - (inp - PyUnicode_AS_UNICODE(in)));
+
+       return (PyObject*)out;
+}
+
+
+static PyObject*
+escape(PyObject *self, PyObject *text)
+{
+       PyObject *s = NULL, *rv = NULL, *html;
+
+       /* we don't have to escape integers, bools or floats */
+       if (PyLong_CheckExact(text) ||
+#if PY_MAJOR_VERSION < 3
+           PyInt_CheckExact(text) ||
+#endif
+           PyFloat_CheckExact(text) || PyBool_Check(text) ||
+           text == Py_None)
+               return PyObject_CallFunctionObjArgs(markup, text, NULL);
+
+       /* if the object has an __html__ method that performs the escaping */
+       html = PyObject_GetAttrString(text, "__html__");
+       if (html) {
+               rv = PyObject_CallObject(html, NULL);
+               Py_DECREF(html);
+               return rv;
+       }
+
+       /* otherwise make the object unicode if it isn't, then escape */
+       PyErr_Clear();
+       if (!PyUnicode_Check(text)) {
+#if PY_MAJOR_VERSION < 3
+               PyObject *unicode = PyObject_Unicode(text);
+#else
+               PyObject *unicode = PyObject_Str(text);
+#endif
+               if (!unicode)
+                       return NULL;
+               s = escape_unicode((PyUnicodeObject*)unicode);
+               Py_DECREF(unicode);
+       }
+       else
+               s = escape_unicode((PyUnicodeObject*)text);
+
+       /* convert the unicode string into a markup object. */
+       rv = PyObject_CallFunctionObjArgs(markup, (PyObject*)s, NULL);
+       Py_DECREF(s);
+       return rv;
+}
+
+
+static PyObject*
+escape_silent(PyObject *self, PyObject *text)
+{
+       if (text != Py_None)
+               return escape(self, text);
+       return PyObject_CallFunctionObjArgs(markup, NULL);
+}
+
+
+static PyObject*
+soft_unicode(PyObject *self, PyObject *s)
+{
+       if (!PyUnicode_Check(s))
+#if PY_MAJOR_VERSION < 3
+               return PyObject_Unicode(s);
+#else
+               return PyObject_Str(s);
+#endif
+       Py_INCREF(s);
+       return s;
+}
+
+
+static PyMethodDef module_methods[] = {
+       {"escape", (PyCFunction)escape, METH_O,
+        "escape(s) -> markup\n\n"
+        "Convert the characters &, <, >, ', and \" in string s to HTML-safe\n"
+        "sequences.  Use this if you need to display text that might contain\n"
+        "such characters in HTML.  Marks return value as markup string."},
+       {"escape_silent", (PyCFunction)escape_silent, METH_O,
+        "escape_silent(s) -> markup\n\n"
+        "Like escape but converts None to an empty string."},
+       {"soft_unicode", (PyCFunction)soft_unicode, METH_O,
+        "soft_unicode(object) -> string\n\n"
+         "Make a string unicode if it isn't already.  That way a markup\n"
+         "string is not converted back to unicode."},
+       {NULL, NULL, 0, NULL}           /* Sentinel */
+};
+
+
+#if PY_MAJOR_VERSION < 3
+
+#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
+#define PyMODINIT_FUNC void
+#endif
+PyMODINIT_FUNC
+init_speedups(void)
+{
+       if (!init_constants())
+               return;
+
+       Py_InitModule3("markupsafe._speedups", module_methods, "");
+}
+
+#else /* Python 3.x module initialization */
+
+static struct PyModuleDef module_definition = {
+        PyModuleDef_HEAD_INIT,
+       "markupsafe._speedups",
+       NULL,
+       -1,
+       module_methods,
+       NULL,
+       NULL,
+       NULL,
+       NULL
+};
+
+PyMODINIT_FUNC
+PyInit__speedups(void)
+{
+       if (!init_constants())
+               return NULL;
+
+       return PyModule_Create(&module_definition);
+}
+
+#endif
diff --git a/setup.cfg b/setup.cfg
new file mode 100644 (file)
index 0000000..2a37914
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,8 @@
+[metadata]
+license_file = LICENSE
+
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/setup.py b/setup.py
new file mode 100755 (executable)
index 0000000..e30df8e
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+import os
+import re
+import ast
+import sys
+from setuptools import setup, Extension, Feature
+from distutils.command.build_ext import build_ext
+from distutils.errors import CCompilerError, DistutilsExecError, \
+     DistutilsPlatformError
+
+
+# fail safe compilation shamelessly stolen from the simplejson
+# setup.py file.  Original author: Bob Ippolito
+
+is_jython = 'java' in sys.platform
+is_pypy = hasattr(sys, 'pypy_version_info')
+
+with open('markupsafe/__init__.py') as f:
+    version = ast.literal_eval(re.search(
+        '^__version__\s+=\s+(.*?)$(?sm)', f.read()).group(1))
+
+
+speedups = Feature(
+    'optional C speed-enhancement module',
+    standard=True,
+    ext_modules=[
+        Extension('markupsafe._speedups', ['markupsafe/_speedups.c']),
+    ],
+)
+
+# Known errors when running build_ext.build_extension method
+ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError)
+if sys.platform == 'win32' and sys.version_info > (2, 6):
+    # 2.6's distutils.msvc9compiler can raise an IOError when failing to
+    # find the compiler
+    ext_errors += (IOError,)
+# Known errors when running build_ext.run method
+run_errors = (DistutilsPlatformError,)
+if sys.platform == 'darwin':
+    run_errors += (SystemError,)
+
+
+class BuildFailed(Exception):
+    pass
+
+
+class ve_build_ext(build_ext):
+    """This class allows C extension building to fail."""
+
+    def run(self):
+        try:
+            build_ext.run(self)
+        except run_errors:
+            raise BuildFailed()
+
+    def build_extension(self, ext):
+        try:
+            build_ext.build_extension(self, ext)
+        except ext_errors:
+            raise BuildFailed()
+        except ValueError:
+            # this can happen on Windows 64 bit, see Python issue 7511
+            if "'path'" in str(sys.exc_info()[1]): # works with Python 2 and 3
+                raise BuildFailed()
+            raise
+
+
+def echo(msg=''):
+    sys.stdout.write(msg + '\n')
+
+
+readme = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read()
+
+
+def run_setup(with_binary):
+    features = {}
+    if with_binary:
+        features['speedups'] = speedups
+    setup(
+        name='MarkupSafe',
+        version=version,
+        url='http://github.com/pallets/markupsafe',
+        license='BSD',
+        author='Armin Ronacher',
+        author_email='armin.ronacher@active-4.com',
+        description='Implements a XML/HTML/XHTML Markup safe string for Python',
+        long_description=readme,
+        zip_safe=False,
+        classifiers=[
+            'Development Status :: 5 - Production/Stable',
+            'Environment :: Web Environment',
+            'Intended Audience :: Developers',
+            'License :: OSI Approved :: BSD License',
+            'Operating System :: OS Independent',
+            'Programming Language :: Python',
+            'Programming Language :: Python :: 3',
+            'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+            'Topic :: Software Development :: Libraries :: Python Modules',
+            'Topic :: Text Processing :: Markup :: HTML'
+        ],
+        packages=['markupsafe'],
+        test_suite='tests.suite',
+        include_package_data=True,
+        cmdclass={'build_ext': ve_build_ext},
+        features=features,
+    )
+
+
+def try_building_extension():
+    try:
+        run_setup(True)
+    except BuildFailed:
+        LINE = '=' * 74
+        BUILD_EXT_WARNING = 'WARNING: The C extension could not be ' \
+                            'compiled, speedups are not enabled.'
+
+        echo(LINE)
+        echo(BUILD_EXT_WARNING)
+        echo('Failure information, if any, is above.')
+        echo('Retrying the build without the C extension now.')
+        echo()
+
+        run_setup(False)
+
+        echo(LINE)
+        echo(BUILD_EXT_WARNING)
+        echo('Plain-Python installation succeeded.')
+        echo(LINE)
+
+
+if not (is_pypy or is_jython):
+    try_building_extension()
+else:
+    run_setup(False)
diff --git a/tests.py b/tests.py
new file mode 100755 (executable)
index 0000000..7ec2acb
--- /dev/null
+++ b/tests.py
@@ -0,0 +1,208 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import gc
+import sys
+import unittest
+from markupsafe import Markup, escape, escape_silent
+from markupsafe._compat import text_type, PY2
+
+
+class MarkupTestCase(unittest.TestCase):
+
+    def test_adding(self):
+        # adding two strings should escape the unsafe one
+        unsafe = '<script type="application/x-some-script">alert("foo");</script>'
+        safe = Markup('<em>username</em>')
+        assert unsafe + safe == text_type(escape(unsafe)) + text_type(safe)
+
+    def test_string_interpolation(self):
+        # string interpolations are safe to use too
+        assert Markup('<em>%s</em>') % '<bad user>' == \
+               '<em>&lt;bad user&gt;</em>'
+        assert Markup('<em>%(username)s</em>') % {
+            'username': '<bad user>'
+        } == '<em>&lt;bad user&gt;</em>'
+
+        assert Markup('%i') % 3.14 == '3'
+        assert Markup('%.2f') % 3.14 == '3.14'
+
+    def test_type_behavior(self):
+        # an escaped object is markup too
+        assert type(Markup('foo') + 'bar') is Markup
+
+        # and it implements __html__ by returning itself
+        x = Markup("foo")
+        assert x.__html__() is x
+
+    def test_html_interop(self):
+        # it also knows how to treat __html__ objects
+        class Foo(object):
+            def __html__(self):
+                return '<em>awesome</em>'
+            def __unicode__(self):
+                return 'awesome'
+            __str__ = __unicode__
+        assert Markup(Foo()) == '<em>awesome</em>'
+        assert Markup('<strong>%s</strong>') % Foo() == \
+            '<strong><em>awesome</em></strong>'
+
+    def test_tuple_interpol(self):
+        self.assertEqual(Markup('<em>%s:%s</em>') % (
+            '<foo>',
+            '<bar>',
+        ), Markup(u'<em>&lt;foo&gt;:&lt;bar&gt;</em>'))
+
+    def test_dict_interpol(self):
+        self.assertEqual(Markup('<em>%(foo)s</em>') % {
+            'foo': '<foo>',
+        }, Markup(u'<em>&lt;foo&gt;</em>'))
+        self.assertEqual(Markup('<em>%(foo)s:%(bar)s</em>') % {
+            'foo': '<foo>',
+            'bar': '<bar>',
+        }, Markup(u'<em>&lt;foo&gt;:&lt;bar&gt;</em>'))
+
+    def test_escaping(self):
+        # escaping
+        assert escape('"<>&\'') == '&#34;&lt;&gt;&amp;&#39;'
+        assert Markup("<em>Foo &amp; Bar</em>").striptags() == "Foo & Bar"
+
+    def test_unescape(self):
+        assert Markup("&lt;test&gt;").unescape() == "<test>"
+        assert "jack & tavi are cooler than mike & russ" == \
+            Markup("jack & tavi are cooler than mike &amp; russ").unescape(), \
+            Markup("jack & tavi are cooler than mike &amp; russ").unescape()
+
+        # Test that unescape is idempotent
+        original = '&foo&#x3b;'
+        once = Markup(original).unescape()
+        twice = Markup(once).unescape()
+        expected = "&foo;"
+        assert expected == once == twice, (once, twice)
+
+    def test_formatting(self):
+        for actual, expected in (
+            (Markup('%i') % 3.14, '3'),
+            (Markup('%.2f') % 3.14159, '3.14'),
+            (Markup('%s %s %s') % ('<', 123, '>'), '&lt; 123 &gt;'),
+            (Markup('<em>{awesome}</em>').format(awesome='<awesome>'),
+             '<em>&lt;awesome&gt;</em>'),
+            (Markup('{0[1][bar]}').format([0, {'bar': '<bar/>'}]),
+             '&lt;bar/&gt;'),
+            (Markup('{0[1][bar]}').format([0, {'bar': Markup('<bar/>')}]),
+             '<bar/>')):
+            assert actual == expected, "%r should be %r!" % (actual, expected)
+
+    # This is new in 2.7
+    if sys.version_info >= (2, 7):
+        def test_formatting_empty(self):
+            formatted = Markup('{}').format(0)
+            assert formatted == Markup('0')
+
+    def test_custom_formatting(self):
+        class HasHTMLOnly(object):
+            def __html__(self):
+                return Markup('<foo>')
+
+        class HasHTMLAndFormat(object):
+            def __html__(self):
+                return Markup('<foo>')
+            def __html_format__(self, spec):
+                return Markup('<FORMAT>')
+
+        assert Markup('{0}').format(HasHTMLOnly()) == Markup('<foo>')
+        assert Markup('{0}').format(HasHTMLAndFormat()) == Markup('<FORMAT>')
+
+    def test_complex_custom_formatting(self):
+        class User(object):
+            def __init__(self, id, username):
+                self.id = id
+                self.username = username
+            def __html_format__(self, format_spec):
+                if format_spec == 'link':
+                    return Markup('<a href="/user/{0}">{1}</a>').format(
+                        self.id,
+                        self.__html__(),
+                    )
+                elif format_spec:
+                    raise ValueError('Invalid format spec')
+                return self.__html__()
+            def __html__(self):
+                return Markup('<span class=user>{0}</span>').format(self.username)
+
+        user = User(1, 'foo')
+        assert Markup('<p>User: {0:link}').format(user) == \
+            Markup('<p>User: <a href="/user/1"><span class=user>foo</span></a>')
+
+    def test_formatting_with_objects(self):
+        class Stringable(object):
+            def __unicode__(self):
+                return u'строка'
+            if PY2:
+                def __str__(self):
+                    return 'some other value'
+            else:
+                __str__ = __unicode__
+
+        assert Markup('{s}').format(s=Stringable()) == \
+            Markup(u'строка')
+
+    def test_all_set(self):
+        import markupsafe as markup
+        for item in markup.__all__:
+            getattr(markup, item)
+
+    def test_escape_silent(self):
+        assert escape_silent(None) == Markup()
+        assert escape(None) == Markup(None)
+        assert escape_silent('<foo>') == Markup(u'&lt;foo&gt;')
+
+    def test_splitting(self):
+        self.assertEqual(Markup('a b').split(), [
+            Markup('a'),
+            Markup('b')
+        ])
+        self.assertEqual(Markup('a b').rsplit(), [
+            Markup('a'),
+            Markup('b')
+        ])
+        self.assertEqual(Markup('a\nb').splitlines(), [
+            Markup('a'),
+            Markup('b')
+        ])
+
+    def test_mul(self):
+        self.assertEqual(Markup('a') * 3, Markup('aaa'))
+
+
+class MarkupLeakTestCase(unittest.TestCase):
+
+    def test_markup_leaks(self):
+        counts = set()
+        for count in range(20):
+            for item in range(1000):
+                escape("foo")
+                escape("<foo>")
+                escape(u"foo")
+                escape(u"<foo>")
+            if hasattr(sys, 'pypy_version_info'):
+                gc.collect()
+            counts.add(len(gc.get_objects()))
+        assert len(counts) == 1, 'ouch, c extension seems to ' \
+            'leak objects, got: ' + str(len(counts))
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(MarkupTestCase))
+
+    # this test only tests the c extension
+    if not hasattr(escape, 'func_code'):
+        suite.addTest(unittest.makeSuite(MarkupLeakTestCase))
+
+    return suite
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='suite')
+
+# vim:sts=4:sw=4:et: