release version 3.1.2 (#5800)

This commit is contained in:
David Lord 2025-08-19 14:03:43 -07:00 committed by Christian Clauss
commit 6719ac2afe
46 changed files with 1188 additions and 1161 deletions

View file

@ -5,7 +5,7 @@ import pytest
from _pytest import monkeypatch
from flask import Flask
from flask.globals import request_ctx
from flask.globals import app_ctx as _app_ctx
@pytest.fixture(scope="session", autouse=True)
@ -83,16 +83,17 @@ def test_apps(monkeypatch):
@pytest.fixture(autouse=True)
def leak_detector():
"""Fails if any app contexts are still pushed when a test ends. Pops all
contexts so subsequent tests are not affected.
"""
yield
# make sure we're not leaking a request context since we are
# testing flask internally in debug mode in a few cases
leaks = []
while request_ctx:
leaks.append(request_ctx._get_current_object())
request_ctx.pop()
assert leaks == []
while _app_ctx:
leaks.append(_app_ctx._get_current_object())
_app_ctx.pop()
assert not leaks
@pytest.fixture

View file

@ -2,7 +2,6 @@ import pytest
import flask
from flask.globals import app_ctx
from flask.globals import request_ctx
def test_basic_url_generation(app):
@ -107,7 +106,8 @@ def test_app_tearing_down_with_handled_exception_by_app_handler(app, client):
with app.app_context():
client.get("/")
assert cleanup_stuff == [None]
# teardown request context, and with block context
assert cleanup_stuff == [None, None]
def test_app_tearing_down_with_unhandled_exception(app, client):
@ -126,9 +126,11 @@ def test_app_tearing_down_with_unhandled_exception(app, client):
with app.app_context():
client.get("/")
assert len(cleanup_stuff) == 1
assert len(cleanup_stuff) == 2
assert isinstance(cleanup_stuff[0], ValueError)
assert str(cleanup_stuff[0]) == "dummy"
# exception propagated, seen by request context and with block context
assert cleanup_stuff[0] is cleanup_stuff[1]
def test_app_ctx_globals_methods(app, app_ctx):
@ -178,8 +180,7 @@ def test_context_refcounts(app, client):
@app.route("/")
def index():
with app_ctx:
with request_ctx:
pass
pass
assert flask.request.environ["werkzeug.request"] is not None
return ""

View file

@ -366,11 +366,35 @@ def test_template_filter(app):
def my_reverse(s):
return s[::-1]
@bp.app_template_filter
def my_reverse_2(s):
return s[::-1]
@bp.app_template_filter("my_reverse_custom_name_3")
def my_reverse_3(s):
return s[::-1]
@bp.app_template_filter(name="my_reverse_custom_name_4")
def my_reverse_4(s):
return s[::-1]
app.register_blueprint(bp, url_prefix="/py")
assert "my_reverse" in app.jinja_env.filters.keys()
assert app.jinja_env.filters["my_reverse"] == my_reverse
assert app.jinja_env.filters["my_reverse"]("abcd") == "dcba"
assert "my_reverse_2" in app.jinja_env.filters.keys()
assert app.jinja_env.filters["my_reverse_2"] == my_reverse_2
assert app.jinja_env.filters["my_reverse_2"]("abcd") == "dcba"
assert "my_reverse_custom_name_3" in app.jinja_env.filters.keys()
assert app.jinja_env.filters["my_reverse_custom_name_3"] == my_reverse_3
assert app.jinja_env.filters["my_reverse_custom_name_3"]("abcd") == "dcba"
assert "my_reverse_custom_name_4" in app.jinja_env.filters.keys()
assert app.jinja_env.filters["my_reverse_custom_name_4"] == my_reverse_4
assert app.jinja_env.filters["my_reverse_custom_name_4"]("abcd") == "dcba"
def test_add_template_filter(app):
bp = flask.Blueprint("bp", __name__)
@ -502,11 +526,35 @@ def test_template_test(app):
def is_boolean(value):
return isinstance(value, bool)
@bp.app_template_test
def boolean_2(value):
return isinstance(value, bool)
@bp.app_template_test("my_boolean_custom_name")
def boolean_3(value):
return isinstance(value, bool)
@bp.app_template_test(name="my_boolean_custom_name_2")
def boolean_4(value):
return isinstance(value, bool)
app.register_blueprint(bp, url_prefix="/py")
assert "is_boolean" in app.jinja_env.tests.keys()
assert app.jinja_env.tests["is_boolean"] == is_boolean
assert app.jinja_env.tests["is_boolean"](False)
assert "boolean_2" in app.jinja_env.tests.keys()
assert app.jinja_env.tests["boolean_2"] == boolean_2
assert app.jinja_env.tests["boolean_2"](False)
assert "my_boolean_custom_name" in app.jinja_env.tests.keys()
assert app.jinja_env.tests["my_boolean_custom_name"] == boolean_3
assert app.jinja_env.tests["my_boolean_custom_name"](False)
assert "my_boolean_custom_name_2" in app.jinja_env.tests.keys()
assert app.jinja_env.tests["my_boolean_custom_name_2"] == boolean_4
assert app.jinja_env.tests["my_boolean_custom_name_2"](False)
def test_add_template_test(app):
bp = flask.Blueprint("bp", __name__)
@ -679,6 +727,18 @@ def test_template_global(app):
def get_answer():
return 42
@bp.app_template_global
def get_stuff_1():
return "get_stuff_1"
@bp.app_template_global("my_get_stuff_custom_name_2")
def get_stuff_2():
return "get_stuff_2"
@bp.app_template_global(name="my_get_stuff_custom_name_3")
def get_stuff_3():
return "get_stuff_3"
# Make sure the function is not in the jinja_env already
assert "get_answer" not in app.jinja_env.globals.keys()
app.register_blueprint(bp)
@ -688,10 +748,31 @@ def test_template_global(app):
assert app.jinja_env.globals["get_answer"] is get_answer
assert app.jinja_env.globals["get_answer"]() == 42
assert "get_stuff_1" in app.jinja_env.globals.keys()
assert app.jinja_env.globals["get_stuff_1"] == get_stuff_1
assert app.jinja_env.globals["get_stuff_1"](), "get_stuff_1"
assert "my_get_stuff_custom_name_2" in app.jinja_env.globals.keys()
assert app.jinja_env.globals["my_get_stuff_custom_name_2"] == get_stuff_2
assert app.jinja_env.globals["my_get_stuff_custom_name_2"](), "get_stuff_2"
assert "my_get_stuff_custom_name_3" in app.jinja_env.globals.keys()
assert app.jinja_env.globals["my_get_stuff_custom_name_3"] == get_stuff_3
assert app.jinja_env.globals["my_get_stuff_custom_name_3"](), "get_stuff_3"
with app.app_context():
rv = flask.render_template_string("{{ get_answer() }}")
assert rv == "42"
rv = flask.render_template_string("{{ get_stuff_1() }}")
assert rv == "get_stuff_1"
rv = flask.render_template_string("{{ my_get_stuff_custom_name_2() }}")
assert rv == "get_stuff_2"
rv = flask.render_template_string("{{ my_get_stuff_custom_name_3() }}")
assert rv == "get_stuff_3"
def test_request_processing(app, client):
bp = flask.Blueprint("bp", __name__)

View file

@ -462,7 +462,7 @@ class TestRoutes:
def expect_order(self, order, output):
# skip the header and match the start of each row
for expect, line in zip(order, output.splitlines()[2:]):
for expect, line in zip(order, output.splitlines()[2:], strict=False):
# do this instead of startswith for nicer pytest output
assert line[: len(expect)] == expect

View file

@ -3,7 +3,7 @@ import warnings
import pytest
import flask
from flask.globals import request_ctx
from flask.globals import app_ctx
from flask.sessions import SecureCookieSessionInterface
from flask.sessions import SessionInterface
@ -153,12 +153,12 @@ class TestGreenletContextCopying:
@app.route("/")
def index():
flask.session["fizz"] = "buzz"
reqctx = request_ctx.copy()
ctx = app_ctx.copy()
def g():
assert not flask.request
assert not flask.current_app
with reqctx:
with ctx:
assert flask.request
assert flask.current_app == app
assert flask.request.path == "/"

View file

@ -1,5 +1,5 @@
import flask
from flask.globals import request_ctx
from flask.globals import app_ctx
from flask.sessions import SessionInterface
@ -14,7 +14,7 @@ def test_open_session_with_endpoint():
pass
def open_session(self, app, request):
request_ctx.match_request()
app_ctx.match_request()
assert request.endpoint is not None
app = flask.Flask(__name__)

View file

@ -129,6 +129,30 @@ def test_template_filter(app):
assert app.jinja_env.filters["my_reverse"] == my_reverse
assert app.jinja_env.filters["my_reverse"]("abcd") == "dcba"
@app.template_filter
def my_reverse_2(s):
return s[::-1]
assert "my_reverse_2" in app.jinja_env.filters.keys()
assert app.jinja_env.filters["my_reverse_2"] == my_reverse_2
assert app.jinja_env.filters["my_reverse_2"]("abcd") == "dcba"
@app.template_filter("my_reverse_custom_name_3")
def my_reverse_3(s):
return s[::-1]
assert "my_reverse_custom_name_3" in app.jinja_env.filters.keys()
assert app.jinja_env.filters["my_reverse_custom_name_3"] == my_reverse_3
assert app.jinja_env.filters["my_reverse_custom_name_3"]("abcd") == "dcba"
@app.template_filter(name="my_reverse_custom_name_4")
def my_reverse_4(s):
return s[::-1]
assert "my_reverse_custom_name_4" in app.jinja_env.filters.keys()
assert app.jinja_env.filters["my_reverse_custom_name_4"] == my_reverse_4
assert app.jinja_env.filters["my_reverse_custom_name_4"]("abcd") == "dcba"
def test_add_template_filter(app):
def my_reverse(s):
@ -223,6 +247,30 @@ def test_template_test(app):
assert app.jinja_env.tests["boolean"] == boolean
assert app.jinja_env.tests["boolean"](False)
@app.template_test
def boolean_2(value):
return isinstance(value, bool)
assert "boolean_2" in app.jinja_env.tests.keys()
assert app.jinja_env.tests["boolean_2"] == boolean_2
assert app.jinja_env.tests["boolean_2"](False)
@app.template_test("my_boolean_custom_name")
def boolean_3(value):
return isinstance(value, bool)
assert "my_boolean_custom_name" in app.jinja_env.tests.keys()
assert app.jinja_env.tests["my_boolean_custom_name"] == boolean_3
assert app.jinja_env.tests["my_boolean_custom_name"](False)
@app.template_test(name="my_boolean_custom_name_2")
def boolean_4(value):
return isinstance(value, bool)
assert "my_boolean_custom_name_2" in app.jinja_env.tests.keys()
assert app.jinja_env.tests["my_boolean_custom_name_2"] == boolean_4
assert app.jinja_env.tests["my_boolean_custom_name_2"](False)
def test_add_template_test(app):
def boolean(value):
@ -320,6 +368,39 @@ def test_add_template_global(app, app_ctx):
rv = flask.render_template_string("{{ get_stuff() }}")
assert rv == "42"
@app.template_global
def get_stuff_1():
return "get_stuff_1"
assert "get_stuff_1" in app.jinja_env.globals.keys()
assert app.jinja_env.globals["get_stuff_1"] == get_stuff_1
assert app.jinja_env.globals["get_stuff_1"](), "get_stuff_1"
rv = flask.render_template_string("{{ get_stuff_1() }}")
assert rv == "get_stuff_1"
@app.template_global("my_get_stuff_custom_name_2")
def get_stuff_2():
return "get_stuff_2"
assert "my_get_stuff_custom_name_2" in app.jinja_env.globals.keys()
assert app.jinja_env.globals["my_get_stuff_custom_name_2"] == get_stuff_2
assert app.jinja_env.globals["my_get_stuff_custom_name_2"](), "get_stuff_2"
rv = flask.render_template_string("{{ my_get_stuff_custom_name_2() }}")
assert rv == "get_stuff_2"
@app.template_global(name="my_get_stuff_custom_name_3")
def get_stuff_3():
return "get_stuff_3"
assert "my_get_stuff_custom_name_3" in app.jinja_env.globals.keys()
assert app.jinja_env.globals["my_get_stuff_custom_name_3"] == get_stuff_3
assert app.jinja_env.globals["my_get_stuff_custom_name_3"](), "get_stuff_3"
rv = flask.render_template_string("{{ my_get_stuff_custom_name_3() }}")
assert rv == "get_stuff_3"
def test_custom_template_loader(client):
class MyFlask(flask.Flask):

View file

@ -6,7 +6,7 @@ import pytest
import flask
from flask import appcontext_popped
from flask.cli import ScriptInfo
from flask.globals import _cv_request
from flask.globals import _cv_app
from flask.json import jsonify
from flask.testing import EnvironBuilder
from flask.testing import FlaskCliRunner
@ -382,4 +382,4 @@ def test_client_pop_all_preserved(app, req_ctx, client):
# close the response, releasing the context held by stream_with_context
rv.close()
# only req_ctx fixture should still be pushed
assert _cv_request.get(None) is req_ctx
assert _cv_app.get(None) is req_ctx