diff options
Diffstat (limited to '')
21 files changed, 1587 insertions, 0 deletions
diff --git a/third_party/python/MarkupSafe/CHANGES.rst b/third_party/python/MarkupSafe/CHANGES.rst new file mode 100644 index 0000000000..e50fc98021 --- /dev/null +++ b/third_party/python/MarkupSafe/CHANGES.rst @@ -0,0 +1,112 @@ +Version 2.0.1 +------------- + +Released 2021-05-18 + +- Mark top-level names as exported so type checking understands + imports in user projects. :pr:`215` +- Fix some types that weren't available in Python 3.6.0. :pr:`215` + + +Version 2.0.0 +------------- + +Released 2021-05-11 + +- Drop Python 2.7, 3.4, and 3.5 support. +- ``Markup.unescape`` uses :func:`html.unescape` to support HTML5 + character references. :pr:`117` +- Add type annotations for static typing tools. :pr:`149` + + +Version 1.1.1 +------------- + +Released 2019-02-23 + +- Fix segfault when ``__html__`` method raises an exception when using + the C speedups. The exception is now propagated correctly. :pr:`109` + + +Version 1.1.0 +------------- + +Released 2018-11-05 + +- Drop support for Python 2.6 and 3.3. +- Build wheels for Linux, Mac, and Windows, allowing systems without + a compiler to take advantage of the C extension speedups. :pr:`104` +- Use newer CPython API on Python 3, resulting in a 1.5x speedup. + :pr`64` +- ``escape`` wraps ``__html__`` result in ``Markup``, consistent with + documented behavior. :pr:`69` + + +Version 1.0 +----------- + +Released 2017-03-07 + +- 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 +------------ + +Released 2013-05-22 + +- Fixed ``__mul__`` and string splitting on Python 3. + + +Version 0.17 +------------ + +Released 2013-05-21 + +- Fixed a bug with broken interpolation on tuples. + + +Version 0.16 +------------ + +Released 2013-05-20 + +- Improved Python 3 Support and removed 2to3. +- Removed support for Python 3.2 and 2.5. + + +Version 0.15 +------------ + +Released 2011-07-20 + +- Fixed a typo that caused the library to fail to install on pypy and + jython. + + +Version 0.14 +------------ + +Released 2011-07-20 + +- Release fix for 0.13. + + +Version 0.13 +------------ + +Released 2011-07-20 + +- Do not attempt to compile extension for PyPy or Jython. +- Work around some 64bit Windows issues. + + +Version 0.12 +------------ + +Released 2011-02-17 + +- Improved PyPy compatibility. diff --git a/third_party/python/MarkupSafe/LICENSE.rst b/third_party/python/MarkupSafe/LICENSE.rst new file mode 100644 index 0000000000..9d227a0cc4 --- /dev/null +++ b/third_party/python/MarkupSafe/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE 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 +HOLDER 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, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/python/MarkupSafe/MANIFEST.in b/third_party/python/MarkupSafe/MANIFEST.in new file mode 100644 index 0000000000..7dfa3f60c7 --- /dev/null +++ b/third_party/python/MarkupSafe/MANIFEST.in @@ -0,0 +1,9 @@ +include CHANGES.rst +include tox.ini +include requirements/*.txt +graft docs +prune docs/_build +graft tests +include src/markupsafe/py.typed +include src/markupsafe/*.pyi +global-exclude *.pyc diff --git a/third_party/python/MarkupSafe/PKG-INFO b/third_party/python/MarkupSafe/PKG-INFO new file mode 100644 index 0000000000..bd2f99cba8 --- /dev/null +++ b/third_party/python/MarkupSafe/PKG-INFO @@ -0,0 +1,98 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 2.0.1 +Summary: Safely add untrusted strings to HTML/XML markup. +Home-page: https://palletsprojects.com/p/markupsafe/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://markupsafe.palletsprojects.com/ +Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/markupsafe/ +Project-URL: Issue Tracker, https://github.com/pallets/markupsafe/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Description: MarkupSafe + ========== + + MarkupSafe implements a text object that escapes characters so it is + safe to use in HTML and XML. Characters that have special meanings are + replaced so that they display as the actual characters. This mitigates + injection attacks, meaning untrusted user input can safely be displayed + on a page. + + + Installing + ---------- + + Install and update using `pip`_: + + .. code-block:: text + + pip install -U MarkupSafe + + .. _pip: https://pip.pypa.io/en/stable/quickstart/ + + + Examples + -------- + + .. code-block:: pycon + + >>> from markupsafe import Markup, escape + + >>> # escape replaces special characters and wraps in Markup + >>> escape("<script>alert(document.cookie);</script>") + Markup('<script>alert(document.cookie);</script>') + + >>> # wrap in Markup to mark text "safe" and prevent escaping + >>> Markup("<strong>Hello</strong>") + Markup('<strong>hello</strong>') + + >>> escape(Markup("<strong>Hello</strong>")) + Markup('<strong>hello</strong>') + + >>> # Markup is a str subclass + >>> # methods and operators escape their arguments + >>> template = Markup("Hello <em>{name}</em>") + >>> template.format(name='"World"') + Markup('Hello <em>"World"</em>') + + + Donate + ------ + + The Pallets organization develops and supports MarkupSafe and other + popular packages. In order to grow the community of contributors and + users, and allow the maintainers to devote more time to the projects, + `please donate today`_. + + .. _please donate today: https://palletsprojects.com/donate + + + Links + ----- + + - Documentation: https://markupsafe.palletsprojects.com/ + - Changes: https://markupsafe.palletsprojects.com/changes/ + - PyPI Releases: https://pypi.org/project/MarkupSafe/ + - Source Code: https://github.com/pallets/markupsafe/ + - Issue Tracker: https://github.com/pallets/markupsafe/issues/ + - Website: https://palletsprojects.com/p/markupsafe/ + - Twitter: https://twitter.com/PalletsTeam + - Chat: https://discord.gg/pallets + +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: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst diff --git a/third_party/python/MarkupSafe/README.rst b/third_party/python/MarkupSafe/README.rst new file mode 100644 index 0000000000..273e1db40f --- /dev/null +++ b/third_party/python/MarkupSafe/README.rst @@ -0,0 +1,69 @@ +MarkupSafe +========== + +MarkupSafe implements a text object that escapes characters so it is +safe to use in HTML and XML. Characters that have special meanings are +replaced so that they display as the actual characters. This mitigates +injection attacks, meaning untrusted user input can safely be displayed +on a page. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U MarkupSafe + +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + +Examples +-------- + +.. code-block:: pycon + + >>> from markupsafe import Markup, escape + + >>> # escape replaces special characters and wraps in Markup + >>> escape("<script>alert(document.cookie);</script>") + Markup('<script>alert(document.cookie);</script>') + + >>> # wrap in Markup to mark text "safe" and prevent escaping + >>> Markup("<strong>Hello</strong>") + Markup('<strong>hello</strong>') + + >>> escape(Markup("<strong>Hello</strong>")) + Markup('<strong>hello</strong>') + + >>> # Markup is a str subclass + >>> # methods and operators escape their arguments + >>> template = Markup("Hello <em>{name}</em>") + >>> template.format(name='"World"') + Markup('Hello <em>"World"</em>') + + +Donate +------ + +The Pallets organization develops and supports MarkupSafe and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +`please donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://markupsafe.palletsprojects.com/ +- Changes: https://markupsafe.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/MarkupSafe/ +- Source Code: https://github.com/pallets/markupsafe/ +- Issue Tracker: https://github.com/pallets/markupsafe/issues/ +- Website: https://palletsprojects.com/p/markupsafe/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets diff --git a/third_party/python/MarkupSafe/requirements/dev.txt b/third_party/python/MarkupSafe/requirements/dev.txt new file mode 100644 index 0000000000..0dbc2bc860 --- /dev/null +++ b/third_party/python/MarkupSafe/requirements/dev.txt @@ -0,0 +1,132 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile requirements/dev.in +# +alabaster==0.7.12 + # via sphinx +appdirs==1.4.4 + # via virtualenv +attrs==21.2.0 + # via pytest +babel==2.9.1 + # via sphinx +certifi==2020.12.5 + # via requests +cfgv==3.2.0 + # via pre-commit +chardet==4.0.0 + # via requests +click==8.0.0 + # via pip-tools +distlib==0.3.1 + # via virtualenv +docutils==0.17.1 + # via sphinx +filelock==3.0.12 + # via + # tox + # virtualenv +identify==2.2.4 + # via pre-commit +idna==2.10 + # via requests +imagesize==1.2.0 + # via sphinx +iniconfig==1.1.1 + # via pytest +jinja2==3.0.0 + # via sphinx +markupsafe==2.0.0 + # via jinja2 +mypy-extensions==0.4.3 + # via mypy +mypy==0.812 + # via -r requirements/typing.in +nodeenv==1.6.0 + # via pre-commit +packaging==20.9 + # via + # pallets-sphinx-themes + # pytest + # sphinx + # tox +pallets-sphinx-themes==2.0.0 + # via -r requirements/docs.in +pep517==0.10.0 + # via pip-tools +pip-tools==6.1.0 + # via -r requirements/dev.in +pluggy==0.13.1 + # via + # pytest + # tox +pre-commit==2.12.1 + # via -r requirements/dev.in +py==1.10.0 + # via + # pytest + # tox +pygments==2.9.0 + # via sphinx +pyparsing==2.4.7 + # via packaging +pytest==6.2.4 + # via -r requirements/tests.in +pytz==2021.1 + # via babel +pyyaml==5.4.1 + # via pre-commit +requests==2.25.1 + # via sphinx +six==1.16.0 + # via + # tox + # virtualenv +snowballstemmer==2.1.0 + # via sphinx +sphinx-issues==1.2.0 + # via -r requirements/docs.in +git+https://github.com/sphinx-doc/sphinx.git@96dbe5e3 + # via + # -r requirements/docs.in + # pallets-sphinx-themes + # sphinx-issues + # sphinxcontrib-log-cabinet +sphinxcontrib-applehelp==1.0.2 + # via sphinx +sphinxcontrib-devhelp==1.0.2 + # via sphinx +sphinxcontrib-htmlhelp==1.0.3 + # via sphinx +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-log-cabinet==1.0.1 + # via -r requirements/docs.in +sphinxcontrib-qthelp==1.0.3 + # via sphinx +sphinxcontrib-serializinghtml==1.1.4 + # via sphinx +toml==0.10.2 + # via + # pep517 + # pre-commit + # pytest + # tox +tox==3.23.1 + # via -r requirements/dev.in +typed-ast==1.4.3 + # via mypy +typing-extensions==3.10.0.0 + # via mypy +urllib3==1.26.4 + # via requests +virtualenv==20.4.6 + # via + # pre-commit + # tox + +# The following packages are considered to be unsafe in a requirements file: +# pip +# setuptools diff --git a/third_party/python/MarkupSafe/requirements/docs.txt b/third_party/python/MarkupSafe/requirements/docs.txt new file mode 100644 index 0000000000..ec9cfcb668 --- /dev/null +++ b/third_party/python/MarkupSafe/requirements/docs.txt @@ -0,0 +1,67 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile requirements/docs.in +# +alabaster==0.7.12 + # via sphinx +babel==2.9.1 + # via sphinx +certifi==2020.12.5 + # via requests +chardet==4.0.0 + # via requests +docutils==0.17.1 + # via sphinx +idna==2.10 + # via requests +imagesize==1.2.0 + # via sphinx +jinja2==3.0.0 + # via sphinx +markupsafe==2.0.0 + # via jinja2 +packaging==20.9 + # via + # pallets-sphinx-themes + # sphinx +pallets-sphinx-themes==2.0.0 + # via -r requirements/docs.in +pygments==2.9.0 + # via sphinx +pyparsing==2.4.7 + # via packaging +pytz==2021.1 + # via babel +requests==2.25.1 + # via sphinx +snowballstemmer==2.1.0 + # via sphinx +sphinx-issues==1.2.0 + # via -r requirements/docs.in +git+https://github.com/sphinx-doc/sphinx.git@96dbe5e3 + # via + # -r requirements/docs.in + # pallets-sphinx-themes + # sphinx-issues + # sphinxcontrib-log-cabinet +sphinxcontrib-applehelp==1.0.2 + # via sphinx +sphinxcontrib-devhelp==1.0.2 + # via sphinx +sphinxcontrib-htmlhelp==1.0.3 + # via sphinx +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-log-cabinet==1.0.1 + # via -r requirements/docs.in +sphinxcontrib-qthelp==1.0.3 + # via sphinx +sphinxcontrib-serializinghtml==1.1.4 + # via sphinx +urllib3==1.26.4 + # via requests + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/third_party/python/MarkupSafe/requirements/tests.txt b/third_party/python/MarkupSafe/requirements/tests.txt new file mode 100644 index 0000000000..4ff31e3187 --- /dev/null +++ b/third_party/python/MarkupSafe/requirements/tests.txt @@ -0,0 +1,22 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile requirements/tests.in +# +attrs==21.2.0 + # via pytest +iniconfig==1.1.1 + # via pytest +packaging==20.9 + # via pytest +pluggy==0.13.1 + # via pytest +py==1.10.0 + # via pytest +pyparsing==2.4.7 + # via packaging +pytest==6.2.4 + # via -r requirements/tests.in +toml==0.10.2 + # via pytest diff --git a/third_party/python/MarkupSafe/requirements/typing.txt b/third_party/python/MarkupSafe/requirements/typing.txt new file mode 100644 index 0000000000..0e342aaad8 --- /dev/null +++ b/third_party/python/MarkupSafe/requirements/typing.txt @@ -0,0 +1,14 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile requirements/typing.in +# +mypy-extensions==0.4.3 + # via mypy +mypy==0.812 + # via -r requirements/typing.in +typed-ast==1.4.3 + # via mypy +typing-extensions==3.10.0.0 + # via mypy diff --git a/third_party/python/MarkupSafe/setup.cfg b/third_party/python/MarkupSafe/setup.cfg new file mode 100644 index 0000000000..1bbc1d4ceb --- /dev/null +++ b/third_party/python/MarkupSafe/setup.cfg @@ -0,0 +1,86 @@ +[metadata] +name = MarkupSafe +version = attr: markupsafe.__version__ +url = https://palletsprojects.com/p/markupsafe/ +project_urls = + Donate = https://palletsprojects.com/donate + Documentation = https://markupsafe.palletsprojects.com/ + Changes = https://markupsafe.palletsprojects.com/changes/ + Source Code = https://github.com/pallets/markupsafe/ + Issue Tracker = https://github.com/pallets/markupsafe/issues/ + Twitter = https://twitter.com/PalletsTeam + Chat = https://discord.gg/pallets +license = BSD-3-Clause +license_files = LICENSE.rst +author = Armin Ronacher +author_email = armin.ronacher@active-4.com +maintainer = Pallets +maintainer_email = contact@palletsprojects.com +description = Safely add untrusted strings to HTML/XML markup. +long_description = file: README.rst +long_description_content_type = text/x-rst +classifiers = + Development Status :: 5 - Production/Stable + Environment :: Web Environment + Intended Audience :: Developers + License :: OSI Approved :: BSD License + Operating System :: OS Independent + Programming Language :: Python + Topic :: Internet :: WWW/HTTP :: Dynamic Content + Topic :: Text Processing :: Markup :: HTML + +[options] +packages = find: +package_dir = = src +include_package_data = true +python_requires = >= 3.6 + +[options.packages.find] +where = src + +[tool:pytest] +testpaths = tests +filterwarnings = + error + +[coverage:run] +branch = true +source = + markupsafe + tests + +[coverage:paths] +source = + src + */site-packages + +[flake8] +select = B, E, F, W, B9 +ignore = + E203 + E501 + E722 + W503 +max-line-length = 80 + +[mypy] +files = src/markupsafe +python_version = 3.6 +disallow_subclassing_any = True +disallow_untyped_calls = True +disallow_untyped_defs = True +disallow_incomplete_defs = True +no_implicit_optional = True +local_partial_types = True +no_implicit_reexport = True +strict_equality = True +warn_redundant_casts = True +warn_unused_configs = True +warn_unused_ignores = True +warn_return_any = True +warn_unreachable = True + +[egg_info] +tag_build = +tag_date = 0 + diff --git a/third_party/python/MarkupSafe/setup.py b/third_party/python/MarkupSafe/setup.py new file mode 100644 index 0000000000..c6ee5bf176 --- /dev/null +++ b/third_party/python/MarkupSafe/setup.py @@ -0,0 +1,81 @@ +import os +import platform +import sys +from distutils.errors import CCompilerError +from distutils.errors import DistutilsExecError +from distutils.errors import DistutilsPlatformError + +from setuptools import Extension +from setuptools import setup +from setuptools.command.build_ext import build_ext + +ext_modules = [Extension("markupsafe._speedups", ["src/markupsafe/_speedups.c"])] + + +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 DistutilsPlatformError: + raise BuildFailed() + + def build_extension(self, ext): + try: + build_ext.build_extension(self, ext) + except (CCompilerError, DistutilsExecError, DistutilsPlatformError): + 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 run_setup(with_binary): + setup( + name="MarkupSafe", + cmdclass={"build_ext": ve_build_ext}, + ext_modules=ext_modules if with_binary else [], + ) + + +def show_message(*lines): + print("=" * 74) + for line in lines: + print(line) + print("=" * 74) + + +supports_speedups = platform.python_implementation() not in {"PyPy", "Jython"} + +if os.environ.get("CIBUILDWHEEL", "0") == "1" and supports_speedups: + run_setup(True) +elif supports_speedups: + try: + run_setup(True) + except BuildFailed: + show_message( + "WARNING: The C extension could not be compiled, speedups" + " are not enabled.", + "Failure information, if any, is above.", + "Retrying the build without the C extension now.", + ) + run_setup(False) + show_message( + "WARNING: The C extension could not be compiled, speedups" + " are not enabled.", + "Plain-Python build succeeded.", + ) +else: + run_setup(False) + show_message( + "WARNING: C extensions are not supported on this Python" + " platform, speedups are not enabled.", + "Plain-Python build succeeded.", + ) diff --git a/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/PKG-INFO b/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/PKG-INFO new file mode 100644 index 0000000000..bd2f99cba8 --- /dev/null +++ b/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/PKG-INFO @@ -0,0 +1,98 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 2.0.1 +Summary: Safely add untrusted strings to HTML/XML markup. +Home-page: https://palletsprojects.com/p/markupsafe/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://markupsafe.palletsprojects.com/ +Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/markupsafe/ +Project-URL: Issue Tracker, https://github.com/pallets/markupsafe/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Description: MarkupSafe + ========== + + MarkupSafe implements a text object that escapes characters so it is + safe to use in HTML and XML. Characters that have special meanings are + replaced so that they display as the actual characters. This mitigates + injection attacks, meaning untrusted user input can safely be displayed + on a page. + + + Installing + ---------- + + Install and update using `pip`_: + + .. code-block:: text + + pip install -U MarkupSafe + + .. _pip: https://pip.pypa.io/en/stable/quickstart/ + + + Examples + -------- + + .. code-block:: pycon + + >>> from markupsafe import Markup, escape + + >>> # escape replaces special characters and wraps in Markup + >>> escape("<script>alert(document.cookie);</script>") + Markup('<script>alert(document.cookie);</script>') + + >>> # wrap in Markup to mark text "safe" and prevent escaping + >>> Markup("<strong>Hello</strong>") + Markup('<strong>hello</strong>') + + >>> escape(Markup("<strong>Hello</strong>")) + Markup('<strong>hello</strong>') + + >>> # Markup is a str subclass + >>> # methods and operators escape their arguments + >>> template = Markup("Hello <em>{name}</em>") + >>> template.format(name='"World"') + Markup('Hello <em>"World"</em>') + + + Donate + ------ + + The Pallets organization develops and supports MarkupSafe and other + popular packages. In order to grow the community of contributors and + users, and allow the maintainers to devote more time to the projects, + `please donate today`_. + + .. _please donate today: https://palletsprojects.com/donate + + + Links + ----- + + - Documentation: https://markupsafe.palletsprojects.com/ + - Changes: https://markupsafe.palletsprojects.com/changes/ + - PyPI Releases: https://pypi.org/project/MarkupSafe/ + - Source Code: https://github.com/pallets/markupsafe/ + - Issue Tracker: https://github.com/pallets/markupsafe/issues/ + - Website: https://palletsprojects.com/p/markupsafe/ + - Twitter: https://twitter.com/PalletsTeam + - Chat: https://discord.gg/pallets + +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: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst diff --git a/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/SOURCES.txt b/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/SOURCES.txt new file mode 100644 index 0000000000..3f8c1a146d --- /dev/null +++ b/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/SOURCES.txt @@ -0,0 +1,34 @@ +CHANGES.rst +LICENSE.rst +MANIFEST.in +README.rst +setup.cfg +setup.py +tox.ini +docs/Makefile +docs/changes.rst +docs/conf.py +docs/escaping.rst +docs/formatting.rst +docs/html.rst +docs/index.rst +docs/license.rst +docs/make.bat +requirements/dev.txt +requirements/docs.txt +requirements/tests.txt +requirements/typing.txt +src/MarkupSafe.egg-info/PKG-INFO +src/MarkupSafe.egg-info/SOURCES.txt +src/MarkupSafe.egg-info/dependency_links.txt +src/MarkupSafe.egg-info/top_level.txt +src/markupsafe/__init__.py +src/markupsafe/_native.py +src/markupsafe/_speedups.c +src/markupsafe/_speedups.pyi +src/markupsafe/py.typed +tests/conftest.py +tests/test_escape.py +tests/test_exception_custom_html.py +tests/test_leak.py +tests/test_markupsafe.py
\ No newline at end of file diff --git a/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/dependency_links.txt b/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/dependency_links.txt new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/top_level.txt b/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/top_level.txt new file mode 100644 index 0000000000..75bf729258 --- /dev/null +++ b/third_party/python/MarkupSafe/src/MarkupSafe.egg-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/third_party/python/MarkupSafe/src/markupsafe/__init__.py b/third_party/python/MarkupSafe/src/markupsafe/__init__.py new file mode 100644 index 0000000000..d331ac3622 --- /dev/null +++ b/third_party/python/MarkupSafe/src/markupsafe/__init__.py @@ -0,0 +1,288 @@ +import functools +import re +import string +import typing as t + +if t.TYPE_CHECKING: + import typing_extensions as te + + class HasHTML(te.Protocol): + def __html__(self) -> str: + pass + + +__version__ = "2.0.1" + +_striptags_re = re.compile(r"(<!--.*?-->|<[^>]*>)") + + +def _simple_escaping_wrapper(name: str) -> t.Callable[..., "Markup"]: + orig = getattr(str, name) + + @functools.wraps(orig) + def wrapped(self: "Markup", *args: t.Any, **kwargs: t.Any) -> "Markup": + args = _escape_argspec(list(args), enumerate(args), self.escape) # type: ignore + _escape_argspec(kwargs, kwargs.items(), self.escape) + return self.__class__(orig(self, *args, **kwargs)) + + return wrapped + + +class Markup(str): + """A string that is ready to be safely inserted into an HTML or XML + document, either because it was escaped or because it was marked + safe. + + Passing an object to the constructor converts it to text and wraps + it to mark it safe without escaping. To escape the text, use the + :meth:`escape` class method instead. + + >>> Markup("Hello, <em>World</em>!") + Markup('Hello, <em>World</em>!') + >>> Markup(42) + Markup('42') + >>> Markup.escape("Hello, <em>World</em>!") + Markup('Hello <em>World</em>!') + + This implements the ``__html__()`` interface that some frameworks + use. Passing an object that implements ``__html__()`` will wrap the + output of that method, marking it safe. + + >>> class Foo: + ... def __html__(self): + ... return '<a href="/foo">foo</a>' + ... + >>> Markup(Foo()) + Markup('<a href="/foo">foo</a>') + + This is a subclass of :class:`str`. It has the same methods, but + escapes their arguments and returns a ``Markup`` instance. + + >>> Markup("<em>%s</em>") % ("foo & bar",) + Markup('<em>foo & bar</em>') + >>> Markup("<em>Hello</em> ") + "<foo>" + Markup('<em>Hello</em> <foo>') + """ + + __slots__ = () + + def __new__( + cls, base: t.Any = "", encoding: t.Optional[str] = None, errors: str = "strict" + ) -> "Markup": + if hasattr(base, "__html__"): + base = base.__html__() + + if encoding is None: + return super().__new__(cls, base) + + return super().__new__(cls, base, encoding, errors) + + def __html__(self) -> "Markup": + return self + + def __add__(self, other: t.Union[str, "HasHTML"]) -> "Markup": + if isinstance(other, str) or hasattr(other, "__html__"): + return self.__class__(super().__add__(self.escape(other))) + + return NotImplemented + + def __radd__(self, other: t.Union[str, "HasHTML"]) -> "Markup": + if isinstance(other, str) or hasattr(other, "__html__"): + return self.escape(other).__add__(self) + + return NotImplemented + + def __mul__(self, num: int) -> "Markup": + if isinstance(num, int): + return self.__class__(super().__mul__(num)) + + return NotImplemented # type: ignore + + __rmul__ = __mul__ + + def __mod__(self, arg: t.Any) -> "Markup": + if isinstance(arg, tuple): + arg = tuple(_MarkupEscapeHelper(x, self.escape) for x in arg) + else: + arg = _MarkupEscapeHelper(arg, self.escape) + + return self.__class__(super().__mod__(arg)) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({super().__repr__()})" + + def join(self, seq: t.Iterable[t.Union[str, "HasHTML"]]) -> "Markup": + return self.__class__(super().join(map(self.escape, seq))) + + join.__doc__ = str.join.__doc__ + + def split( # type: ignore + self, sep: t.Optional[str] = None, maxsplit: int = -1 + ) -> t.List["Markup"]: + return [self.__class__(v) for v in super().split(sep, maxsplit)] + + split.__doc__ = str.split.__doc__ + + def rsplit( # type: ignore + self, sep: t.Optional[str] = None, maxsplit: int = -1 + ) -> t.List["Markup"]: + return [self.__class__(v) for v in super().rsplit(sep, maxsplit)] + + rsplit.__doc__ = str.rsplit.__doc__ + + def splitlines(self, keepends: bool = False) -> t.List["Markup"]: # type: ignore + return [self.__class__(v) for v in super().splitlines(keepends)] + + splitlines.__doc__ = str.splitlines.__doc__ + + def unescape(self) -> str: + """Convert escaped markup back into a text string. This replaces + HTML entities with the characters they represent. + + >>> Markup("Main » <em>About</em>").unescape() + 'Main » <em>About</em>' + """ + from html import unescape + + return unescape(str(self)) + + def striptags(self) -> str: + """:meth:`unescape` the markup, remove tags, and normalize + whitespace to single spaces. + + >>> Markup("Main »\t<em>About</em>").striptags() + 'Main » About' + """ + stripped = " ".join(_striptags_re.sub("", self).split()) + return Markup(stripped).unescape() + + @classmethod + def escape(cls, s: t.Any) -> "Markup": + """Escape a string. Calls :func:`escape` and ensures that for + subclasses the correct type is returned. + """ + rv = escape(s) + + if rv.__class__ is not cls: + return cls(rv) + + return rv + + for method in ( + "__getitem__", + "capitalize", + "title", + "lower", + "upper", + "replace", + "ljust", + "rjust", + "lstrip", + "rstrip", + "center", + "strip", + "translate", + "expandtabs", + "swapcase", + "zfill", + ): + locals()[method] = _simple_escaping_wrapper(method) + + del method + + def partition(self, sep: str) -> t.Tuple["Markup", "Markup", "Markup"]: + l, s, r = super().partition(self.escape(sep)) + cls = self.__class__ + return cls(l), cls(s), cls(r) + + def rpartition(self, sep: str) -> t.Tuple["Markup", "Markup", "Markup"]: + l, s, r = super().rpartition(self.escape(sep)) + cls = self.__class__ + return cls(l), cls(s), cls(r) + + def format(self, *args: t.Any, **kwargs: t.Any) -> "Markup": + formatter = EscapeFormatter(self.escape) + return self.__class__(formatter.vformat(self, args, kwargs)) + + def __html_format__(self, format_spec: str) -> "Markup": + if format_spec: + raise ValueError("Unsupported format specification for Markup.") + + return self + + +class EscapeFormatter(string.Formatter): + __slots__ = ("escape",) + + def __init__(self, escape: t.Callable[[t.Any], Markup]) -> None: + self.escape = escape + super().__init__() + + def format_field(self, value: t.Any, format_spec: str) -> str: + if hasattr(value, "__html_format__"): + rv = value.__html_format__(format_spec) + elif hasattr(value, "__html__"): + if format_spec: + raise ValueError( + f"Format specifier {format_spec} given, but {type(value)} does not" + " define __html_format__. A class that defines __html__ must define" + " __html_format__ to work with format specifiers." + ) + rv = value.__html__() + else: + # We need to make sure the format spec is str here as + # otherwise the wrong callback methods are invoked. + rv = string.Formatter.format_field(self, value, str(format_spec)) + return str(self.escape(rv)) + + +_ListOrDict = t.TypeVar("_ListOrDict", list, dict) + + +def _escape_argspec( + obj: _ListOrDict, iterable: t.Iterable[t.Any], escape: t.Callable[[t.Any], Markup] +) -> _ListOrDict: + """Helper for various string-wrapped functions.""" + for key, value in iterable: + if isinstance(value, str) or hasattr(value, "__html__"): + obj[key] = escape(value) + + return obj + + +class _MarkupEscapeHelper: + """Helper for :meth:`Markup.__mod__`.""" + + __slots__ = ("obj", "escape") + + def __init__(self, obj: t.Any, escape: t.Callable[[t.Any], Markup]) -> None: + self.obj = obj + self.escape = escape + + def __getitem__(self, item: t.Any) -> "_MarkupEscapeHelper": + return _MarkupEscapeHelper(self.obj[item], self.escape) + + def __str__(self) -> str: + return str(self.escape(self.obj)) + + def __repr__(self) -> str: + return str(self.escape(repr(self.obj))) + + def __int__(self) -> int: + return int(self.obj) + + def __float__(self) -> float: + return float(self.obj) + + +# circular import +try: + from ._speedups import escape as escape + from ._speedups import escape_silent as escape_silent + from ._speedups import soft_str as soft_str + from ._speedups import soft_unicode +except ImportError: + from ._native import escape as escape + from ._native import escape_silent as escape_silent # noqa: F401 + from ._native import soft_str as soft_str # noqa: F401 + from ._native import soft_unicode # noqa: F401 diff --git a/third_party/python/MarkupSafe/src/markupsafe/_native.py b/third_party/python/MarkupSafe/src/markupsafe/_native.py new file mode 100644 index 0000000000..6f7eb7a8cb --- /dev/null +++ b/third_party/python/MarkupSafe/src/markupsafe/_native.py @@ -0,0 +1,75 @@ +import typing as t + +from . import Markup + + +def escape(s: t.Any) -> Markup: + """Replace the characters ``&``, ``<``, ``>``, ``'``, and ``"`` in + the string with HTML-safe sequences. Use this if you need to display + text that might contain such characters in HTML. + + If the object has an ``__html__`` method, it is called and the + return value is assumed to already be safe for HTML. + + :param s: An object to be converted to a string and escaped. + :return: A :class:`Markup` string with the escaped text. + """ + if hasattr(s, "__html__"): + return Markup(s.__html__()) + + return Markup( + str(s) + .replace("&", "&") + .replace(">", ">") + .replace("<", "<") + .replace("'", "'") + .replace('"', """) + ) + + +def escape_silent(s: t.Optional[t.Any]) -> Markup: + """Like :func:`escape` but treats ``None`` as the empty string. + Useful with optional values, as otherwise you get the string + ``'None'`` when the value is ``None``. + + >>> escape(None) + Markup('None') + >>> escape_silent(None) + Markup('') + """ + if s is None: + return Markup() + + return escape(s) + + +def soft_str(s: t.Any) -> str: + """Convert an object to a string if it isn't already. This preserves + a :class:`Markup` string rather than converting it back to a basic + string, so it will still be marked as safe and won't be escaped + again. + + >>> value = escape("<User 1>") + >>> value + Markup('<User 1>') + >>> escape(str(value)) + Markup('&lt;User 1&gt;') + >>> escape(soft_str(value)) + Markup('<User 1>') + """ + if not isinstance(s, str): + return str(s) + + return s + + +def soft_unicode(s: t.Any) -> str: + import warnings + + warnings.warn( + "'soft_unicode' has been renamed to 'soft_str'. The old name" + " will be removed in MarkupSafe 2.1.", + DeprecationWarning, + stacklevel=2, + ) + return soft_str(s) diff --git a/third_party/python/MarkupSafe/src/markupsafe/_speedups.c b/third_party/python/MarkupSafe/src/markupsafe/_speedups.c new file mode 100644 index 0000000000..44967b1fdc --- /dev/null +++ b/third_party/python/MarkupSafe/src/markupsafe/_speedups.c @@ -0,0 +1,339 @@ +#include <Python.h> + +static PyObject* markup; + +static int +init_constants(void) +{ + PyObject *module; + + /* 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; +} + +#define GET_DELTA(inp, inp_end, delta) \ + while (inp < inp_end) { \ + switch (*inp++) { \ + case '"': \ + case '\'': \ + case '&': \ + delta += 4; \ + break; \ + case '<': \ + case '>': \ + delta += 3; \ + break; \ + } \ + } + +#define DO_ESCAPE(inp, inp_end, outp) \ + { \ + Py_ssize_t ncopy = 0; \ + while (inp < inp_end) { \ + switch (*inp) { \ + case '"': \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + outp += ncopy; ncopy = 0; \ + *outp++ = '&'; \ + *outp++ = '#'; \ + *outp++ = '3'; \ + *outp++ = '4'; \ + *outp++ = ';'; \ + break; \ + case '\'': \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + outp += ncopy; ncopy = 0; \ + *outp++ = '&'; \ + *outp++ = '#'; \ + *outp++ = '3'; \ + *outp++ = '9'; \ + *outp++ = ';'; \ + break; \ + case '&': \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + outp += ncopy; ncopy = 0; \ + *outp++ = '&'; \ + *outp++ = 'a'; \ + *outp++ = 'm'; \ + *outp++ = 'p'; \ + *outp++ = ';'; \ + break; \ + case '<': \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + outp += ncopy; ncopy = 0; \ + *outp++ = '&'; \ + *outp++ = 'l'; \ + *outp++ = 't'; \ + *outp++ = ';'; \ + break; \ + case '>': \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + outp += ncopy; ncopy = 0; \ + *outp++ = '&'; \ + *outp++ = 'g'; \ + *outp++ = 't'; \ + *outp++ = ';'; \ + break; \ + default: \ + ncopy++; \ + } \ + inp++; \ + } \ + memcpy(outp, inp-ncopy, sizeof(*outp)*ncopy); \ + } + +static PyObject* +escape_unicode_kind1(PyUnicodeObject *in) +{ + Py_UCS1 *inp = PyUnicode_1BYTE_DATA(in); + Py_UCS1 *inp_end = inp + PyUnicode_GET_LENGTH(in); + Py_UCS1 *outp; + PyObject *out; + Py_ssize_t delta = 0; + + GET_DELTA(inp, inp_end, delta); + if (!delta) { + Py_INCREF(in); + return (PyObject*)in; + } + + out = PyUnicode_New(PyUnicode_GET_LENGTH(in) + delta, + PyUnicode_IS_ASCII(in) ? 127 : 255); + if (!out) + return NULL; + + inp = PyUnicode_1BYTE_DATA(in); + outp = PyUnicode_1BYTE_DATA(out); + DO_ESCAPE(inp, inp_end, outp); + return out; +} + +static PyObject* +escape_unicode_kind2(PyUnicodeObject *in) +{ + Py_UCS2 *inp = PyUnicode_2BYTE_DATA(in); + Py_UCS2 *inp_end = inp + PyUnicode_GET_LENGTH(in); + Py_UCS2 *outp; + PyObject *out; + Py_ssize_t delta = 0; + + GET_DELTA(inp, inp_end, delta); + if (!delta) { + Py_INCREF(in); + return (PyObject*)in; + } + + out = PyUnicode_New(PyUnicode_GET_LENGTH(in) + delta, 65535); + if (!out) + return NULL; + + inp = PyUnicode_2BYTE_DATA(in); + outp = PyUnicode_2BYTE_DATA(out); + DO_ESCAPE(inp, inp_end, outp); + return out; +} + + +static PyObject* +escape_unicode_kind4(PyUnicodeObject *in) +{ + Py_UCS4 *inp = PyUnicode_4BYTE_DATA(in); + Py_UCS4 *inp_end = inp + PyUnicode_GET_LENGTH(in); + Py_UCS4 *outp; + PyObject *out; + Py_ssize_t delta = 0; + + GET_DELTA(inp, inp_end, delta); + if (!delta) { + Py_INCREF(in); + return (PyObject*)in; + } + + out = PyUnicode_New(PyUnicode_GET_LENGTH(in) + delta, 1114111); + if (!out) + return NULL; + + inp = PyUnicode_4BYTE_DATA(in); + outp = PyUnicode_4BYTE_DATA(out); + DO_ESCAPE(inp, inp_end, outp); + return out; +} + +static PyObject* +escape_unicode(PyUnicodeObject *in) +{ + if (PyUnicode_READY(in)) + return NULL; + + switch (PyUnicode_KIND(in)) { + case PyUnicode_1BYTE_KIND: + return escape_unicode_kind1(in); + case PyUnicode_2BYTE_KIND: + return escape_unicode_kind2(in); + case PyUnicode_4BYTE_KIND: + return escape_unicode_kind4(in); + } + assert(0); /* shouldn't happen */ + return NULL; +} + +static PyObject* +escape(PyObject *self, PyObject *text) +{ + static PyObject *id_html; + PyObject *s = NULL, *rv = NULL, *html; + + if (id_html == NULL) { + id_html = PyUnicode_InternFromString("__html__"); + if (id_html == NULL) { + return NULL; + } + } + + /* we don't have to escape integers, bools or floats */ + if (PyLong_CheckExact(text) || + 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_GetAttr(text ,id_html); + if (html) { + s = PyObject_CallObject(html, NULL); + Py_DECREF(html); + if (s == NULL) { + return NULL; + } + /* Convert to Markup object */ + rv = PyObject_CallFunctionObjArgs(markup, (PyObject*)s, NULL); + Py_DECREF(s); + return rv; + } + + /* otherwise make the object unicode if it isn't, then escape */ + PyErr_Clear(); + if (!PyUnicode_Check(text)) { + PyObject *unicode = PyObject_Str(text); + 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_str(PyObject *self, PyObject *s) +{ + if (!PyUnicode_Check(s)) + return PyObject_Str(s); + Py_INCREF(s); + return s; +} + + +static PyObject* +soft_unicode(PyObject *self, PyObject *s) +{ + PyErr_WarnEx( + PyExc_DeprecationWarning, + "'soft_unicode' has been renamed to 'soft_str'. The old name" + " will be removed in MarkupSafe 2.1.", + 2 + ); + return soft_str(self, s); +} + + +static PyMethodDef module_methods[] = { + { + "escape", + (PyCFunction)escape, + METH_O, + "Replace the characters ``&``, ``<``, ``>``, ``'``, and ``\"`` in" + " the string with HTML-safe sequences. Use this if you need to display" + " text that might contain such characters in HTML.\n\n" + "If the object has an ``__html__`` method, it is called and the" + " return value is assumed to already be safe for HTML.\n\n" + ":param s: An object to be converted to a string and escaped.\n" + ":return: A :class:`Markup` string with the escaped text.\n" + }, + { + "escape_silent", + (PyCFunction)escape_silent, + METH_O, + "Like :func:`escape` but treats ``None`` as the empty string." + " Useful with optional values, as otherwise you get the string" + " ``'None'`` when the value is ``None``.\n\n" + ">>> escape(None)\n" + "Markup('None')\n" + ">>> escape_silent(None)\n" + "Markup('')\n" + }, + { + "soft_str", + (PyCFunction)soft_str, + METH_O, + "Convert an object to a string if it isn't already. This preserves" + " a :class:`Markup` string rather than converting it back to a basic" + " string, so it will still be marked as safe and won't be escaped" + " again.\n\n" + ">>> value = escape(\"<User 1>\")\n" + ">>> value\n" + "Markup('<User 1>')\n" + ">>> escape(str(value))\n" + "Markup('&lt;User 1&gt;')\n" + ">>> escape(soft_str(value))\n" + "Markup('<User 1>')\n" + }, + { + "soft_unicode", + (PyCFunction)soft_unicode, + METH_O, + "" + }, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +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); +} diff --git a/third_party/python/MarkupSafe/src/markupsafe/_speedups.pyi b/third_party/python/MarkupSafe/src/markupsafe/_speedups.pyi new file mode 100644 index 0000000000..f673240f6d --- /dev/null +++ b/third_party/python/MarkupSafe/src/markupsafe/_speedups.pyi @@ -0,0 +1,9 @@ +from typing import Any +from typing import Optional + +from . import Markup + +def escape(s: Any) -> Markup: ... +def escape_silent(s: Optional[Any]) -> Markup: ... +def soft_str(s: Any) -> str: ... +def soft_unicode(s: Any) -> str: ... diff --git a/third_party/python/MarkupSafe/src/markupsafe/py.typed b/third_party/python/MarkupSafe/src/markupsafe/py.typed new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/third_party/python/MarkupSafe/src/markupsafe/py.typed diff --git a/third_party/python/MarkupSafe/tox.ini b/third_party/python/MarkupSafe/tox.ini new file mode 100644 index 0000000000..de68730f28 --- /dev/null +++ b/third_party/python/MarkupSafe/tox.ini @@ -0,0 +1,24 @@ +[tox] +envlist = + py{39,38,37,36,py3} + style + typing + docs +skip_missing_interpreters = true + +[testenv] +deps = -r requirements/tests.txt +commands = pytest -v --tb=short --basetemp={envtmpdir} {posargs} + +[testenv:style] +deps = pre-commit +skip_install = true +commands = pre-commit run --all-files --show-diff-on-failure + +[testenv:typing] +deps = -r requirements/typing.txt +commands = mypy + +[testenv:docs] +deps = -r requirements/docs.txt +commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs {envtmpdir}/html |