diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/Makefile | 19 | ||||
-rw-r--r-- | docs/changes.rst | 4 | ||||
-rw-r--r-- | docs/conf.py | 52 | ||||
-rw-r--r-- | docs/escaping.rst | 21 | ||||
-rw-r--r-- | docs/formatting.rst | 77 | ||||
-rw-r--r-- | docs/html.rst | 49 | ||||
-rw-r--r-- | docs/index.rst | 47 | ||||
-rw-r--r-- | docs/license.rst | 4 | ||||
-rw-r--r-- | docs/make.bat | 35 |
9 files changed, 308 insertions, 0 deletions
diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..5128596 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/changes.rst b/docs/changes.rst new file mode 100644 index 0000000..955deaf --- /dev/null +++ b/docs/changes.rst @@ -0,0 +1,4 @@ +Changes +======= + +.. include:: ../CHANGES.rst diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..bba34c0 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,52 @@ +from pallets_sphinx_themes import get_version +from pallets_sphinx_themes import ProjectLink + +# Project -------------------------------------------------------------- + +project = "MarkupSafe" +copyright = "2010 Pallets" +author = "Pallets" +release, version = get_version("MarkupSafe") + +# General -------------------------------------------------------------- + +master_doc = "index" +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.intersphinx", + "pallets_sphinx_themes", + "sphinxcontrib.log_cabinet", + "sphinx_issues", +] +autodoc_typehints = "description" +intersphinx_mapping = {"python": ("https://docs.python.org/3/", None)} +issues_github_path = "pallets/markupsafe" + +# HTML ----------------------------------------------------------------- + +html_theme = "jinja" +html_theme_options = {"index_sidebar_logo": False} +html_context = { + "project_links": [ + ProjectLink("Donate", "https://palletsprojects.com/donate"), + ProjectLink("PyPI Releases", "https://pypi.org/project/MarkupSafe/"), + ProjectLink("Source Code", "https://github.com/pallets/markupsafe/"), + ProjectLink("Issue Tracker", "https://github.com/pallets/markupsafe/issues/"), + ProjectLink("Website", "https://palletsprojects.com/p/markupsafe/"), + ProjectLink("Twitter", "https://twitter.com/PalletsTeam"), + ProjectLink("Chat", "https://discord.gg/pallets"), + ] +} +html_sidebars = { + "index": ["project.html", "localtoc.html", "searchbox.html", "ethicalads.html"], + "**": ["localtoc.html", "relations.html", "searchbox.html", "ethicalads.html"], +} +singlehtml_sidebars = {"index": ["project.html", "localtoc.html", "ethicalads.html"]} +html_title = f"MarkupSafe Documentation ({version})" +html_show_sourcelink = False + +# LaTeX ---------------------------------------------------------------- + +latex_documents = [ + (master_doc, f"MarkupSafe-{version}.tex", html_title, author, "manual") +] diff --git a/docs/escaping.rst b/docs/escaping.rst new file mode 100644 index 0000000..9e7000a --- /dev/null +++ b/docs/escaping.rst @@ -0,0 +1,21 @@ +.. module:: markupsafe + +Working With Safe Text +====================== + +.. autofunction:: escape + +.. autoclass:: Markup + :members: escape, unescape, striptags + + +Optional Values +--------------- + +.. autofunction:: escape_silent + + +Convert an Object to a String +----------------------------- + +.. autofunction:: soft_str diff --git a/docs/formatting.rst b/docs/formatting.rst new file mode 100644 index 0000000..c14f917 --- /dev/null +++ b/docs/formatting.rst @@ -0,0 +1,77 @@ +.. currentmodule:: markupsafe + +String Formatting +================= + +The :class:`Markup` class can be used as a format string. Objects +formatted into a markup string will be escaped first. + + +Format Method +------------- + +The ``format`` method extends the standard :meth:`str.format` behavior +to use an ``__html_format__`` method. + +#. If an object has an ``__html_format__`` method, it is called as a + replacement for the ``__format__`` method. It is passed a format + specifier if it's given. The method must return a string or + :class:`Markup` instance. + +#. If an object has an ``__html__`` method, it is called. If a format + specifier was passed and the class defined ``__html__`` but not + ``__html_format__``, a ``ValueError`` is raised. + +#. Otherwise Python's default format behavior is used and the result + is escaped. + +For example, to implement a ``User`` that wraps its ``name`` in a +``span`` tag, and adds a link when using the ``"link"`` format +specifier: + +.. code-block:: python + + class User(object): + def __init__(self, id, name): + self.id = id + self.name = name + + def __html_format__(self, format_spec): + if format_spec == "link": + return Markup( + '<a href="/user/{}">{}</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.name) + + +.. code-block:: pycon + + >>> user = User(3, "<script>") + >>> escape(user) + Markup('<span class="user"><script></span>') + >>> Markup("<p>User: {user:link}").format(user=user) + Markup('<p>User: <a href="/user/3"><span class="user"><script></span></a> + +See Python's docs on :ref:`format string syntax <python:formatstrings>`. + + +printf-style Formatting +----------------------- + +Besides escaping, there's no special behavior involved with percent +formatting. + +.. code-block:: pycon + + >>> user = User(3, "<script>") + >>> Markup('<a href="/user/%d">%s</a>') % (user.id, user.name) + Markup('<a href="/user/3"><script></a>') + +See Python's docs on :ref:`printf-style formatting <python:old-string-formatting>`. diff --git a/docs/html.rst b/docs/html.rst new file mode 100644 index 0000000..dec87af --- /dev/null +++ b/docs/html.rst @@ -0,0 +1,49 @@ +.. currentmodule:: markupsafe + +HTML Representations +==================== + +In many frameworks, if a class implements an ``__html__`` method it +will be used to get the object's representation in HTML. MarkupSafe's +:func:`escape` function and :class:`Markup` class understand and +implement this method. If an object has an ``__html__`` method it will +be called rather than converting the object to a string, and the result +will be assumed safe and not escaped. + +For example, an ``Image`` class might automatically generate an +``<img>`` tag: + +.. code-block:: python + + class Image: + def __init__(self, url): + self.url = url + + def __html__(self): + return f'<img src="{self.url}">' + +.. code-block:: pycon + + >>> img = Image("/static/logo.png") + >>> Markup(img) + Markup('<img src="/static/logo.png">') + +Since this bypasses escaping, you need to be careful about using +user-provided data in the output. For example, a user's display name +should still be escaped: + +.. code-block:: python + + class User: + def __init__(self, id, name): + self.id = id + self.name = name + + def __html__(self): + return f'<a href="/user/{self.id}">{escape(self.name)}</a>' + +.. code-block:: pycon + + >>> user = User(3, "<script>") + >>> escape(user) + Markup('<a href="/users/3"><script></a>') diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..5c45e64 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,47 @@ +.. currentmodule:: markupsafe + +MarkupSafe +========== + +MarkupSafe escapes characters so text 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. + +The :func:`escape` function escapes text and returns a :class:`Markup` +object. The object won't be escaped anymore, but any text that is used +with it will be, ensuring that the result remains safe to use in HTML. + +>>> from markupsafe import escape +>>> hello = escape("<em>Hello</em>") +>>> hello +Markup('<em>Hello</em>') +>>> escape(hello) +Markup('<em>Hello</em>') +>>> hello + " <strong>World</strong>" +Markup('<em>Hello</em> <strong>World</strong>') + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U MarkupSafe + +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + +Table of Contents +----------------- + +.. toctree:: + :maxdepth: 2 + + escaping + html + formatting + license + changes diff --git a/docs/license.rst b/docs/license.rst new file mode 100644 index 0000000..a53a98c --- /dev/null +++ b/docs/license.rst @@ -0,0 +1,4 @@ +BSD-3-Clause License +==================== + +.. include:: ../LICENSE.rst diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..7893348 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd |