Flask-Admin Blueprint creation during Testing
Question: I'm having trouble with the creation of blueprints by Flask-Admin when I'm
testing my app.

This is my View class (using SQLAlchemy)

    
    
    ##
    # All views that only admins are allowed to see should inherit from this class.
    #
    class AuthView(ModelView):
        def is_accessible(self):
            return current_user.is_admin()
    
    class UserView(AuthView):
        column_list = ('name', 'email', 'role_code')
    

This is how I initialize the views:

    
    
    # flask-admin
    admin.add_view(UserView(User, db.session))
    admin.init_app(app)
    

However, when I try to run more then one test (the fault always occurs on the
second test and all the other tests that follow), I always get following error
message:

    
    
    ======================================================================
    ERROR: test_send_email (tests.test_views.TestUser)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/lib/python2.7/site-packages/nose/case.py", line 133, in run
        self.runTest(result)
      File "/lib/python2.7/site-packages/nose/case.py", line 151, in runTest
        test(result)
      File "/lib/python2.7/site-packages/flask_testing.py", line 72, in __call__
        self._pre_setup()
      File "/lib/python2.7/site-packages/flask_testing.py", line 80, in _pre_setup
        self.app = self.create_app()
      File "/tests/test_init.py", line 27, in create_app
        app = create_app(TestConfig)
      File "/fbone/app.py", line 41, in create_app
        configure_extensions(app)
      File "/fbone/app.py", line 98, in configure_extensions
        admin.add_view(UserView(User, db.session))
      File "/lib/python2.7/site-packages/flask_admin/base.py", line 484, in add_view
        self.app.register_blueprint(view.create_blueprint(self))
      File "/lib/python2.7/site-packages/flask/app.py", line 62, in wrapper_func
        return f(self, *args, **kwargs)
      File "/lib/python2.7/site-packages/flask/app.py", line 885, in register_blueprint
        (blueprint, self.blueprints[blueprint.name], blueprint.name)
    AssertionError: A blueprint's name collision occurred between <flask.blueprints.Blueprint object at 0x110576910> and <flask.blueprints.Blueprint object at 0x1103bd3d0>.  Both share the same name "userview".  Blueprints that are created on the fly need unique names.
    

The strange thing is that this only happens on the second test and never when
I just run the app.

When I debugged the tests, the first time it did exactly what I expected and
added the blueprint to the app after the init_app(app). The second time
however the process immediately stopped when reaching the add_view step (which
I think is strange because the blueprints get registered in the init_app(app)
call?)


Answer: The same thing happened to me while using Flask-Admin and testing with pytest.
I was able to fix it without creating teardown functions for my tests by
moving the creation of the admin instance into the app factory.

Before:

    
    
    # extensions.py
    from flask.ext.admin import Admin
    admin = Admin()
    
    # __init__.py
    from .extensions import admin
    
    def create_app():
        app = Flask('flask_app')
    
        admin.add_view(sqla.ModelView(models.User, db.session))
        admin.init_app(app)
    
        return app
    

After:

    
    
    # __init__.py
    from flask.ext.admin import Admin
    
    def create_app():
        app = Flask('flask_app')
    
        admin = Admin()
    
        admin.add_view(sqla.ModelView(models.User, db.session))    
        admin.init_app(app)
    
        return app
    

Because pytest runs the app factory each time it no longer tries to register
multiple views on a global admin instance. This isn't consistent with typical
Flask extension usage, but it works and it'll keep your app factory from
stumbling over Flask-Admin views.

