Skip to main content

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

Project description

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

Test status PyPI package

Introduction

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

>>> 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.

>>> 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.

>>> 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.

>>> 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).

  • 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.

    >>> from tinyhtml import Frag
  • Write templates as functions.

    >>> 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.)

    >>> 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.

    >>> 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.

    >>> 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.

    >>> 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.

    >>> 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.

    >>> 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, or the MIT license, at your option.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tinyhtml-1.3.0.tar.gz (30.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tinyhtml-1.3.0-py3-none-any.whl (30.0 kB view details)

Uploaded Python 3

File details

Details for the file tinyhtml-1.3.0.tar.gz.

File metadata

  • Download URL: tinyhtml-1.3.0.tar.gz
  • Upload date:
  • Size: 30.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.0.1 CPython/3.13.1

File hashes

Hashes for tinyhtml-1.3.0.tar.gz
Algorithm Hash digest
SHA256 457f2683a22051ac48674e00d978f39098344546da7276a0aaef467380d3bb53
MD5 783e8f14c919e4ec25d42730ffb297a9
BLAKE2b-256 c19dde470c06fd3c02f9a14e0ac1429ccbd6320ef17bed264a225a2c85dca38a

See more details on using hashes here.

File details

Details for the file tinyhtml-1.3.0-py3-none-any.whl.

File metadata

  • Download URL: tinyhtml-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 30.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.0.1 CPython/3.13.1

File hashes

Hashes for tinyhtml-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b9a726fd3332f0a6c6ef8ef501cb1aabb6bad23ac98a61ae6ac321c605439c4b
MD5 5507a8ab3807a34256f085d43e69081f
BLAKE2b-256 bdb10f1243a6adf8363b3a46d0d98fd34850bcc3ae9d568fd7efaf6da82b653a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page