alisaifee / flask-limiter

Rate Limiting extension for Flask

Home Page:https://flask-limiter.readthedocs.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

"weakly-referenced object no longer exists" when enabled=False in Limiter()

phesSofthouse opened this issue · comments

Expected Behaviour

Should turn off rate limiting (Im using it for disabling rate limiting when running unit tests)

Current Behaviour

Raises an error:

 File "python3.10/site-packages/flask/app.py", line 1823, in full_dispatch_request
    rv = self.dispatch_request()
  File "python3.10/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "python3.10/site-packages/flask_limiter/extension.py", line 1209, in __inner
    self.limiter._auto_check
ReferenceError: weakly-referenced object no longer exists

Steps to Reproduce

Relevant code in my project:

limiter = Limiter(
      get_remote_address,
      strategy="fixed-window-elastic-expiry",
      storage_uri=app.config["LIMITER_STORAGE_URI"],
      enabled=False,
  )
limiter.init_app(app)

forgot_password_view = ForgotPasswordView.as_view("forgotpassword")
forgot_password_view = limiter.limit("1/minute", methods=["POST"])(
    forgot_password_view
)
app.add_url_rule(
    "/forgot-password",
    view_func=forgot_password_view,
    methods=["GET", "POST"],
)

Same thing also happens when using RATELIMIT_ENABLED = False instead of the limiter parameter.

Your Environment

  • Flask-limiter version: flask-limiter[redis]==3.4.0
  • Flask version: flask==2.2.3
  • Operating system: Macos Ventura 13.3.1
  • Python version: 3.10.11

This implies that there is no reference to the limiter left and it was collected by the GC. Is the code snippet you shared done within the scope of a method call where the scope of limiter is the method scope?

The reason there is no problem when enabled=True is that the init_app method adds the limiter to app.extensions here but that code path is never hit when enabled=False.

Im running the application factory pattern in flask, so the limiter is in the create_app() function.

So to prevent the GC from picking up the limiter, this does the trick.
app.limiter = limiter

(I realise this is only a short term solution until I refactor the structure of my project.)

Thanks for the help and amazing work with the library!

@phesSofthouse I'd recommend doing something along the lines of the guide here.

Basically create a global limiter=Limiter(....) somewhere and then in the create_app do the init_app.