Remix.run Logo
spankalee 8 months ago

Maintainer of lit-html here, which uses tagged template literals in JavaScript extensively.

This looks really great! It's almost exactly like JavaScript tagged template literals, just with a fixed tag function of:

    (strings, ...values) => {strings, values};
It's pretty interesting how what would be the tag function in JavaScript, and the arguments to it, are separated by the Template class. At first it seems like this will add noise since it takes more characters to write, but it can make nested templates more compact.

Take this type of nested template structure in JS:

    html`<ul>${items.map((i) => html`<li>${i}</li>`}</ul>`
With PEP 750, I suppose this would be:

    html(t"<ul>{map(lambda i: t"<li>{i}</li>", items)}</ul>")
Python's unfortunate lambda syntax aside, not needing html() around nested template could be nice (assuming an html() function would interpret plain Templates as HTML).

In JavaScript reliable syntax highlighting and type-checking are keyed off the fact that a template can only ever have a single tag, so a static analyzer can know what the nested language is. In Python you could separate the template creation from the processing possibly introduce some ambiguities, but hopefully that's rare in practice.

I'm personally would be interested to see if a special html() processing instruction could both emit server-rendered HTML and say, lit-html JavaScript templates that could be used to update the DOM client-side with new data. That could lead to some very transparent fine-grained single page updates, from what looks like traditional server-only code.

pauleveritt 8 months ago | parent | next [-]

I'd like to add, after the first publication for discussion, we got some wonderful involvement from Andrea Giammarchi who brought his deep JS libraries and tools experience into the PEP. In fact, he's deeply involved in the next steps, with some forthcoming demos and libraries that will make a real difference. Exciting times.

davepeck 8 months ago | parent | prev | next [-]

> assuming an html() function would interpret plain Templates as HTML

Agreed; it feels natural to accept plain templates (and simple sequences of plain templates) as HTML; this is hinted at in the PEP.

> html(t"<ul>{map(lambda i: t"<li>{i}</li>", items)}</ul>")

Perhaps more idiomatically: html(t"<ul>{(t"<li>{i}</li>" for i in items)}</ul>")

> syntax highlighting and type-checking are keyed off the fact that a template can only ever have a single tag

Yes, this is a key difference and something we agonized a bit over as the PEP came together. In the (very) long term, I'm hopeful that we see type annotations used to indicate the expected string content type. In the nearer term, I think a certain amount of "clever kludginess" will be necessary in tools like (say) black if they wish to provide specialized formatting for common types.

> a special html() processing instruction could both emit server-rendered HTML and say, lit-html JavaScript templates that could be used to update the DOM client-side with new data

I'd love to see this and it's exactly the sort of thing I'm hoping emerges from PEP 750 over time. Please do reach out if you'd like to talk it over!

MathMonkeyMan 8 months ago | parent [-]

Python already has built-in data structure literals that allow you to express lispy DSLs:

    html(['ul', {'class': 'foo'}, *(['li', item] for item in items)])
I guess template strings do make it more concise. Kind of like Racket's "#lang at-exp racket".

The benefit of lisp-like representation is you have the entire structure of the data, not just a sequence of already-serialized and not-yet-serialized pieces.

Latty 8 months ago | parent | prev | next [-]

Generally a generator expression would be more idiomatic in Python than map/lambda.

    html(t"<ul>{(t"<li>{i}</li>" for i in items)}</ul>")
breuleux 8 months ago | parent | prev [-]

> not needing html() around nested template could be nice

One possibility would be to define __and__ on html so that you can write e.g. html&t"<b>{x}</b>" (or whichever operator looks the best).