【问题标题】:RecursionError: maximum recursion depth exceeded in Flask PytestRecursionError:Flask Pytest 中超出了最大递归深度
【发布时间】:2018-03-31 12:07:56
【问题描述】:

我正在使用 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)

【问题讨论】:

    标签: python flask sqlalchemy flask-sqlalchemy pytest


    【解决方案1】:

    扩展 Roman 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关键字,除非你想在内部范围内为全局变量赋值。

    【讨论】:

      【解决方案2】:

      我认为您不应该在您的拆卸函数中调用ctx.pop(),因为对pop() 的调用会调用已注册的拆卸回调(因此无限recurAppContext 调用Flask.do_teardown_appcontext(),其中包含以下内容:

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

      您在销毁您的灯具时应该致电ctx.pop()

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-01
        • 1970-01-01
        • 2017-03-24
        • 2011-12-31
        • 2017-08-09
        相关资源
        最近更新 更多