Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detached instance errors - Instance is not bound to a session #27

Open
JehoG opened this issue Feb 14, 2020 · 2 comments
Open

Detached instance errors - Instance is not bound to a session #27

JehoG opened this issue Feb 14, 2020 · 2 comments

Comments

@JehoG
Copy link

JehoG commented Feb 14, 2020

In a test suite that has nearly 2000 test, sometimes there are some tests failing because we get an DetachedInstance exception withing the test (after a call to a endpoint we want to test):

sqlalchemy.orm.exc.DetachedInstanceError: Instance <Object at 0xxxxxxxxxxxx> is not bound to a Session; attribute refresh operation cannot proceed (Background on this error at: http://sqlalche.me/e/bhk3)

+.venv/lib/python3.6/site-packages/sqlalchemy/orm/loading.py:915: DetachedInstanceError

This bug is unpredictible, doesn't happen when executing one test alone and when using IPDB before the call to the endpoint it wouldn't happen.
After investigation, we realized that in some rare case, the db_session is closed by flask, so I guess that sometime this package fails to block a db_session closing.

Locally we got able to avoid it by removing the sqlalchemy shutdown_session function (which is set by flask-sqlalchemy) from app.teardown_appcontext_funcs and running it at the end of each test.

It's hard to reproduce, but here are some hints that I got able to spot:
It happens only in a test when we fetch an object, make the call to the endpoint and then try to access the attribute of the object.
Needs to be multiple test running, running only one doesn't cause any problem.
Most of the case, the test before validate that an exception has been raised and handled within the tested endpoint.
It happens more in a test that follows a test which is parametrized, by example:
@pytest.mark.parametrize('expected_status', [429, 503, 504])

@jshridha
Copy link

jshridha commented Apr 22, 2020

@JehoG I'm running into the same issue with just 74 tests. Can you post an example of your workaround? I think it'll be helpful for others (and myself).

I added the following to my conftest.py and it seems to have fixed the issue:

@pytest.fixture(scope="function")
def db_session(db_session):
    with mock.patch.object(db_session, "remove", lambda: None):
        yield db_session

@JehoG
Copy link
Author

JehoG commented Apr 22, 2020

@jshridha Sure, here's the fixtures we use to avoid this problem:

@pytest.fixture(scope='session')
def app():
    app = initialize_app(config_name='tests')

    # Here we backup the teardown function set by flask-sqlalchemy (it's closing the session)
    app.teardown_bkp = app.teardown_appcontext_funcs
    app.teardown_appcontext_funcs = []
    return app

To be sure that the session is closed at the end of each test:

def close_sessions(app, request):
    # At the end of each test we close the db_session
    @request.addfinalizer
    def teardown():
        flask_sa_shutdown_session_func = app.teardown_bkp[0]

It doesn't solves the problem since this package should be handling it, but we are able to avoid it this way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants