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

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions