Skip to main content
Package version Code coverage Supported Python versions Checked with mypy

Sanity 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 sanity-html

Usage

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

The following content

from sanity_html import SanityBlockRenderer

renderer = SanityBlockRenderer({
    "_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 sanity_html import SanityBlockRenderer

renderer = SanityBlockRenderer({
  "_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 sanity_html import SanityBlockRenderer

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

renderer = SanityBlockRenderer(
    ...,
    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 sanity_html import SanityBlockRenderer

renderer = SanityBlockRenderer(
    ...,
    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 sanity_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(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 sanity_html.marker_definitions import MarkerDefinition  # base
from sanity_html import SanityBlockRenderer

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 = SanityBlockRenderer(
    ...,
    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.

Metadata

Release files for sanity-html 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sanity-html 1.0.0
File Size Uploaded Provenance
sanity-html-1.0.0.tar.gz 14.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for sanity-html 1.0.0
File Interpreter ABI Platform
sanity_html-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 29.5 kB

Release files / sanity-html-1.0.0.tar.gz

Download URL sanity-html-1.0.0.tar.gz
Size 14.9 kB
Tags Source
SHA-256 checksum
How to use checksums
80b579366119ce3e90fb4fc1b2b9158a5b467e49ec4908d9a917649f25885bbf
BLAKE2b-256 checksum
How to use checksums
c2033d2f58210f258a39da786d66bf212519fd96deadeadbf004115c71b54a85
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.1.6 CPython/3.9.9 Linux/5.11.0-1021-azure

Release files / sanity_html-1.0.0-py3-none-any.whl

Download URL sanity_html-1.0.0-py3-none-any.whl
Size 14.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f3a805a0d523c8dd9bc14f173f41a126e6094f4bc03e55841799bfa97a81e4b8
BLAKE2b-256 checksum
How to use checksums
6d9ecb065bbb4836c3523b8153643418bce94831572bc3f99cb5518e18a6a58a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.1.6 CPython/3.9.9 Linux/5.11.0-1021-azure

Security for sanity-html 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page