Skip to content

The template_filter decorator doesn't work if you don't pass an argument #5729

@alexwlchan

Description

@alexwlchan

What's the issue?

You can use template_filter as a decorator, but it only registers the filter if you write an explicit name or an empty set of parentheses. If you call it without parens, the filter doesn't get registered.

It's a small difference and can be confusing.

Minimal example

Consider the following program:

from flask import Flask, render_template_string


app = Flask(__name__)


@app.template_filter
def double(x):
    return x * 2


@app.route("/")
def index():
    return render_template_string("2 times 2 is {{ 2 | double }}")

If you run this app (flask run --port 8008 --debug) and then open it in your browser (http://localhost:8008) you'll get an error:

jinja2.exceptions.TemplateAssertionError: No filter named 'double'.

This is confusing, and it took me a while to realise the missing parentheses in app.template_filter were at fault.

Suggested fix

I think it would be helpful if the decorator either:

  • Supported being called without parentheses, or
  • Printed an explicit warning if called this way, e.g. Did you use 'template_filter' as a decorator without parentheses? You need to call it with 'template_filter()'

This is caught by type checkers, but not everybody type checks their Python and the error message is less obvious:

Argument 1 to "template_filter" of "App" has incompatible type "Callable[[Any], Any]"; expected "str | None"

I've had a look at the relevant code, and I'd be happy to provide a patch if you think this is a useful change.

Environment

  • Python version: Python 3.11.11
  • Flask version: Flask 3.1.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions