Skip to content

Add support for PEP 750 template strings to CustomJS, etc. #14649

@mattpap

Description

@mattpap

This will be a Python 3.14+ specific feature. It will allow simplified and possibly more readable CustomJS, advanced templates in HoverTool, and perhaps useful in other contexts. As an example, CustomJS currently requires to separately provide all arguments used in the code, e.g.:

from bokeh.io import show
from bokeh.layouts import row
from bokeh.models import CustomJS, Div, Switch

switch = Switch(label="Toggle state:", active=True)
div = Div()
switch.js_on_change("active", CustomJS(args=dict(div=div), code="""
    const state = this.active ? "ON" : "OFF"
    div.text = `Current state: ${state}`
"""))
show(row([switch, div]))

Using string templates would allow to replace this with:

from bokeh.io import show
from bokeh.layouts import row
from bokeh.models import CustomJS, Div, Switch

switch = Switch(label="Toggle state:", active=True)
div = Div()
switch.js_on_change("active", CustomJS(code=t"""
    const state = this.active ? "ON" : "OFF"
    {div}.text = `Current state: ${{state}}`
"""))
show(row([switch, div]))

assuming CustomJS.code allows values of the new Template type. However, for the sake of experimentation we can implement this ad-hoc as a function:

from bokeh.io import show
from bokeh.layouts import row
from bokeh.models import CustomJS, Div, Switch

switch = Switch(label="Toggle state:", active=True)
div = Div()

from string.templatelib import Template, Interpolation
from typing import Any

def custom_js(template: Template) -> CustomJS:
    args: dict[str, Any] = {}
    code = ""
    for item in template:
        if isinstance(item, Interpolation):
            name = item.expression
            args[name] = item.value
            code += name
        else:
            code += item
    return CustomJS(args=args, code=code)

switch.js_on_change("active", custom_js(t"""
    const state = this.active ? "ON" : "OFF"
    {div}.text = `Current state: ${{state}}`
"""))
show(row([switch, div]))

If you want to try this out, you need Python 3.14 (currently rc3). You can install it like this:

conda create -n bk_py3.14rc3 python=3.14.0rc3 conda-forge/label/python_rc::_python_rc

Metadata

Metadata

Assignees

Labels

pythonIssues that should only require updating Python codetype: feature

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions