Python RecursionError:测试中超过了最大递归深度

Python RecursionError:测试中超过了最大递归深度,python,flask,sqlalchemy,flask-sqlalchemy,pytest,Python,Flask,Sqlalchemy,Flask Sqlalchemy,Pytest,我正在使用Pytest测试一个Flask+SQLAlchemy应用程序。这是tests/contftest.py 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, BaseQuer

我正在使用Pytest测试一个Flask+SQLAlchemy应用程序。这是
tests/contftest.py

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)

我认为您不应该在teardown函数中调用
ctx.pop()
,因为调用
pop()
调用已注册的teardown回调(因此无限重复调用
Flask.do_teardown\u appcontext()
,其中包含以下内容:

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

销毁设备时,应该调用
ctx.pop()

我不认为应该在teardown函数中调用
ctx.pop()
,因为调用
pop()
调用已注册的teardown回调(因此无限重复调用
Flask.do\teardown\appcontext()
其中包含以下内容:

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

销毁设备时,应调用
ctx.pop()

扩展Roman Kutlak的答案,下面是我将如何重写您的
应用程序
设备:

@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
关键字,除非您希望从内部范围内为全局变量赋值。

扩展Roman Kutlak的答案,下面是我将如何重写您的
应用程序
夹具:

@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
关键字,除非您希望从内部范围内为全局变量赋值