RecursionError:Flask Pytest中超出最大递归深度

问题描述:

我正在使用Pytest来测试Flask + SQLAlchemy应用程序。这是tests/contftest.pyRecursionError:Flask Pytest中超出最大递归深度

import pytest 
from sqlalchemy import create_engine 
from sqlalchemy.orm import scoped_session, sessionmaker 
from flask import _app_ctx_stack 
from flask.ext.sqlalchemy import SQLAlchemy, BaseQuery 
from package.myapp import create_app 
from package.config import DefaultConfig 

DbSession = scoped_session(
     sessionmaker(), 
     scopefunc=_app_ctx_stack.__ident_func__ 
    ) 
@pytest.fixture(scope='session') 
def app(request): 
    _app = create_app() 
    _app.debug = False 

    _app.engine = create_engine(_app.config['SQLALCHEMY_DATABASE_URI'], connect_args={"options": "-c timezone=utc"}) 
    global DbSession 
    DbSession.configure(bind=_app.engine, query_cls=BaseQuery) 

    # Establish an application context before running the tests. 
    ctx = _app.app_context() 
    ctx.push() 

    @_app.teardown_appcontext 
    def teardown(exception=None): 
     ctx.pop() 
     global DbSession 
     if DbSession: 
      DbSession.remove() 


    request.addfinalizer(teardown) 
    return _app 

当我运行pytest,我得到这个错误信息

___________________ ERROR at teardown of test_create_project ___________________ 

exception = None 

    @_app.teardown_appcontext 
    def teardown(exception=None): 
>  ctx.pop() 

tests/conftest.py:31: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../.virtualenvs/quest-backend/lib/python3.6/site-packages/flask/ctx.py:189: in pop 
    self.app.do_teardown_appcontext(exc) 
../../.virtualenvs/quest-backend/lib/python3.6/site-packages/flask/app.py:1892: in do_teardown_appcontext 
    func(exc) 
tests/conftest.py:31: in teardown 
    ctx.pop() 
E RecursionError: maximum recursion depth exceeded 
!!! Recursion detected (same locals & position) 

扩大罗马Kutlak的答案,这里是我怎么会重写你app夹具:

@pytest.fixture(scope='session') 
def app(): 
    _app = create_app() 
    _app.debug = False 

    _app.engine = create_engine(_app.config['SQLALCHEMY_DATABASE_URI'], connect_args={"options": "-c timezone=utc"}) 
    # session should probably not be global?.. 
    DbSession = scoped_session(
     sessionmaker(), 
     scopefunc=_app_ctx_stack.__ident_func__ 
    ) 
    DbSession.configure(bind=_app.engine, query_cls=BaseQuery) 

    # Establish an application context before running the tests. 
    ctx = _app.app_context() 
    ctx.push() 

    # this function is specifically for app's teardown, don't call it again for fixture teardown 
    @_app.teardown_appcontext 
    def teardown(exception=None): 
     if DbSession: 
      DbSession.remove() 

    # here is where tests will be executed 
    yield _app 

    # now tear-down our fixture (as apposed to flask app's teardown) 
    ctx.pop() 

,除非你想从内部范围内的值分配给全局变量来使用global关键字这是没有必要的。

我不认为你应该叫ctx.pop()在拆卸功能调用pop()内容调用已注册的拆解回调(因此无限重复AppContext调用Flask.do_teardown_appcontext()其中包含以下内容:

for func in reversed(self.teardown_appcontext_funcs): 
    func(exc) 

当您销毁夹具时,应该致电ctx.pop()