Details

Configuration

The preceding discussion assumes you import Dash packages under the usual names:

import dash_html_components as html
import dash_core_components as dcc
import dash_table

If this does not match your preferences, you can customize the mappings used by htexpr:

import dash_html_components as H
import dash_core_components as C

import htexpr
from htexpr import mappings

tags = [mappings.html('H'), mappings.dcc('C')]

def compile(code):
    return htexpr.compile(code, map_tag=tags)

There is a prebuilt configuration for Dash Bootstrap components:

import dash_html_components as html
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import htexpr
from htexpr import mappings

def compile(code):
    return htexpr.compile(code, map_tag=mappings.dbc_and_default)

layout = compile("""
    <Container class="p-5"><Alert>Hello Bootstrap!</Alert></Container>
""").run()

The Bootstrap components shadow some HTML components, but there is a trick to work around this: if you need to use an HTML component, just use upper/lowercase letters differently from the Bootstrap components.

compile("""
  <div>
    <Label>this is a Bootstrap label</Label>
    <label>this is an HTML label</label>
  </div>
""")

Htexpr objects

The compile function returns an Htexpr object, which encapsulates the Python code resulting from the compilation. This object needs to be evaluated to result in actual Dash objects. Because the Python code refers to various objects (such as imported modules, functions, and variables) these need to be passed in:

import dash_html_components as html
htexpr.compile(
    "<div>[(<span>{i}</span>) for i in range(10) if i not in removed]</div>"
).eval({**globals(), "removed": {1, 2, 3}})

The compiled code is able to refer to html.Div because html occurs in globals(), and to the removed variable because it is included in the bindings manually. Similarly, local variables can be included with **locals().

Including **globals() and **locals() every time gets tedious, so there is a small magic trick to do it automatically:

import dash_html_components as html
htexpr.compile(
    "<div>[(<span>{i}</span>) for i in range(10) if i not in removed]</div>"
).run(removed={1, 2, 3})

The run method peeks into the caller’s frame and automatically includes all the global and local bindings. Any keyword arguments are added on top of these.

Peeking into frames is discouraged by some Python developers and involves calling a private function, so the eval method is recommended for anyone who is worried.