PEP750: Template Strings (new updates)

I’ve been thinking a lot recently on the topic of templating. I think it’s a misstep for PEP 750 to propose a syntax here in 2024 that doesn’t support the concept of a “filter”.

If I understand correctly, Jinja2, Mako, and Django templates are the three most popular templating libraries for Python and it’s not close. All three support filters. And it turns out–while their syntaxes vary wildly in most respects, they all agree on the syntax to specify a filter. At the end of an expression in a substitution, you add:

    | <filter>

This means “evaluate the expression, turn it into a string, then apply the filter <filter> to that string” in all three libraries. Sure, they differ in how you supply arguments to a filter, and how you specify multiple filters, but all three use literally identical syntax for “apply one filter with no arguments”. I therefore assert that this is a popular feature and there’s an obvious spelling for it. And I think PEP 750 template strings should add it.

Yes, this would add a small incompatibility with f-strings, as | isn’t a special character in the f-string format spec. If a user used | in a format spec today, it’d be passed on to the object in the (non-self) argument to __format__. As a practical matter, none of the built-in objects support | in their format spec. And I admit I don’t know, but: I don’t believe there’s widespread use of custom __format__ methods, and I suspect that the ones that support custom methods don’t do anything interesting with |. Also, template strings are new and their own thing, and while I think “support everything that f-strings support” is an excellent starting point, in this case I urge you to go one step farther.

As far as what syntax to use for supplying arguments, or calling multiple filters, I think only Jinja2 got it right. To call multiple filters, you’d apply this same syntax multiple times:

    | filter1 | filter2

To supply arguments, you allow the filter spec to be an expression that produces filter you want to apply. I propose we follow in the footsteps of decorators here: limit this expression to either a single possibly-dotted symbol name, or a function call. (We could relax this restriction later if it seemed advisable.) In case I’m stating that badly, I propose we allow this the filter name to optionally be followed by a single set of parentheses which turns the filter spec into a function call:

    | filter_a(...) | filter_b | filter_c(...)

[Edit: added possibly-dotted above.]

2 Likes