tinyhtml


Nametinyhtml JSON
Version 1.3.0 PyPI version JSON
download
home_pagehttps://github.com/niklasf/python-tinyhtml
SummaryA tiny library to safely render compact HTML5 from Python expressions.
upload_time2025-01-11 12:13:52
maintainerNone
docs_urlNone
authorNiklas Fiekas
requires_python>=3.8
licenseMIT/Apache-2.0
keywords html html5 vdom functional-programming
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            tinyhtml
========

A tiny library to safely render compact HTML5 from Python expressions.

.. image:: https://github.com/niklasf/python-tinyhtml/workflows/Test/badge.svg
    :target: https://github.com/niklasf/python-tinyhtml/actions
    :alt: Test status

.. image:: https://badge.fury.io/py/tinyhtml.svg
    :target: https://pypi.python.org/pypi/tinyhtml
    :alt: PyPI package

Introduction
------------

This is the entire API. The following documentation is longer than the
implementation.

.. code:: python

    >>> from tinyhtml import html, h, frag, raw

The most important function is ``h()``. Below you see how to render attributes,
normal elements, and void/self-closing elements.

.. code:: python

    >>> html(lang="en")(
    ...     h("head")(
    ...         h("meta", charset="utf-8"),
    ...     ),
    ... ).render()
    '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head></html>'

Use ``frag()`` to pass around groups of elements.

.. code:: python

    >>> frag(
    ...     h("h1")("Lorem ipsum ..."),
    ...     h("p")("... dolor sit amet."),
    ... )
    raw('<h1>Lorem ipsum ...</h1><p>... dolor sit amet.</p>')

Of course all content and attributes are properly escaped. Use ``raw()`` as an
escape hatch to render unescaped HTML.

.. code:: python

    >>> print(h("a", title="&<>\"'")("&<>\"'").render())
    <a title="&amp;&lt;&gt;&quot;'">&amp;&lt;&gt;"'</a>

    >>> print(raw("<!-- 💥"))
    <!-- 💥


Installing
----------

::

    pip install tinyhtml


Features and patterns
---------------------

* Output is compact: Naturally produces no superfluous whitespace between
  elements.

* Fragments provide ``_repr_html_()`` for Jupyter notebook integration and
  ``__html__`` for integration with other ecosystems (see
  `MarkupSafe <https://markupsafe.palletsprojects.com/en/stable/html/>`_).

* Fragments can include and render objects providing ``_repr_html_()`` and
  ``__html__()``. This means objects that already render as HTML in a
  Jupyter notebook will be rendered by tinyhtml.

* Includes mypy typings.

  .. code:: python

      >>> from tinyhtml import Frag

* Write **templates** as functions.

  .. code:: python

      >>> def layout(title: str, body: Frag) -> Frag:
      ...     return html()(
      ...        h("head")(
      ...            h("title")(title),
      ...        ),
      ...        h("body")(body)
      ...     )

      >>> layout("Hello world", frag(
      ...     h("h1")("Hello world"),
      ...     h("p")("Lorem ipsum dolor sit amet."),
      ... ))
      raw('<!DOCTYPE html><html><head><title>Hello world</title></head><body><h1>Hello world</h1><p>Lorem ipsum dolor sit amet.</p></body></html>')

* Use ``str``, ``int``, other fragments, ``None``, or iterables of these as
  **child elements**. (Note that rendering consumes the iterables, so fragments
  using generators can be rendered only once.)

  .. code:: python

      >>> h("ul")(
      ...     h("li")(n) for n in range(3)
      ... )
      raw('<ul><li>0</li><li>1</li><li>2</li></ul>')

      >>> h("ul")(
      ...     h("li")("Foo") if False else None,
      ...     h("li")("Bar"),
      ... )
      raw('<ul><li>Bar</li></ul>')

* Use ``str``, ``int``, ``None``, iterables of these, ``bool``, or dictionaries
  with boolean values as **attributes**.

  .. code:: python

      >>> h("input", type="checkbox", checked=True, disabled=False)
      raw('<input type="checkbox" checked>')

      >>> h("body", klass=["a", "b"])()
      raw('<body class="a b"></body>')

      >>> h("body", klass={
      ...    "a": True,
      ...    "b": False,
      ... })()
      raw('<body class="a"></body>')


* Use ``klass`` instead of ``class``, append a trailing underscore (``for_``),
  or use underscores instead of dashes (``http_equiv``) for attribute names
  that cannot be Python identifiers.

  .. code:: python

      >>> h("div", klass="container")()
      raw('<div class="container"></div>')

      >>> h("label", for_="name")("Name")
      raw('<label for="name">Name</label>')

      >>> h("meta", http_equiv="refresh", content=10)
      raw('<meta http-equiv="refresh" content="10">')

* Render fragments as ``str``, or into a list of ``str`` for efficient string
  building.

  .. code:: python

      >>> frag("Hello world", "!").render()
      'Hello world!'

      >>> builder = []
      >>> frag("Hello world", "!").render_into(builder)
      >>> builder
      ['Hello world', '!']
      >>> "".join(builder)
      'Hello world!'

* Does not support comment nodes, unescapable raw text elements
  (like inline styles and scripts), or foreign elements (like inline SVG).
  Instead, reference external files, or use ``raw()`` with appropriate caution.


Interoperability
----------------

Fragments implement ``_repr_html_`` and can be displayed in Jupyter notebooks
as HTML, but they can also render object that implement ``_repr_html_``.
Similarly fragments can include and be included in other template systems that
use the ``__html__`` convention, such as Jinja2 via
`MarkupSafe`_.

* Render fragments into a Jinja2 template.

  .. code:: python

      >>> import jinja2
      >>>
      >>> template = jinja2.Template('<div>{{ fragment }}</div>')
      >>> frag = h('ul')(h('li')(i) for i in range(2))
      >>> template.render(fragment=frag)
      '<div><ul><li>0</li><li>1</li></ul></div>'


* Render an object the supports display in a Jupyter notebook, such as a pandas
  dataframe.

  .. code:: python

      >>> import pandas as pd
      >>>
      >>> table = pd.DataFrame({'Fruit': ['apple', 'pear'], 'Count': [3, 4]})
      >>> h('div')(h('h1')('A table'), table) # doctest: +ELLIPSIS
      raw('<div><h1>A table</h1><div>...<table ...>...<td>apple</td>...</table>...</div>')


License
-------

Licensed under the
`Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0>`_,
or the `MIT license <https://opensource.org/licenses/MIT>`_, at your option.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/niklasf/python-tinyhtml",
    "name": "tinyhtml",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "html html5 vdom functional-programming",
    "author": "Niklas Fiekas",
    "author_email": "niklas.fiekas@backscattering.de",
    "download_url": "https://files.pythonhosted.org/packages/c1/9d/de470c06fd3c02f9a14e0ac1429ccbd6320ef17bed264a225a2c85dca38a/tinyhtml-1.3.0.tar.gz",
    "platform": null,
    "description": "tinyhtml\n========\n\nA tiny library to safely render compact HTML5 from Python expressions.\n\n.. image:: https://github.com/niklasf/python-tinyhtml/workflows/Test/badge.svg\n    :target: https://github.com/niklasf/python-tinyhtml/actions\n    :alt: Test status\n\n.. image:: https://badge.fury.io/py/tinyhtml.svg\n    :target: https://pypi.python.org/pypi/tinyhtml\n    :alt: PyPI package\n\nIntroduction\n------------\n\nThis is the entire API. The following documentation is longer than the\nimplementation.\n\n.. code:: python\n\n    >>> from tinyhtml import html, h, frag, raw\n\nThe most important function is ``h()``. Below you see how to render attributes,\nnormal elements, and void/self-closing elements.\n\n.. code:: python\n\n    >>> html(lang=\"en\")(\n    ...     h(\"head\")(\n    ...         h(\"meta\", charset=\"utf-8\"),\n    ...     ),\n    ... ).render()\n    '<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"></head></html>'\n\nUse ``frag()`` to pass around groups of elements.\n\n.. code:: python\n\n    >>> frag(\n    ...     h(\"h1\")(\"Lorem ipsum ...\"),\n    ...     h(\"p\")(\"... dolor sit amet.\"),\n    ... )\n    raw('<h1>Lorem ipsum ...</h1><p>... dolor sit amet.</p>')\n\nOf course all content and attributes are properly escaped. Use ``raw()`` as an\nescape hatch to render unescaped HTML.\n\n.. code:: python\n\n    >>> print(h(\"a\", title=\"&<>\\\"'\")(\"&<>\\\"'\").render())\n    <a title=\"&amp;&lt;&gt;&quot;'\">&amp;&lt;&gt;\"'</a>\n\n    >>> print(raw(\"<!-- \ud83d\udca5\"))\n    <!-- \ud83d\udca5\n\n\nInstalling\n----------\n\n::\n\n    pip install tinyhtml\n\n\nFeatures and patterns\n---------------------\n\n* Output is compact: Naturally produces no superfluous whitespace between\n  elements.\n\n* Fragments provide ``_repr_html_()`` for Jupyter notebook integration and\n  ``__html__`` for integration with other ecosystems (see\n  `MarkupSafe <https://markupsafe.palletsprojects.com/en/stable/html/>`_).\n\n* Fragments can include and render objects providing ``_repr_html_()`` and\n  ``__html__()``. This means objects that already render as HTML in a\n  Jupyter notebook will be rendered by tinyhtml.\n\n* Includes mypy typings.\n\n  .. code:: python\n\n      >>> from tinyhtml import Frag\n\n* Write **templates** as functions.\n\n  .. code:: python\n\n      >>> def layout(title: str, body: Frag) -> Frag:\n      ...     return html()(\n      ...        h(\"head\")(\n      ...            h(\"title\")(title),\n      ...        ),\n      ...        h(\"body\")(body)\n      ...     )\n\n      >>> layout(\"Hello world\", frag(\n      ...     h(\"h1\")(\"Hello world\"),\n      ...     h(\"p\")(\"Lorem ipsum dolor sit amet.\"),\n      ... ))\n      raw('<!DOCTYPE html><html><head><title>Hello world</title></head><body><h1>Hello world</h1><p>Lorem ipsum dolor sit amet.</p></body></html>')\n\n* Use ``str``, ``int``, other fragments, ``None``, or iterables of these as\n  **child elements**. (Note that rendering consumes the iterables, so fragments\n  using generators can be rendered only once.)\n\n  .. code:: python\n\n      >>> h(\"ul\")(\n      ...     h(\"li\")(n) for n in range(3)\n      ... )\n      raw('<ul><li>0</li><li>1</li><li>2</li></ul>')\n\n      >>> h(\"ul\")(\n      ...     h(\"li\")(\"Foo\") if False else None,\n      ...     h(\"li\")(\"Bar\"),\n      ... )\n      raw('<ul><li>Bar</li></ul>')\n\n* Use ``str``, ``int``, ``None``, iterables of these, ``bool``, or dictionaries\n  with boolean values as **attributes**.\n\n  .. code:: python\n\n      >>> h(\"input\", type=\"checkbox\", checked=True, disabled=False)\n      raw('<input type=\"checkbox\" checked>')\n\n      >>> h(\"body\", klass=[\"a\", \"b\"])()\n      raw('<body class=\"a b\"></body>')\n\n      >>> h(\"body\", klass={\n      ...    \"a\": True,\n      ...    \"b\": False,\n      ... })()\n      raw('<body class=\"a\"></body>')\n\n\n* Use ``klass`` instead of ``class``, append a trailing underscore (``for_``),\n  or use underscores instead of dashes (``http_equiv``) for attribute names\n  that cannot be Python identifiers.\n\n  .. code:: python\n\n      >>> h(\"div\", klass=\"container\")()\n      raw('<div class=\"container\"></div>')\n\n      >>> h(\"label\", for_=\"name\")(\"Name\")\n      raw('<label for=\"name\">Name</label>')\n\n      >>> h(\"meta\", http_equiv=\"refresh\", content=10)\n      raw('<meta http-equiv=\"refresh\" content=\"10\">')\n\n* Render fragments as ``str``, or into a list of ``str`` for efficient string\n  building.\n\n  .. code:: python\n\n      >>> frag(\"Hello world\", \"!\").render()\n      'Hello world!'\n\n      >>> builder = []\n      >>> frag(\"Hello world\", \"!\").render_into(builder)\n      >>> builder\n      ['Hello world', '!']\n      >>> \"\".join(builder)\n      'Hello world!'\n\n* Does not support comment nodes, unescapable raw text elements\n  (like inline styles and scripts), or foreign elements (like inline SVG).\n  Instead, reference external files, or use ``raw()`` with appropriate caution.\n\n\nInteroperability\n----------------\n\nFragments implement ``_repr_html_`` and can be displayed in Jupyter notebooks\nas HTML, but they can also render object that implement ``_repr_html_``.\nSimilarly fragments can include and be included in other template systems that\nuse the ``__html__`` convention, such as Jinja2 via\n`MarkupSafe`_.\n\n* Render fragments into a Jinja2 template.\n\n  .. code:: python\n\n      >>> import jinja2\n      >>>\n      >>> template = jinja2.Template('<div>{{ fragment }}</div>')\n      >>> frag = h('ul')(h('li')(i) for i in range(2))\n      >>> template.render(fragment=frag)\n      '<div><ul><li>0</li><li>1</li></ul></div>'\n\n\n* Render an object the supports display in a Jupyter notebook, such as a pandas\n  dataframe.\n\n  .. code:: python\n\n      >>> import pandas as pd\n      >>>\n      >>> table = pd.DataFrame({'Fruit': ['apple', 'pear'], 'Count': [3, 4]})\n      >>> h('div')(h('h1')('A table'), table) # doctest: +ELLIPSIS\n      raw('<div><h1>A table</h1><div>...<table ...>...<td>apple</td>...</table>...</div>')\n\n\nLicense\n-------\n\nLicensed under the\n`Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0>`_,\nor the `MIT license <https://opensource.org/licenses/MIT>`_, at your option.\n",
    "bugtrack_url": null,
    "license": "MIT/Apache-2.0",
    "summary": "A tiny library to safely render compact HTML5 from Python expressions.",
    "version": "1.3.0",
    "project_urls": {
        "Homepage": "https://github.com/niklasf/python-tinyhtml"
    },
    "split_keywords": [
        "html",
        "html5",
        "vdom",
        "functional-programming"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "bdb10f1243a6adf8363b3a46d0d98fd34850bcc3ae9d568fd7efaf6da82b653a",
                "md5": "5507a8ab3807a34256f085d43e69081f",
                "sha256": "b9a726fd3332f0a6c6ef8ef501cb1aabb6bad23ac98a61ae6ac321c605439c4b"
            },
            "downloads": -1,
            "filename": "tinyhtml-1.3.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5507a8ab3807a34256f085d43e69081f",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 29993,
            "upload_time": "2025-01-11T12:13:49",
            "upload_time_iso_8601": "2025-01-11T12:13:49.747095Z",
            "url": "https://files.pythonhosted.org/packages/bd/b1/0f1243a6adf8363b3a46d0d98fd34850bcc3ae9d568fd7efaf6da82b653a/tinyhtml-1.3.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c19dde470c06fd3c02f9a14e0ac1429ccbd6320ef17bed264a225a2c85dca38a",
                "md5": "783e8f14c919e4ec25d42730ffb297a9",
                "sha256": "457f2683a22051ac48674e00d978f39098344546da7276a0aaef467380d3bb53"
            },
            "downloads": -1,
            "filename": "tinyhtml-1.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "783e8f14c919e4ec25d42730ffb297a9",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 30529,
            "upload_time": "2025-01-11T12:13:52",
            "upload_time_iso_8601": "2025-01-11T12:13:52.762306Z",
            "url": "https://files.pythonhosted.org/packages/c1/9d/de470c06fd3c02f9a14e0ac1429ccbd6320ef17bed264a225a2c85dca38a/tinyhtml-1.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-01-11 12:13:52",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "niklasf",
    "github_project": "python-tinyhtml",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "tinyhtml"
}
        
Elapsed time: 1.56522s