From 554fad132ee385a45f7f89873e8f4cf69031ccf7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 08:24:13 +0000 Subject: [PATCH] [pre-commit.ci lite] apply automatic fixes --- tests/test_basic.py | 89 ++++++++++++++++++++++++++++++++++++++++++++ tests/test_cli.py | 32 ++++++++++++++++ tests/test_config.py | 18 +++++++++ 3 files changed, 139 insertions(+) diff --git a/tests/test_basic.py b/tests/test_basic.py index 2ef92497..f8a11529 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -26,6 +26,7 @@ require_cpython_gc = pytest.mark.skipif( reason="Requires CPython GC behavior", ) + def test_options_work(app, client): @app.route("/", methods=["GET", "POST"]) def index(): @@ -35,6 +36,7 @@ def test_options_work(app, client): assert sorted(rv.allow) == ["GET", "HEAD", "OPTIONS", "POST"] assert rv.data == b"" + def test_options_on_multiple_rules(app, client): @app.route("/", methods=["GET", "POST"]) def index(): @@ -47,6 +49,7 @@ def test_options_on_multiple_rules(app, client): rv = client.open("/", method="OPTIONS") assert sorted(rv.allow) == ["GET", "HEAD", "OPTIONS", "POST", "PUT"] + @pytest.mark.parametrize("method", ["get", "post", "put", "delete", "patch"]) def test_method_route(app, client, method): method_route = getattr(app, method) @@ -58,10 +61,12 @@ def test_method_route(app, client, method): assert client_method("/").data == b"Hello" + def test_method_route_no_methods(app): with pytest.raises(TypeError): app.get("/", methods=["GET", "POST"]) + def test_provide_automatic_options_attr(): app = flask.Flask(__name__) @@ -83,6 +88,7 @@ def test_provide_automatic_options_attr(): rv = app.test_client().open("/", method="OPTIONS") assert sorted(rv.allow) == ["OPTIONS"] + def test_provide_automatic_options_kwarg(app, client): def index(): return flask.request.method @@ -119,6 +125,7 @@ def test_provide_automatic_options_kwarg(app, client): rv = client.open("/more", method="OPTIONS") assert rv.status_code == 405 + def test_request_dispatching(app, client): @app.route("/") def index(): @@ -141,10 +148,12 @@ def test_request_dispatching(app, client): assert rv.status_code == 405 assert sorted(rv.allow) == ["GET", "HEAD", "OPTIONS", "POST"] + def test_disallow_string_for_allowed_methods(app): with pytest.raises(TypeError): app.add_url_rule("/", methods="GET POST", endpoint="test") + def test_url_mapping(app, client): random_uuid4 = "7eb41166-9ebf-4d26-b771-ea3f54f8b383" @@ -180,6 +189,7 @@ def test_url_mapping(app, client): assert rv.status_code == 200 assert random_uuid4 in rv.data.decode("utf-8") + def test_werkzeug_routing(app, client): from werkzeug.routing import Rule from werkzeug.routing import Submount @@ -200,6 +210,7 @@ def test_werkzeug_routing(app, client): assert client.get("/foo/").data == b"index" assert client.get("/foo/bar").data == b"bar" + def test_endpoint_decorator(app, client): from werkzeug.routing import Rule from werkzeug.routing import Submount @@ -219,6 +230,7 @@ def test_endpoint_decorator(app, client): assert client.get("/foo/").data == b"index" assert client.get("/foo/bar").data == b"bar" + def test_session(app, client): @app.route("/set", methods=["POST"]) def set(): @@ -241,6 +253,7 @@ def test_session(app, client): assert client.post("/set", data={"value": "42"}).data == b"value set" assert client.get("/get").data == b"42" + def test_session_path(app, client): app.config.update(APPLICATION_ROOT="/foo") @@ -252,6 +265,7 @@ def test_session_path(app, client): rv = client.get("/", "http://example.com:8080/foo") assert "path=/foo" in rv.headers["set-cookie"].lower() + def test_session_using_application_root(app, client): class PrefixPathMiddleware: def __init__(self, app, prefix): @@ -273,6 +287,7 @@ def test_session_using_application_root(app, client): rv = client.get("/", "http://example.com:8080/") assert "path=/bar" in rv.headers["set-cookie"].lower() + def test_session_using_session_settings(app, client): app.config.update( SERVER_NAME="www.example.com:8080", @@ -315,6 +330,7 @@ def test_session_using_session_settings(app, client): assert "samesite" in cookie assert "partitioned" in cookie + def test_session_using_samesite_attribute(app, client): @app.route("/") def index(): @@ -341,6 +357,7 @@ def test_session_using_samesite_attribute(app, client): cookie = rv.headers["set-cookie"].lower() assert "samesite=lax" in cookie + def test_missing_session(app): app.secret_key = None @@ -353,6 +370,7 @@ def test_missing_session(app): expect_exception(flask.session.__setitem__, "foo", 42) expect_exception(flask.session.pop, "foo") + def test_session_secret_key_fallbacks(app, client) -> None: @app.post("/") def set_session() -> str: @@ -380,6 +398,7 @@ def test_session_secret_key_fallbacks(app, client) -> None: ) assert client.get().json == {"a": 1} + def test_session_expiration(app, client): permanent = True @@ -411,6 +430,7 @@ def test_session_expiration(app, client): match = re.search(r"\bexpires=([^;]+)", rv.headers["set-cookie"]) assert match is None + def test_session_stored_last(app, client): @app.after_request def modify_session(response): @@ -424,6 +444,7 @@ def test_session_stored_last(app, client): assert client.get("/").data == b"None" assert client.get("/").data == b"42" + def test_session_special_types(app, client): now = datetime.now(timezone.utc).replace(microsecond=0) the_uuid = uuid.uuid4() @@ -454,6 +475,7 @@ def test_session_special_types(app, client): assert s["di_t_tag"] == {" t__": "not-a-tuple"} assert s["di_tag"] == {" di": "not-a-dict"} + def test_session_cookie_setting(app): is_permanent = True @@ -494,6 +516,7 @@ def test_session_cookie_setting(app): app.config["SESSION_REFRESH_EACH_REQUEST"] = False run_test(expect_header=False) + def test_session_vary_cookie(app, client): @app.route("/set") def set_session(): @@ -554,6 +577,7 @@ def test_session_vary_cookie(app, client): expect("/vary-header-set", "Accept-Encoding, Accept-Language, Cookie") expect("/no-vary-header", None) + def test_session_refresh_vary(app, client): @app.get("/login") def login(): @@ -570,6 +594,7 @@ def test_session_refresh_vary(app, client): rv = client.get("/ignored") assert rv.headers["Vary"] == "Cookie" + def test_flashes(app, req_ctx): assert not flask.session.modified flask.flash("Zap") @@ -578,6 +603,7 @@ def test_flashes(app, req_ctx): assert flask.session.modified assert list(flask.get_flashed_messages()) == ["Zap", "Zip"] + def test_extended_flashing(app): # Be sure app.testing=True below, else tests can fail silently. # @@ -658,6 +684,7 @@ def test_extended_flashing(app): client.get("/") client.get("/test_filters_without_returning_categories/") + def test_request_processing(app, client): evts = [] @@ -682,6 +709,7 @@ def test_request_processing(app, client): assert "after" in evts assert rv == b"request|after" + def test_request_preprocessing_early_return(app, client): evts = [] @@ -708,6 +736,7 @@ def test_request_preprocessing_early_return(app, client): assert rv == b"hello" assert evts == [1, 2] + def test_after_request_processing(app, client): @app.route("/") def index(): @@ -722,6 +751,7 @@ def test_after_request_processing(app, client): assert resp.status_code == 200 assert resp.headers["X-Foo"] == "a header" + def test_teardown_request_handler(app, client): called = [] @@ -739,6 +769,7 @@ def test_teardown_request_handler(app, client): assert b"Response" in rv.data assert len(called) == 1 + def test_teardown_request_handler_debug_mode(app, client): called = [] @@ -756,6 +787,7 @@ def test_teardown_request_handler_debug_mode(app, client): assert b"Response" in rv.data assert len(called) == 1 + def test_teardown_request_handler_error(app, client): called = [] app.testing = False @@ -793,6 +825,7 @@ def test_teardown_request_handler_error(app, client): assert b"Internal Server Error" in rv.data assert len(called) == 2 + def test_before_after_request_order(app, client): called = [] @@ -830,6 +863,7 @@ def test_before_after_request_order(app, client): assert rv.data == b"42" assert called == [1, 2, 3, 4, 5, 6] + def test_error_handling(app, client): app.testing = False @@ -867,6 +901,7 @@ def test_error_handling(app, client): assert rv.status_code == 403 assert b"forbidden" == rv.data + def test_error_handling_processing(app, client): app.testing = False @@ -887,6 +922,7 @@ def test_error_handling_processing(app, client): assert resp.mimetype == "text/x-special" assert resp.data == b"internal server error" + def test_baseexception_error_handling(app, client): app.testing = False @@ -897,6 +933,7 @@ def test_baseexception_error_handling(app, client): with pytest.raises(KeyboardInterrupt): client.get("/") + def test_before_request_and_routing_errors(app, client): @app.before_request def attach_something(): @@ -910,6 +947,7 @@ def test_before_request_and_routing_errors(app, client): assert rv.status_code == 404 assert rv.data == b"value" + def test_user_error_handling(app, client): class MyException(Exception): pass @@ -925,6 +963,7 @@ def test_user_error_handling(app, client): assert client.get("/").data == b"42" + def test_http_error_subclass_handling(app, client): class ForbiddenSubclass(Forbidden): pass @@ -956,6 +995,7 @@ def test_http_error_subclass_handling(app, client): assert client.get("/2").data == b"apple" assert client.get("/3").data == b"apple" + def test_errorhandler_precedence(app, client): class E1(Exception): pass @@ -988,6 +1028,7 @@ def test_errorhandler_precedence(app, client): rv = client.get("/E3") assert rv.data == b"E2" + @pytest.mark.parametrize( ("debug", "trap", "expect_key", "expect_abort"), [(False, None, True, True), (True, None, False, True), (False, True, False, False)], @@ -1022,6 +1063,7 @@ def test_trap_bad_request_key_error(app, client, debug, trap, expect_key, expect with pytest.raises(BadRequest): client.get("/abort") + def test_trapping_of_all_http_exceptions(app, client): app.config["TRAP_HTTP_EXCEPTIONS"] = True @@ -1032,6 +1074,7 @@ def test_trapping_of_all_http_exceptions(app, client): with pytest.raises(NotFound): client.get("/fail") + def test_error_handler_after_processor_error(app, client): app.testing = False @@ -1060,6 +1103,7 @@ def test_error_handler_after_processor_error(app, client): assert rv.status_code == 500 assert rv.data == b"Hello Server Error" + def test_enctype_debug_helper(app, client): from flask.debughelpers import DebugFilesKeyError @@ -1074,6 +1118,7 @@ def test_enctype_debug_helper(app, client): assert "no file contents were transmitted" in str(e.value) assert "This was submitted: 'index.txt'" in str(e.value) + def test_response_types(app, client): @app.route("/text") def from_text(): @@ -1167,6 +1212,7 @@ def test_response_types(app, client): assert rv.json == ["foo", "bar"] assert rv.status_code == 201 + def test_response_type_errors(): app = flask.Flask(__name__) app.testing = True @@ -1215,6 +1261,7 @@ def test_response_type_errors(): with pytest.raises(TypeError): c.get("/bad_wsgi") + def test_make_response(app, req_ctx): rv = flask.make_response() assert rv.status_code == 200 @@ -1236,6 +1283,7 @@ def test_make_response(app, req_ctx): assert rv.data == b"Hello" assert rv.mimetype == "text/html" + def test_make_response_with_response_instance(app, req_ctx): rv = flask.make_response(flask.jsonify({"msg": "W00t"}), 400) assert rv.status_code == 400 @@ -1256,6 +1304,7 @@ def test_make_response_with_response_instance(app, req_ctx): assert rv.headers["Content-Type"] == "text/html" assert rv.headers["X-Foo"] == "bar" + @pytest.mark.parametrize("compact", [True, False]) def test_jsonify_no_prettyprint(app, compact): app.json.compact = compact @@ -1264,12 +1313,14 @@ def test_jsonify_no_prettyprint(app, compact): assert (b" " not in data) is compact assert (b"\n" not in data) is compact + def test_jsonify_mimetype(app, req_ctx): app.json.mimetype = "application/vnd.api+json" msg = {"msg": {"submsg": "W00t"}} rv = flask.make_response(flask.jsonify(msg), 200) assert rv.mimetype == "application/vnd.api+json" + def test_json_dump_dataclass(app, req_ctx): from dataclasses import make_dataclass @@ -1278,11 +1329,13 @@ def test_json_dump_dataclass(app, req_ctx): value = app.json.loads(value) assert value == {"name": "Flask"} + def test_jsonify_args_and_kwargs_check(app, req_ctx): with pytest.raises(TypeError) as e: flask.jsonify("fake args", kwargs="fake") assert "args or kwargs" in str(e.value) + def test_url_generation(app, req_ctx): @app.route("/hello/", methods=["POST"]) def hello(): @@ -1294,6 +1347,7 @@ def test_url_generation(app, req_ctx): == "http://localhost/hello/test%20x" ) + def test_build_error_handler(app): # Test base case, a URL which results in a BuildError. with app.test_request_context(): @@ -1319,6 +1373,7 @@ def test_build_error_handler(app): with app.test_request_context(): assert flask.url_for("spam") == "/test_handler/" + def test_build_error_handler_reraise(app): # Test a custom handler which reraises the BuildError def handler_raises_build_error(error, endpoint, values): @@ -1329,6 +1384,7 @@ def test_build_error_handler_reraise(app): with app.test_request_context(): pytest.raises(BuildError, flask.url_for, "not.existing") + def test_url_for_passes_special_values_to_build_error_handler(app): @app.url_build_error_handlers.append def handler(error, endpoint, values): @@ -1343,6 +1399,7 @@ def test_url_for_passes_special_values_to_build_error_handler(app): with app.test_request_context(): flask.url_for("/") + def test_static_files(app, client): rv = client.get("/static/index.html") assert rv.status_code == 200 @@ -1351,6 +1408,7 @@ def test_static_files(app, client): assert flask.url_for("static", filename="index.html") == "/static/index.html" rv.close() + def test_static_url_path(): app = flask.Flask(__name__, static_url_path="/foo") app.testing = True @@ -1361,6 +1419,7 @@ def test_static_url_path(): with app.test_request_context(): assert flask.url_for("static", filename="index.html") == "/foo/index.html" + def test_static_url_path_with_ending_slash(): app = flask.Flask(__name__, static_url_path="/foo/") app.testing = True @@ -1371,18 +1430,21 @@ def test_static_url_path_with_ending_slash(): with app.test_request_context(): assert flask.url_for("static", filename="index.html") == "/foo/index.html" + def test_static_url_empty_path(app): app = flask.Flask(__name__, static_folder="", static_url_path="") rv = app.test_client().open("/static/index.html", method="GET") assert rv.status_code == 200 rv.close() + def test_static_url_empty_path_default(app): app = flask.Flask(__name__, static_folder="") rv = app.test_client().open("/static/index.html", method="GET") assert rv.status_code == 200 rv.close() + def test_static_folder_with_pathlib_path(app): from pathlib import Path @@ -1391,6 +1453,7 @@ def test_static_folder_with_pathlib_path(app): assert rv.status_code == 200 rv.close() + def test_static_folder_with_ending_slash(): app = flask.Flask(__name__, static_folder="static/") @@ -1401,6 +1464,7 @@ def test_static_folder_with_ending_slash(): rv = app.test_client().get("/catch/all") assert rv.data == b"catch/all" + def test_static_route_with_host_matching(): app = flask.Flask(__name__, host_matching=True, static_host="example.com") c = app.test_client() @@ -1421,12 +1485,15 @@ def test_static_route_with_host_matching(): # but with static_folder=None should not error. flask.Flask(__name__, host_matching=True, static_folder=None) + def test_request_locals(): assert repr(flask.g) == "" assert not flask.g + werkzeug_3_2 = importlib.metadata.version("werkzeug") >= "3.2." + @pytest.mark.parametrize( ("subdomain_matching", "host_matching", "expect_subdomain", "expect_host"), [ @@ -1470,6 +1537,7 @@ def test_server_name_matching( else: assert r.text == expect_host + def test_server_name_subdomain(): app = flask.Flask(__name__, subdomain_matching=True) client = app.test_client() @@ -1514,6 +1582,7 @@ def test_server_name_subdomain(): rv = client.get("/", "http://foo.dev.local") assert rv.data == b"subdomain" + @pytest.mark.parametrize("key", ["TESTING", "PROPAGATE_EXCEPTIONS", "DEBUG", None]) def test_exception_propagation(app, client, key): app.testing = False @@ -1530,6 +1599,7 @@ def test_exception_propagation(app, client, key): else: assert client.get("/").status_code == 500 + @pytest.mark.parametrize("debug", [True, False]) @pytest.mark.parametrize("use_debugger", [True, False]) @pytest.mark.parametrize("use_reloader", [True, False]) @@ -1547,6 +1617,7 @@ def test_werkzeug_passthrough_errors( app.config["PROPAGATE_EXCEPTIONS"] = propagate_exceptions app.run(debug=debug, use_debugger=use_debugger, use_reloader=use_reloader) + def test_url_processors(app, client): @app.url_defaults def add_language_code(endpoint, values): @@ -1575,6 +1646,7 @@ def test_url_processors(app, client): assert client.get("/de/about").data == b"/foo" assert client.get("/foo").data == b"/en/about" + def test_inject_blueprint_url_defaults(app): bp = flask.Blueprint("foo", __name__, template_folder="template") @@ -1598,6 +1670,7 @@ def test_inject_blueprint_url_defaults(app): expected = "/login" assert url == expected + def test_nonascii_pathinfo(app, client): @app.route("/киртест") def index(): @@ -1606,6 +1679,7 @@ def test_nonascii_pathinfo(app, client): rv = client.get("/киртест") assert rv.data == b"Hello World!" + def test_no_setup_after_first_request(app, client): app.debug = True @@ -1620,6 +1694,7 @@ def test_no_setup_after_first_request(app, client): assert "setup method 'add_url_rule'" in str(exc_info.value) + def test_routing_redirect_debugging(monkeypatch, app, client): app.config["DEBUG"] = True @@ -1639,6 +1714,7 @@ def test_routing_redirect_debugging(monkeypatch, app, client): assert "canonical URL 'http://localhost/user/'" in str(exc_info.value) + def test_route_decorator_custom_endpoint(app, client): app.debug = True @@ -1663,6 +1739,7 @@ def test_route_decorator_custom_endpoint(app, client): assert client.get("/bar/").data == b"bar" assert client.get("/bar/123").data == b"123" + def test_get_method_on_g(app_ctx): assert flask.g.get("x") is None assert flask.g.get("x", 11) == 11 @@ -1670,6 +1747,7 @@ def test_get_method_on_g(app_ctx): assert flask.g.get("x") == 42 assert flask.g.x == 42 + def test_g_iteration_protocol(app_ctx): flask.g.foo = 23 flask.g.bar = 42 @@ -1677,6 +1755,7 @@ def test_g_iteration_protocol(app_ctx): assert "foos" not in flask.g assert sorted(flask.g) == ["bar", "foo"] + def test_subdomain_basic_support(): app = flask.Flask(__name__, subdomain_matching=True) app.config["SERVER_NAME"] = "localhost.localdomain" @@ -1696,6 +1775,7 @@ def test_subdomain_basic_support(): rv = client.get("/", "http://test.localhost.localdomain/") assert rv.data == b"test index" + def test_subdomain_matching(): app = flask.Flask(__name__, subdomain_matching=True) client = app.test_client() @@ -1708,6 +1788,7 @@ def test_subdomain_matching(): rv = client.get("/", "http://mitsuhiko.localhost.localdomain/") assert rv.data == b"index for mitsuhiko" + def test_subdomain_matching_with_ports(): app = flask.Flask(__name__, subdomain_matching=True) app.config["SERVER_NAME"] = "localhost.localdomain:3000" @@ -1720,6 +1801,7 @@ def test_subdomain_matching_with_ports(): rv = client.get("/", "http://mitsuhiko.localhost.localdomain:3000/") assert rv.data == b"index for mitsuhiko" + @pytest.mark.parametrize("matching", (False, True)) def test_subdomain_matching_other_name(matching): app = flask.Flask(__name__, subdomain_matching=matching) @@ -1743,6 +1825,7 @@ def test_subdomain_matching_other_name(matching): rv = client.get("/", "http://www.localhost.localdomain:3000/") assert rv.status_code == 404 if matching else 204 + def test_multi_route_rules(app, client): @app.route("/") @app.route("//") @@ -1754,6 +1837,7 @@ def test_multi_route_rules(app, client): rv = client.open("/b/") assert rv.data == b"b" + def test_multi_route_class_views(app, client): class View: def __init__(self, app): @@ -1769,6 +1853,7 @@ def test_multi_route_class_views(app, client): rv = client.open("/b/") assert rv.data == b"b" + def test_run_defaults(monkeypatch, app): rv = {} @@ -1780,6 +1865,7 @@ def test_run_defaults(monkeypatch, app): app.run() assert rv["result"] == "running..." + def test_run_server_port(monkeypatch, app): rv = {} @@ -1792,6 +1878,7 @@ def test_run_server_port(monkeypatch, app): app.run(hostname, port, debug=True) assert rv["result"] == f"running on {hostname}:{port} ..." + @pytest.mark.parametrize( "host,port,server_name,expect_host,expect_port", ( @@ -1815,6 +1902,7 @@ def test_run_from_config( app.config["SERVER_NAME"] = server_name app.run(host, port) + def test_max_cookie_size(app, client, recwarn): app.config["MAX_COOKIE_SIZE"] = 100 @@ -1844,6 +1932,7 @@ def test_max_cookie_size(app, client, recwarn): client.get("/") assert len(recwarn) == 0 + @require_cpython_gc def test_app_freed_on_zero_refcount(): # A Flask instance should not create a reference cycle that prevents CPython diff --git a/tests/test_cli.py b/tests/test_cli.py index d6f7d90b..a5aab501 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -32,16 +32,19 @@ from flask.cli import with_appcontext cwd = Path.cwd() test_path = (Path(__file__) / ".." / "test_apps").resolve() + @pytest.fixture def runner(): return CliRunner() + def test_cli_name(test_apps): """Make sure the CLI object's name is the app's name and not the app itself""" from cliapp.app import testapp assert testapp.cli.name == testapp.name + def test_find_best_app(test_apps): class Module: app = Flask("appname") @@ -128,6 +131,7 @@ def test_find_best_app(test_apps): pytest.raises(TypeError, find_best_app, Module) + @pytest.mark.parametrize( "value,path,result", ( @@ -172,6 +176,7 @@ def test_prepare_import(request, value, path, result): assert prepare_import(value) == result assert sys.path[0] == str(path) + @pytest.mark.parametrize( "iname,aname,result", ( @@ -190,6 +195,7 @@ def test_prepare_import(request, value, path, result): def test_locate_app(test_apps, iname, aname, result): assert locate_app(iname, aname).name == result + @pytest.mark.parametrize( "iname,aname", ( @@ -212,6 +218,7 @@ def test_locate_app_raises(test_apps, iname, aname): with pytest.raises(NoAppException): locate_app(iname, aname) + def test_locate_app_suppress_raise(test_apps): app = locate_app("notanapp.py", None, raise_if_not_found=False) assert app is None @@ -220,6 +227,7 @@ def test_locate_app_suppress_raise(test_apps): with pytest.raises(NoAppException): locate_app("cliapp.importerrorapp", None, raise_if_not_found=False) + def test_get_version(test_apps, capsys): class MockCtx: resilient_parsing = False @@ -235,6 +243,7 @@ def test_get_version(test_apps, capsys): assert f"Flask {importlib.metadata.version('flask')}" in out assert f"Werkzeug {importlib.metadata.version('werkzeug')}" in out + def test_scriptinfo(test_apps, monkeypatch): obj = ScriptInfo(app_import_path="cliapp.app:testapp") app = obj.load_app() @@ -276,6 +285,7 @@ def test_scriptinfo(test_apps, monkeypatch): app = obj.load_app() assert app.name == "testapp" + def test_app_cli_has_app_context(app, runner): def _param_cb(ctx, param, value): # current_app should be available in parameter callbacks @@ -293,6 +303,7 @@ def test_app_cli_has_app_context(app, runner): result = runner.invoke(cli, ["check", "x"], standalone_mode=False) assert result.return_value == (True, True) + def test_with_appcontext(runner): @click.command() @with_appcontext @@ -305,6 +316,7 @@ def test_with_appcontext(runner): assert result.exit_code == 0 assert result.output == "testapp\n" + def test_appgroup_app_context(runner): @click.group(cls=AppGroup) def cli(): @@ -332,6 +344,7 @@ def test_appgroup_app_context(runner): assert result.exit_code == 0 assert result.output == "testappgroup\n" + def test_flaskgroup_app_context(runner): def create_app(): return Flask("flaskgroup") @@ -348,6 +361,7 @@ def test_flaskgroup_app_context(runner): assert result.exit_code == 0 assert result.output == "flaskgroup\n" + @pytest.mark.parametrize("set_debug_flag", (True, False)) def test_flaskgroup_debug(runner, set_debug_flag): def create_app(): @@ -367,6 +381,7 @@ def test_flaskgroup_debug(runner, set_debug_flag): assert result.exit_code == 0 assert result.output == f"{not set_debug_flag}\n" + def test_flaskgroup_nested(app, runner): cli = click.Group("cli") flask_group = FlaskGroup(name="flask", create_app=lambda: app) @@ -379,6 +394,7 @@ def test_flaskgroup_nested(app, runner): result = runner.invoke(cli, ["flask", "show"]) assert result.output == "flask_test\n" + def test_no_command_echo_loading_error(): from flask.cli import cli @@ -393,6 +409,7 @@ def test_no_command_echo_loading_error(): assert "FLASK_APP" in result.stderr assert "Usage:" in result.stderr + def test_help_echo_loading_error(): from flask.cli import cli @@ -407,6 +424,7 @@ def test_help_echo_loading_error(): assert "FLASK_APP" in result.stderr assert "Usage:" in result.stdout + def test_help_echo_exception(): def create_app(): raise Exception("oh no") @@ -424,6 +442,7 @@ def test_help_echo_exception(): assert "Exception: oh no" in result.stderr assert "Usage:" in result.stdout + class TestRoutes: @pytest.fixture def app(self): @@ -498,6 +517,7 @@ class TestRoutes: assert result.exit_code == 0 assert "Host" in result.output + def dotenv_not_available(): try: import dotenv # noqa: F401 @@ -506,10 +526,12 @@ def dotenv_not_available(): return False + need_dotenv = pytest.mark.skipif( dotenv_not_available(), reason="dotenv is not installed" ) + @need_dotenv def test_load_dotenv(monkeypatch): # can't use monkeypatch.delitem since the keys don't exist yet @@ -533,6 +555,7 @@ def test_load_dotenv(monkeypatch): # Non existent file should not load assert not load_dotenv("non-existent-file", load_defaults=False) + @need_dotenv def test_dotenv_path(monkeypatch): for item in ("FOO", "BAR", "EGGS"): @@ -542,12 +565,14 @@ def test_dotenv_path(monkeypatch): assert Path.cwd() == cwd assert "FOO" in os.environ + def test_dotenv_optional(monkeypatch): monkeypatch.setitem(sys.modules, "dotenv", None) monkeypatch.chdir(test_path) load_dotenv() assert "FOO" not in os.environ + @need_dotenv def test_disable_dotenv_from_env(monkeypatch, runner): monkeypatch.chdir(test_path) @@ -555,6 +580,7 @@ def test_disable_dotenv_from_env(monkeypatch, runner): runner.invoke(FlaskGroup()) assert "FOO" not in os.environ + def test_run_cert_path(): # no key with pytest.raises(click.BadParameter): @@ -572,6 +598,7 @@ def test_run_cert_path(): ctx = run_command.make_context("run", ["--key", __file__, "--cert", __file__]) assert ctx.params["cert"] == (__file__, __file__) + def test_run_cert_adhoc(monkeypatch): monkeypatch.setitem(sys.modules, "cryptography", None) @@ -588,6 +615,7 @@ def test_run_cert_adhoc(monkeypatch): with pytest.raises(click.BadParameter): run_command.make_context("run", ["--cert", "adhoc", "--key", __file__]) + def test_run_cert_import(monkeypatch): monkeypatch.setitem(sys.modules, "not_here", None) @@ -609,12 +637,14 @@ def test_run_cert_import(monkeypatch): with pytest.raises(click.BadParameter): run_command.make_context("run", ["--cert", "ssl_context", "--key", __file__]) + def test_run_cert_no_ssl(monkeypatch): monkeypatch.setitem(sys.modules, "ssl", None) with pytest.raises(click.BadParameter): run_command.make_context("run", ["--cert", "not_here"]) + def test_cli_blueprints(app): """Test blueprint commands register correctly to the application""" custom = Blueprint("custom", __name__, cli_group="customized") @@ -657,6 +687,7 @@ def test_cli_blueprints(app): result = app_runner.invoke(args=["late_registration", "late"]) assert "late_result" in result.output + def test_cli_empty(app): """If a Blueprint's CLI group is empty, do not register it.""" bp = Blueprint("blue", __name__, cli_group="blue") @@ -665,6 +696,7 @@ def test_cli_empty(app): result = app.test_cli_runner().invoke(args=["blue", "--help"]) assert result.exit_code == 2, f"Unexpected success:\n\n{result.output}" + def test_run_exclude_patterns(): ctx = run_command.make_context("run", ["--exclude-patterns", __file__]) assert ctx.params["exclude_patterns"] == [__file__] diff --git a/tests/test_config.py b/tests/test_config.py index 0f997b75..e5b1906e 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -9,27 +9,32 @@ import flask TEST_KEY = "foo" SECRET_KEY = "config" + def common_object_test(app): assert app.secret_key == "config" assert app.config["TEST_KEY"] == "foo" assert "TestConfig" not in app.config + def test_config_from_pyfile(): app = flask.Flask(__name__) app.config.from_pyfile(f"{__file__.rsplit('.', 1)[0]}.py") common_object_test(app) + def test_config_from_object(): app = flask.Flask(__name__) app.config.from_object(__name__) common_object_test(app) + def test_config_from_file_json(): app = flask.Flask(__name__) current_dir = os.path.dirname(os.path.abspath(__file__)) app.config.from_file(os.path.join(current_dir, "static", "config.json"), json.load) common_object_test(app) + def test_config_from_file_toml(): tomllib = pytest.importorskip("tomllib", reason="tomllib added in 3.11") app = flask.Flask(__name__) @@ -39,6 +44,7 @@ def test_config_from_file_toml(): ) common_object_test(app) + def test_from_prefixed_env(monkeypatch): monkeypatch.setenv("FLASK_STRING", "value") monkeypatch.setenv("FLASK_BOOL", "true") @@ -59,6 +65,7 @@ def test_from_prefixed_env(monkeypatch): assert app.config["DICT"] == {"k": "v"} assert "OTHER" not in app.config + def test_from_prefixed_env_custom_prefix(monkeypatch): monkeypatch.setenv("FLASK_A", "a") monkeypatch.setenv("NOT_FLASK_A", "b") @@ -68,6 +75,7 @@ def test_from_prefixed_env_custom_prefix(monkeypatch): assert app.config["A"] == "b" + def test_from_prefixed_env_nested(monkeypatch): monkeypatch.setenv("FLASK_EXIST__ok", "other") monkeypatch.setenv("FLASK_EXIST__inner__ik", "2") @@ -98,6 +106,7 @@ def test_from_prefixed_env_nested(monkeypatch): assert app.config["NEW"] == {"K": "v"} + def test_config_from_mapping(): app = flask.Flask(__name__) app.config.from_mapping({"SECRET_KEY": "config", "TEST_KEY": "foo"}) @@ -119,6 +128,7 @@ def test_config_from_mapping(): with pytest.raises(TypeError): app.config.from_mapping({}, {}) + def test_config_from_class(): class Base: TEST_KEY = "foo" @@ -130,6 +140,7 @@ def test_config_from_class(): app.config.from_object(Test) common_object_test(app) + def test_config_from_envvar(monkeypatch): monkeypatch.setattr("os.environ", {}) app = flask.Flask(__name__) @@ -146,6 +157,7 @@ def test_config_from_envvar(monkeypatch): assert app.config.from_envvar("FOO_SETTINGS") common_object_test(app) + def test_config_from_envvar_missing(monkeypatch): monkeypatch.setattr("os.environ", {"FOO_SETTINGS": "missing.cfg"}) app = flask.Flask(__name__) @@ -158,6 +170,7 @@ def test_config_from_envvar_missing(monkeypatch): assert msg.endswith("missing.cfg'") assert not app.config.from_envvar("FOO_SETTINGS", silent=True) + def test_config_missing(): app = flask.Flask(__name__) with pytest.raises(IOError) as e: @@ -169,6 +182,7 @@ def test_config_missing(): assert msg.endswith("missing.cfg'") assert not app.config.from_pyfile("missing.cfg", silent=True) + def test_config_missing_file(): app = flask.Flask(__name__) with pytest.raises(IOError) as e: @@ -180,6 +194,7 @@ def test_config_missing_file(): assert msg.endswith("missing.json'") assert not app.config.from_file("missing.json", load=json.load, silent=True) + def test_custom_config_class(): class Config(flask.Config): pass @@ -192,11 +207,13 @@ def test_custom_config_class(): app.config.from_object(__name__) common_object_test(app) + def test_session_lifetime(): app = flask.Flask(__name__) app.config["PERMANENT_SESSION_LIFETIME"] = 42 assert app.permanent_session_lifetime.seconds == 42 + def test_get_namespace(): app = flask.Flask(__name__) app.config["FOO_OPTION_1"] = "foo option 1" @@ -222,6 +239,7 @@ def test_get_namespace(): assert "bar stuff 1" == bar_options["BAR_STUFF_1"] assert "bar stuff 2" == bar_options["BAR_STUFF_2"] + @pytest.mark.parametrize("encoding", ["utf-8", "iso-8859-15", "latin-1"]) def test_from_pyfile_weird_encoding(tmp_path, encoding): f = tmp_path / "my_config.py"