python - flask blueprint example
Creación de Blueprint de Flask-Admin durante la prueba (3)
Tuve que agregar lo siguiente a mi caso de prueba tearDown. Limpia las vistas que se agregaron a la extensión de administrador en la configuración de prueba
from flask.ext.testing import TestCase
from flask.ext.admin import BaseView
# My application wide instance of the Admin manager
from myapp.extensions import admin
class TestView(BaseView):
...
class MyTestCase(TestCase):
def setUp(self):
admin.add_view(TestView())
def tearDown(self):
admin._views.pop(-1)
admin._menu.pop(-1)
Esto es ciertamente un truco, pero hizo el trabajo mientras tuve este problema.
Estoy teniendo problemas con la creación de planos por Flask-Admin cuando estoy probando mi aplicación.
Esta es mi clase de Vista (usando 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'')
Así es como inicializo las vistas:
# flask-admin
admin.add_view(UserView(User, db.session))
admin.init_app(app)
Sin embargo, cuando trato de ejecutar más de una prueba (la falla siempre ocurre en la segunda prueba y todas las otras pruebas que siguen), siempre recibo el siguiente mensaje de error:
======================================================================
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.
Lo extraño es que esto solo sucede en la segunda prueba y nunca cuando solo ejecuto la aplicación.
Cuando depuré las pruebas, la primera vez hice exactamente lo que esperaba y agregué el blueprint a la aplicación después de la init_app (aplicación). La segunda vez, sin embargo, el proceso se detuvo inmediatamente al alcanzar el paso add_view (que creo que es extraño porque los blueprints se registran en la llamada init_app (app)?)
Me pasó lo mismo al usar Flask-Admin y probar con Pytest. Pude solucionarlo sin crear funciones de extracción para mis pruebas al mover la creación de la instancia de administración a la fábrica de aplicaciones.
Antes de:
# 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
Después:
# __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
Porque pytest ejecuta la fábrica de aplicaciones cada vez que ya no intenta registrar múltiples vistas en una instancia de administración global. Esto no es coherente con el uso habitual de la extensión de Flask, pero funciona y evitará que su fábrica de aplicaciones tropiece con las vistas de Flask-Admin.
En caso de que esto ayude a alguien, otra forma de manejar esto es hacer:
class MyTestCase(TestCase):
def setUp(self):
admin._views = []
de esta manera no tiene que configurar la inicialización de Admin () dentro de la fábrica. Me parece más apropiado.