This rule enforces that the @receiver decorator in Django and the @route decorator in Flask are placed on top of all other decorators.

Why is this an issue?

The order in which decorators are applied can have a significant impact on their behavior. When decorators are applied in Python, they are processed from bottom to top. The outermost decorator (the one written first) is applied last and receives the result of all inner decorators.

In Django, the @receiver decorator is used to register signal handlers. It must be the outermost decorator (written at the top) so that all other decorators are applied to the function before it gets registered as a signal handler. If @receiver is not outermost, it registers the original function, and the decorators written above it will not affect the signal handler, resulting in unexpected behavior or errors.

In Flask, the @app.route() or @blueprint.route() decorator must be the outermost decorator for view functions. If other decorators are placed outside the route decorator, the route may not be registered correctly, leading to 404 errors or routes that don’t respond to requests as expected.

How to fix it in Django

Move the @receiver decorator to the top of the list of decorators used to decorate the function.

Code examples

Noncompliant code example

from django.dispatch import receiver
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
@receiver(some_signal)  # Noncompliant: @receiver should be the outermost decorator
def my_handler(sender, **kwargs):
    ...

Compliant solution

from django.dispatch import receiver
from django.views.decorators.csrf import csrf_exempt

@receiver(some_signal)
@csrf_exempt
def my_handler(sender, **kwargs):
    ...

How to fix it in Flask

Move the @app.route() or @blueprint.route() decorator to be the outermost (first) decorator.

Code examples

Noncompliant code example

@login_required
@app.route('/secret_page')  # Noncompliant: @route should be the outermost decorator
def secret_page():
    return "Secret content"

Compliant solution

@app.route('/secret_page')
@login_required
def secret_page():
    return "Secret content"

Resources

Documentation