Skip to main content

HTML renderer for Sanity's Portable Text format

Project description

pypi test code coverage supported python versions

Portable Text HTML Renderer for Python

This package generates HTML from Portable Text.

For the most part, it mirrors Sanity's own block-content-to-html NPM library.

Installation

pip install portabletext-html

Usage

Instantiate the PortableTextRenderer class with your content and call the render method.

The following content

from portabletext_html import PortableTextRenderer

renderer = PortableTextRenderer({
    "_key": "R5FvMrjo",
    "_type": "block",
    "children": [
        {"_key": "cZUQGmh4", "_type": "span", "marks": ["strong"], "text": "A word of"},
        {"_key": "toaiCqIK", "_type": "span", "marks": ["strong"], "text": " warning;"},
        {"_key": "gaZingsA", "_type": "span", "marks": [], "text": " Sanity is addictive."}
    ],
    "markDefs": [],
    "style": "normal"
})
renderer.render()

Generates this HTML

<p><strong>A word of warning;</strong> Sanity is addictive.</p>

Supported types

The block and span types are supported out of the box.

Custom types

Beyond the built-in types, you have the freedom to provide your own serializers to render any custom _type the way you would like to.

To illustrate, if you passed this data to the renderer class:

from portabletext_html import PortableTextRenderer

renderer = PortableTextRenderer({
    "_type": "block",
    "_key": "foo",
    "style": "normal",
    "children": [
        {
            "_type": "span",
            "text": "Press, "
        },
        {
            "_type": "button",
            "text": "here"
        },
        {
            "_type": "span",
            "text": ", now!"
        }
    ]
})
renderer.render()

The renderer would actually throw an error here, since button does not have a corresponding built-in type serializer by default.

To render this text you must provide your own serializer, like this:

from portabletext_html import PortableTextRenderer


def button_serializer(node: dict, context: Optional[Block], list_item: bool):
    return f'<button>{node["text"]}</button>'


renderer = PortableTextRenderer(
    ...,
    custom_serializers={'button': button_serializer}
)
output = renderer.render()

With the custom serializer provided, the renderer would now successfully output the following HTML:

<p>Press <button>here</button>, now!</p>

Supported mark definitions

The package provides several built-in marker definitions and styles:

decorator marker definitions

  • em
  • strong
  • code
  • underline
  • strike-through

annotation marker definitions

  • link
  • comment

Custom mark definitions

Like with custom type serializers, additional serializers for marker definitions and styles can be passed in like this:

from portabletext_html import PortableTextRenderer

renderer = PortableTextRenderer(
    ...,
    custom_marker_definitions={'em': ComicSansEmphasis}
)
renderer.render()

The primary difference between a type serializer and a mark definition serializer is that the latter uses a class structure, and has three required methods.

Here's an example of a custom style, adding an extra font to the built-in equivalent serializer:

from portabletext_html.marker_definitions import MarkerDefinition


class ComicSansEmphasis(MarkerDefinition):
    tag = 'em'

    @classmethod
    def render_prefix(cls, span: Span, marker: str, context: Block) -> str:
        return f'<{cls.tag} style="font-family: "Comic Sans MS", "Comic Sans", cursive;">'

    @classmethod
    def render_suffix(cls, span: Span, marker: str, context: Block) -> str:
        return f'</{cls.tag}>'

    @classmethod
    def render_text(cls, span: Span, marker: str, context: Block) -> str:
        # custom rendering logic can be placed here
        return str(span.text)

    @classmethod
    def render(cls, span: Span, marker: str, context: Block) -> str:
        result = cls.render_prefix(span, marker, context)
        result += str(span.text)
        result += cls.render_suffix(span, marker, context)
        return result

Since the render_suffix and render methods here are actually identical to the base class, they do not need to be specified, and the whole example can be reduced to:

from portabletext_html.marker_definitions import MarkerDefinition  # base
from portabletext_html import PortableTextRenderer


class ComicSansEmphasis(MarkerDefinition):
    tag = 'em'

    @classmethod
    def render_prefix(cls, span: Span, marker: str, context: Block) -> str:
        return f'<{cls.tag} style="font-family: "Comic Sans MS", "Comic Sans", cursive;">'


renderer = PortableTextRenderer(
    ...,
    custom_marker_definitions={'em': ComicSansEmphasis}
)
renderer.render()

Supported styles

Blocks can optionally define a style tag. These styles are supported:

  • h1
  • h2
  • h3
  • h4
  • h5
  • h6
  • blockquote
  • normal

Missing features

For anyone interested, we would be happy to see a default built-in serializer for the image type added. In the meantime, users should be able to serialize image types by passing a custom serializer.

Contributing

Contributions are always appreciated 👏

For details, see the CONTRIBUTING.md.

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

portabletext-html-1.1.3.tar.gz (15.0 kB view details)

Uploaded Source

Built Distribution

portabletext_html-1.1.3-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

Details for the file portabletext-html-1.1.3.tar.gz.

File metadata

  • Download URL: portabletext-html-1.1.3.tar.gz
  • Upload date:
  • Size: 15.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.6 CPython/3.9.13 Linux/5.13.0-1029-azure

File hashes

Hashes for portabletext-html-1.1.3.tar.gz
Algorithm Hash digest
SHA256 cdf8237aa720d71d38017ad80c27b0fe0a70732f30093ed741697b9f3a0f0cff
MD5 92a7ec705877bdc43c58dad633dbd9e6
BLAKE2b-256 f9acd89fc1c925f4d501a7c31400c5f68b692e986b487ada0a7a0322dda53324

See more details on using hashes here.

File details

Details for the file portabletext_html-1.1.3-py3-none-any.whl.

File metadata

  • Download URL: portabletext_html-1.1.3-py3-none-any.whl
  • Upload date:
  • Size: 15.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.6 CPython/3.9.13 Linux/5.13.0-1029-azure

File hashes

Hashes for portabletext_html-1.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 1e87a1d60e7371bb39484db636e9a4ab35820d94a1a1c3bf8985a22d42853039
MD5 8a798cd5454943a955d14dcaf6710f82
BLAKE2b-256 d68d7b27041d2c69744bc4b14ed7bf5bf7b6aa39ee4b2f77525c6c68ef9932b4

See more details on using hashes here.

Supported by

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