Flask-Login package is broken by importing Google App Engine's testbed

Go To StackoverFlow.com

1

When using Google App Engine 1.6.4 testbed with Flask 0.8, and in particular the Flask-Login 0.1 package (source), I encounter a strange problem with command-line unit testing.

Below is an example that demonstrates the problem. Note the commented line (from google.appengine.ext import testbed). When this line is commented, the tests work as expected.

When this line is uncommented, the @login_required decorator for Flask-Login stops recognizing the logged-in user i.e. current_user.is_authenticated() returns False. It would seem the culprit is importing testbed.

#!/usr/bin/env python2.7
import unittest
import sys
from flask import Flask, current_app, url_for
from flaskext import login

sys.path.append('/usr/local/google_appengine')

# Go ahead and uncomment this:
# from google.appengine.ext import testbed

app = Flask('test')
app.secret_key = 'abc'

login_manager = login.LoginManager()
login_manager.setup_app(app)
login_manager.login_view = 'index'

class User(login.UserMixin):
    def get_id(self):
        return "1"

@login_manager.user_loader
def load_user(user_id):
    return User()

@app.route('/')
@login.login_required
def index():
    pass

@login_manager.unauthorized_handler
def unauthorized():
    raise Exception("Unauthorized.")

class MyTest(unittest.TestCase):
    def setUp(self):
        self.app = app
        self.client = app.test_client()

    def test_user(self):
        with self.app.test_request_context():
            logged_in = login.login_user(User())
            r = self.client.get('/')

if __name__ == '__main__':
    unittest.main()

The specific exception is:

ERROR:test:Exception on / [GET]
Traceback (most recent call last):
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask-0.8-py2.7.egg/flask/app.py", line 1504, in wsgi_app
    response = self.full_dispatch_request()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask-0.8-py2.7.egg/flask/app.py", line 1264, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask-0.8-py2.7.egg/flask/app.py", line 1262, in full_dispatch_request
    rv = self.dispatch_request()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask-0.8-py2.7.egg/flask/app.py", line 1248, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask_Login-0.1-py2.7.egg/flaskext/login.py", line 479, in decorated_view
    return current_app.login_manager.unauthorized()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Flask_Login-0.1-py2.7.egg/flaskext/login.py", line 250, in unauthorized
    return self.unauthorized_callback()
  File "./test.py", line 34, in unauthorized
    raise Exception("Unauthorized.")
Exception: Unauthorized.

The behaviour I would expect is that importing (and using) testbed would have no effect on the Flask context stack and, by extension, Flask-Login would continue to work in the unit testing environment even though testbed has been imported.

I have stared at this for a bit, to no avail, and would be grateful for any insight and suggestions for potential solutions to this problem.

Thank you for reading.

2012-04-03 19:59
by Brian M. Hunt
For what it's worth, in attempting to find a workaround I noticed that flask.g and other associated variables seem to also be unavailable - Brian M. Hunt 2012-04-03 21:59


4

The testbed uses separate stubs for many of the GAE services, including the datastore and user service.

I'm not familiar with flask, but if the login requires a user to exist in the database, it'll fail since the testbed uses a separate database. You'll have to load user data into the testbed database first.

Also if you include the testbed, there's some initialization calls you have to make to set up the stubs before you can use it. https://developers.google.com/appengine/docs/python/tools/localunittesting

2012-04-03 20:13
by dragonx
Thanks. I am unsure why you mention testbed stubs - what bearing might this have? The login does not require database access; it is defined as class User in the degenerate example above. As mentioned, the problem is not using testbed, but that merely importing it breaks Flask-Login - Brian M. Hunt 2012-04-03 20:32
The testbed stubs replace default API behavior. If you're certain flask doesn't use the datastore to store anything (like session ids), you'd want to check which of the other API stubs might have affecting something. Possibly memcache (I don't know if flask uses memcache to store sessions), or quite possibly urlfetch. You'd really have to debug a bit to see which one is responsible - dragonx 2012-04-03 22:14
Agree, there has to be something in testbed that is called. The questions is what. I've debugged from top to bottom in pdb a few times but didn't hit it - the problem seems buried somewhere in Werkzeug. I have used evil monkey patches in the interim. : - Brian M. Hunt 2012-04-04 00:26