vdikan
vdikan

Reputation: 75

FlaskClient set cookie from g in after_request fails

Have problem with setting cookie in my flask test client. Using FlaskFoundation boilerplate + Flask-BabelEx, after I add these for language selection (in main.py):

@main.before_request
def detect_user_language():
    language = request.cookies.get('user_lang') or\
        request.accept_languages.best_match(LANG_CHOICES)
    g.language = language


@main.after_request
def set_language_cookie(response):
    response.set_cookie('user_lang', value=g.language)
    return response


@main.route("/lang/<language_code>")
def switch_language(language_code):
    if language_code in LANG_CHOICES:
        g.language = language_code
    return redirect(url_for('main.home'))

previously fine test:

class TestForm:
    def setup(self):
        app = create_app('appname.settings.DevConfig', env='dev')
        self.app = app.test_client()
        db.app = app
        db.create_all()
        admin = User('admin', 'supersafepassword')
        db.session.add(admin)
        db.session.commit()

    def teardown(self):
        db.session.remove()
        db.drop_all()


    def test_user_login(self):
        rv = self.app.post('/login', data=dict(
            username='admin',
            password="supersafepassword"
        ), follow_redirects=True)

        assert rv.status_code == 200
        assert 'Logged in successfully.' in rv.data

fails with TypeError:

self = <tests.test_login.TestForm instance at 0x415f328c>

    def test_user_login(self):
        rv = self.app.post('/login', data=dict(
            username='admin',
            password="supersafepassword"
>       ), follow_redirects=True)

tests/test_login.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
env/local/lib/python2.7/site-packages/werkzeug/test.py:784: in post
    return self.open(*args, **kw)
env/local/lib/python2.7/site-packages/flask/testing.py:108: in open
    follow_redirects=follow_redirects)
env/local/lib/python2.7/site-packages/werkzeug/test.py:742: in open
    response = self.run_wsgi_app(environ, buffered=buffered)
env/local/lib/python2.7/site-packages/werkzeug/test.py:659: in run_wsgi_app
    rv = run_wsgi_app(self.application, environ, buffered=buffered)
env/local/lib/python2.7/site-packages/werkzeug/test.py:867: in run_wsgi_app
    app_iter = app(environ, start_response)
env/local/lib/python2.7/site-packages/flask/app.py:1836: in __call__
    return self.wsgi_app(environ, start_response)
env/local/lib/python2.7/site-packages/flask/app.py:1820: in wsgi_app
    response = self.make_response(self.handle_exception(e))
env/local/lib/python2.7/site-packages/flask/app.py:1403: in handle_exception
    reraise(exc_type, exc_value, tb)
env/local/lib/python2.7/site-packages/flask/app.py:1817: in wsgi_app
    response = self.full_dispatch_request()
env/local/lib/python2.7/site-packages/flask/app.py:1479: in full_dispatch_request
    response = self.process_response(response)
env/local/lib/python2.7/site-packages/flask/app.py:1691: in process_response
    response = handler(response)
appname/controllers/main.py:22: in set_language_cookie
    response.set_cookie('user_lang', value=g.language)
env/local/lib/python2.7/site-packages/werkzeug/wrappers.py:1008: in set_cookie
    self.charset))
env/local/lib/python2.7/site-packages/werkzeug/http.py:933: in dump_cookie
    buf = [key + b'=' + _cookie_quote(value)]
env/local/lib/python2.7/site-packages/werkzeug/_internal.py:223: in _cookie_quote
    for char in iter_bytes(b):
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

x = None

>   iter_bytes = lambda x: iter(x)
E   TypeError: 'NoneType' object is not iterable

as do other tests with requests.

Upvotes: 1

Views: 1162

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121654

The Accept.best_match() method returns None as the default if there are no matches found.

You are not setting a Accept-Language or a Cookie header on your requests, so no match will be found and None is returned for the language.

That in turn sets g.language = None, which you then try to use as the value for the response.set_cookie() call, which fails.

You can specify a default to be used instead if no match is found:

language = (
    request.cookies.get('user_lang') or
    # default language is English
    request.accept_languages.best_match(LANG_CHOICES, default='en'))

Upvotes: 1

Related Questions