Took me forever to find it, but, yes, it’s documented in the Custom Filters part of the Jinja documentation.
You can tell it’s a filter because there’s a “
|” in front of it. Its first positional parameter is the stuff to the left of the “
|”. Additional positional parameters show up in the parentheses, and some filters also take specific named parameters. If you’re really deep into the Python weeds, you can even pass references to parameters with “
**”, but keep your wizard hat and non-conductive soled shoes on when you do that.
Tangent alert: The first words in that section are “Filters are Python functions”, and it really is true. To be fair, Jinja is targeted at Python programmers, not application end users. This is one of the reasons I’ve called Ansible an extension of Python rather than an application written in Python. There’s just so much of the underlying language exposed to the user (or the other way around) for me to classify it otherwise. To be fair, the Ansible implementation has come a long way in the last few years toward blunting those sharp edges, but they are still there.
As a counter example, Splunk is also written in Python, but I’ve never seen hints through the user interface that would lead me to guess that. (Although, if you go to write your own Splunk “app”, you’d do it in Python. Splunk custom apps are rather like Ansible plugins in that way.)
Another way to think about the “extension of a language” vs “application written in a language” issue is this: If you were to re-implement the existing functionality in some other language, what would that look like? In the case of Ansible, the first thing you’d have to do is create something with semantics frighteningly similar to Python, and that’s the clue. Some of what in retrospect appear to be questionable design decisions in Ansible were in fact properties emergent from the implementation technologies at hand, such as Jinja, and the way they were employed in the early days.
Even farther tangent: I think it’s useful to occasionally think about such questions. If for whatever reasons we chose to start over completely, re-implementing Ansible from scratch with no backward compatible constraints, what would we keep, what would we drop like a hot rock, and what would we do in a different (presumably better) way? It’s not a realistic proposition (or is it?), but it helps shape thinking about how the project evolves. That’s where the value lies in such exercises.