Skip to content

Commit 3883ee7

Browse files
Atte Lautanalalautat
authored andcommitted
Use flask.g as context
This is according to a recommendation on extension development in Flask documentation. This also fixes an issue where force_locale context leaks between two threads which are running in app context rather than request context. `current_app` is a proxy to the application object, while `flask.g` lives only for the duration of the context, either app context or request context. `types.SimpleNamespace` is used with the extension name as a prefix to avoid collisions.
1 parent a49f6b1 commit 3883ee7

File tree

2 files changed

+35
-6
lines changed

2 files changed

+35
-6
lines changed

flask_babel/__init__.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
"""
1010
from __future__ import absolute_import
1111
import os
12+
from types import SimpleNamespace
1213

1314
from datetime import datetime
1415
from contextlib import contextmanager
15-
from flask import current_app, request
16-
from flask.ctx import has_request_context
16+
from flask import current_app, g
1717
from flask.helpers import locked_cached_property
1818
from babel import dates, numbers, support, Locale
1919
from pytz import timezone, UTC
@@ -661,11 +661,13 @@ def lazy_pgettext(self, context, string, **variables):
661661

662662

663663
def _get_current_context():
664-
if has_request_context():
665-
return request
664+
if not g:
665+
return None
666+
667+
if not hasattr(g, "_flask_babel"):
668+
g._flask_babel = SimpleNamespace()
666669

667-
if current_app:
668-
return current_app
670+
return g._flask_babel
669671

670672

671673
def get_domain():

tests/test_force_locale.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,33 @@ def first_request():
4747
thread.join()
4848

4949

50+
def test_force_locale_with_threading_and_app_context():
51+
app = flask.Flask(__name__)
52+
b = babel.Babel(app)
53+
54+
@b.localeselector
55+
def select_locale():
56+
return 'de_DE'
57+
58+
semaphore = Semaphore(value=0)
59+
60+
def first_app_context():
61+
with app.app_context():
62+
with babel.force_locale('en_US'):
63+
assert str(babel.get_locale()) == 'en_US'
64+
semaphore.acquire()
65+
66+
thread = Thread(target=first_app_context)
67+
thread.start()
68+
69+
try:
70+
with app.app_context():
71+
assert str(babel.get_locale()) == 'de_DE'
72+
finally:
73+
semaphore.release()
74+
thread.join()
75+
76+
5077
def test_refresh_during_force_locale():
5178
app = flask.Flask(__name__)
5279
b = babel.Babel(app)

0 commit comments

Comments
 (0)