flask-security icon indicating copy to clipboard operation
flask-security copied to clipboard

security.context_processor raises RecursionError

Open lnlrbr opened this issue 6 years ago • 5 comments

I try to use flask_security with flask_admin, but at start up there's a problem with the context_processor:

File "/home/lionel/dev/knmx/knmx/launcher.py", line 6, in <module>
    from knmx.app import create_app
  File "/home/lionel/dev/knmx/knmx/app.py", line 92, in <module>
    @webui_security.context_processor
  File "/home/lionel/dev/knmx/venv/lib/python3.5/site-packages/flask_security/core.py", line 531, in __getattr__
    return getattr(self._state, name, None)
  File "/home/lionel/dev/knmx/venv/lib/python3.5/site-packages/flask_security/core.py", line 531, in __getattr__
    return getattr(self._state, name, None)
...
RecursionError: maximum recursion depth exceeded

My setup:

  • app.py
from flask import Flask

from knmx import config
from knmx import security
from knmx.db import models
from knmx.views import api, admin, webui, schemas
def create_app(extra_config=None):
    app = Flask(__name__.split('.')[0])
    app.config.from_object(config.DefaultConfig)
    register_extensions(app=app)

def register_extensions(app):
    models.db.init_app(app=app)
    security.webui_security.init_app(app=app, datastore=security.user_datastore)
    security.jwt.init_app(app=app)
    admin.admin.init_app(app=app)
  • security.py
from flask_security import Security, SQLAlchemyUserDatastore
from flask_jwt_extended import JWTManager
from knmx.db import models

webui_security = Security()
jwt = JWTManager()
user_datastore = SQLAlchemyUserDatastore(models.db, models.User, models.Role)
  • admin.py
from flask import redirect, url_for, request, abort
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from flask_admin import helpers as admin_helpers
from flask_security import current_user
from knmx.db import models
from knmx.security import webui_security

admin = Admin()

@webui_security.context_processor
def security_context_processor():
    return dict(
        admin_base_template=admin.base_template,
        admin_view=admin.index_view,
        h=admin_helpers,
        get_url=url_for
    )

lnlrbr avatar Jun 29 '18 10:06 lnlrbr

Hi, @LionelR I also face the issue just like you.

I find out that in version 3.0.0's flask_security.Security init_app function is a little bit different from __init__. It won't assign self._state when using init_app way, but it'll return state object for you. So, I guess, that's why the getattr would never find context_processor attribute in self._state. 😢

For now, I found there are two ways to fix this issue,

  • Using init_app return value
secur = security.webui_security.init_app(app=app, datastore=security.user_datastore)
@secur.context_processor
def security_context_processor():
...
  • Get state object from app.extension after you init_app
security = app.extension['security']
@security.context_processor
def security_context_processor():
...

Or you can just use the develop branch code. I saw someone add self._state = state = _get_state(app, datastore, **kwargs) to fix this problem. (CODE LINK)

Hope it will help you.

BbsonLin avatar Nov 26 '18 15:11 BbsonLin

Any update on this? I still have the same issue (following @LionelR's approach) ...

smn-snkl avatar Jan 15 '19 16:01 smn-snkl

  • I found this as a fix
security_state = security.init_app(app,user_datastore)
security._state = security_state

gharidev avatar May 18 '20 14:05 gharidev

Please consider moving to: https://github.com/Flask-Middleware/flask-security

which is my updated and maintained fork. The fix mentioned above is there.

jwag956 avatar May 18 '20 14:05 jwag956

i am use template: {% set admin_base_template = security.admin_base_template %} {% set admin_view = security.admin_view %} {% set get_url = security.get_url %} {% set h = security.h %} {% extends 'admin/master.html' %}

use in: security.init_app(app, user_datastore, admin_base_template=admin.base_template, admin_view=admin.index_view, h=admin_helpers, get_url=url_for)

Work! Not use @...context_processor

big-vl avatar Oct 26 '20 15:10 big-vl