question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

_on_identity_loaded breaks when multiple test clients are created using with clause and flask==2.2.x

See original GitHub issue

I think changes in flask==2.2.0 breaks flask-security-too when FlaskTestClient objects are used in a with context.

All examples below use:

Flask-Login==0.6.2
Flask-Principal==0.4.0
Flask-Security-Too==5.0.1
SQLAlchemy==1.4.41

and flask version changes from 2.1.3 to 2.2.2 as described in details below.

I have a piece of test code that uses two flask test clients simultaneously in a with statement, along the lines of:

    with application.test_client() as first_client, application.test_client() as second_client:

        post_new_user(
            client=first_client,
            data={
                "email": "first_user@gmail.com",
                "password": "testtest"
            })

        post_new_user(
            client=second_client,
            data={
                "email": "second_user@gmail.com",
                "password": "testtest"
            })

post_new_user registers user via flask-security-too with mysql datastore behind it.

In flask==2.1.3 this works correctly. In flask==2.2.2 this code breaks on call to GET /register inside post_new_user(client=second_client, ...) with message

{'request': {'body': {'form': {}}, 'method': 'GET', 'path': '/register', 'query_parameters': [], 'user': 'first_user@gmail.com', 'user_agent': 'werkzeug/2.2.2'}, 'exception': {'type': "<class 'sqlalchemy.orm.exc.DetachedInstanceError'>", 'string': "Parent instance <User at 0x7f393fe98730> is not bound to a Session; lazy load operation of attribute 'roles' cannot proceed (Background on this error at: https://sqlalche.me/e/14/bhk3)", 'traceback': ['  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1756, in full_dispatch_request\n    rv = self.preprocess_request()\n', '  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 2247, in preprocess_request\n    rv = self.ensure_sync(before_func)()\n', '  File "/usr/local/lib/python3.8/site-packages/flask_principal.py", line 479, in _on_before_request\n    self.set_identity(identity)\n', '  File "/usr/local/lib/python3.8/site-packages/flask_principal.py", line 418, in set_identity\n    self._set_thread_identity(identity)\n', '  File "/usr/local/lib/python3.8/site-packages/flask_principal.py", line 462, in _set_thread_identity\n    identity_loaded.send(current_app._get_current_object(),\n', '  File "/usr/local/lib/python3.8/site-packages/blinker/base.py", line 266, in send\n    return [(receiver, receiver(sender, **kwargs))\n', '  File "/usr/local/lib/python3.8/site-packages/blinker/base.py", line 266, in <listcomp>\n    return [(receiver, receiver(sender, **kwargs))\n', '  File "/usr/local/lib/python3.8/site-packages/flask_security/core.py", line 655, in _on_identity_loaded\n    for role in getattr(current_user, "roles", []):\n', '  File "/usr/local/lib/python3.8/site-packages/sqlalchemy/orm/attributes.py", line 482, in __get__\n    return self.impl.get(state, dict_)\n', '  File "/usr/local/lib/python3.8/site-packages/sqlalchemy/orm/attributes.py", line 942, in get\n    value = self._fire_loader_callables(state, key, passive)\n', '  File "/usr/local/lib/python3.8/site-packages/sqlalchemy/orm/attributes.py", line 978, in _fire_loader_callables\n    return self.callable_(state, passive)\n', '  File "/usr/local/lib/python3.8/site-packages/sqlalchemy/orm/strategies.py", line 863, in _load_for_state\n    raise orm_exc.DetachedInstanceError(\n']}}

One might be tempted to say that this is an error with sqlalchemy, because the last exception is DetachedInstanceError, but I don’t think so - call to GET /register performed by second_client shouldn’t have a User instance associated with it (flask_login.current_user instance should be AnonymousUser), so no sql lookup should be triggered.

Please notice log says 'user': 'first_user@gmail.com' even though endpoint was called by second_client who at that point hasn’t even registered a user instance yet.

My guess is the problem lies with flask_principal doing some caching or context retrieval wrong, and ending up with first_client data when second_client data should be used. flask-principal hasn’t been updated since 2013, and flask==2.2.0 made some changes to app context handling that most likely affect flask_principal's logic.

If I don’t define flask test clients using with clause, and instead just use plain

first_client = application.test_client()
second_client = application.test_client()

in the same context as rest of code, everything works with flask==2.2.2

Above is just the simplest case I was able to reproduce to illustrate that something in flask==2.2.0 breaks flask-security related code. I have errors showing up in cases when multiple test clients are used even without with context, they were just harder to extract to a simple case I can share.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
sr-verdecommented, Sep 13, 2022

On a side note - it seems that most packages in ./requirements folder don’t specify a version?

Since this is a library, it should be compatible with the latest versions of the dependencies. You can specify the versions in your testing requirements (in this project folder you will only find requirements for Testing, Docs and Dev), but that would have no advantage except that you will not see problems with newer versions of your dependencies. The requirements for production use can be found in setup.py. You will find some broad version restrictions there. But all in all: if you want to test your application with different dependency versions, you will do that with tox, which is a great tool for that. And Flask-Security-Too does that to detect problems with deps very early, but of course you can’t test a lib with every single package version.

1reaction
andyDoucettecommented, Nov 22, 2022

@kuba-lilz Thank you very much. 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

What Is the WITH Clause in SQL? - LearnSQL.com
Put simply, the key advantage of the WITH clause is that it helps organize and simplify long and complex hierarchical queries by breaking...
Read more >
SQL WITH: Organize Complex Queries
The WITH clause adds named subqueries to SQL queries. ... Once created, a view has a name in the database schema so that...
Read more >
WITH clause - Amazon Redshift - AWS Documentation
Defines one or more subqueries. A WITH clause is an optional clause that precedes the SELECT list in a query.
Read more >
How the WITH Clause Can Simplify Your SQL Queries
This is a quick post to highlight how you can simplify your SQL using the WITH clause. I've used this technique a lot...
Read more >
SQL | WITH clause - GeeksforGeeks
In this query, WITH clause is used to define a temporary relation temporaryTable that has only 1 attribute averageValue. averageValue holds the ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found