Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/flask/sansio/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,6 @@ def add_url_rule(
rule_obj = self.url_rule_class(rule, methods=methods, **options)
rule_obj.provide_automatic_options = provide_automatic_options # type: ignore[attr-defined]

self.url_map.add(rule_obj)
if view_func is not None:
old_func = self.view_functions.get(endpoint)
if old_func is not None and old_func != view_func:
Expand All @@ -659,6 +658,7 @@ def add_url_rule(
f" endpoint function: {endpoint}"
)
self.view_functions[endpoint] = view_func
self.url_map.add(rule_obj)

@setupmethod
def template_filter(
Expand Down
18 changes: 12 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
from flask import Flask
from flask.globals import request_ctx

# I kept the fix from pull #6072
try:
_notset = monkeypatch.notset
except AttributeError:
from _pytest.compat import NOTSET as _notset


@pytest.fixture(scope="session", autouse=True)
def _standard_os_environ():
Expand All @@ -16,15 +22,15 @@ def _standard_os_environ():
"""
mp = monkeypatch.MonkeyPatch()
out = (
(os.environ, "FLASK_ENV_FILE", monkeypatch.notset),
(os.environ, "FLASK_APP", monkeypatch.notset),
(os.environ, "FLASK_DEBUG", monkeypatch.notset),
(os.environ, "FLASK_RUN_FROM_CLI", monkeypatch.notset),
(os.environ, "WERKZEUG_RUN_MAIN", monkeypatch.notset),
(os.environ, "FLASK_ENV_FILE", _notset),
(os.environ, "FLASK_APP", _notset),
(os.environ, "FLASK_DEBUG", _notset),
(os.environ, "FLASK_RUN_FROM_CLI", _notset),
(os.environ, "WERKZEUG_RUN_MAIN", _notset),
)

for _, key, value in out:
if value is monkeypatch.notset:
if value is _notset:
mp.delenv(key, False)
else:
mp.setenv(key, value)
Expand Down
20 changes: 16 additions & 4 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import gc
import inspect
import re
import typing as t
import uuid
Expand All @@ -17,6 +18,7 @@
from werkzeug.exceptions import NotFound
from werkzeug.http import parse_date
from werkzeug.routing import BuildError
from werkzeug.routing import Map
from werkzeug.routing import RequestRedirect

import flask
Expand All @@ -28,6 +30,8 @@
reason="Requires CPython GC behavior",
)

_has_new_subdomain_matching = "subdomain_matching" in inspect.signature(Map).parameters


def test_options_work(app, client):
@app.route("/", methods=["GET", "POST"])
Expand Down Expand Up @@ -1551,9 +1555,13 @@ def index(name: str) -> str:
with pytest.warns() if subdomain_matching else nullcontext():
r = client.get(base_url="http://xyz.other.test")

assert r.text == expect_xyz
if expect_xyz == "<invalid>":
assert r.text in {"<invalid>", "default"}
else:
assert r.text == expect_xyz


@pytest.mark.filterwarnings("ignore:Couldn't determine current subdomain:UserWarning")
def test_server_name_subdomain():
app = flask.Flask(__name__, subdomain_matching=True)
client = app.test_client()
Expand Down Expand Up @@ -1593,7 +1601,7 @@ def subdomain():
"ignore", "Current server name", UserWarning, "flask.app"
)
rv = client.get("/", "http://foo.localhost")
assert rv.status_code == 404
assert rv.status_code == (200 if _has_new_subdomain_matching else 404)

rv = client.get("/", "http://foo.dev.local")
assert rv.data == b"subdomain"
Expand Down Expand Up @@ -1818,7 +1826,8 @@ def index(user):
assert rv.data == b"index for mitsuhiko"


@pytest.mark.parametrize("matching", (False, True))
@pytest.mark.filterwarnings("ignore:Couldn't determine current subdomain:UserWarning")
@pytest.mark.parametrize("matching", [False, True])
def test_subdomain_matching_other_name(matching):
app = flask.Flask(__name__, subdomain_matching=matching)
app.config["SERVER_NAME"] = "localhost.localdomain:3000"
Expand All @@ -1835,7 +1844,10 @@ def index():
)
# ip address can't match name
rv = client.get("/", "http://127.0.0.1:3000/")
assert rv.status_code == 404 if matching else 204
if matching and not _has_new_subdomain_matching:
assert rv.status_code == 404
else:
assert rv.status_code == 204

# allow all subdomains if matching is disabled
rv = client.get("/", "http://www.localhost.localdomain:3000/")
Expand Down
26 changes: 22 additions & 4 deletions tests/test_blueprints.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
import pytest
from jinja2 import TemplateNotFound
from werkzeug.http import parse_cache_control_header
from werkzeug.datastructures import ResponseCacheControl

# Fixed Deprecation of parse_cache_control_header
if hasattr(ResponseCacheControl, "from_header"):

def parse_cache_control(value: str) -> ResponseCacheControl:
return ResponseCacheControl.from_header(value)

else:
from werkzeug.http import parse_cache_control_header as _parse_cache_control_header

def parse_cache_control(value: str) -> ResponseCacheControl:
return _parse_cache_control_header(value)


import flask

Expand Down Expand Up @@ -199,7 +212,7 @@ def test_templates_and_static(test_apps):
expected_max_age = 7200
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = expected_max_age
rv = client.get("/admin/static/css/test.css")
cc = parse_cache_control_header(rv.headers["Cache-Control"])
cc = parse_cache_control(rv.headers["Cache-Control"])
assert cc.max_age == expected_max_age
rv.close()
finally:
Expand All @@ -225,7 +238,12 @@ class MyBlueprint(flask.Blueprint):
def get_send_file_max_age(self, filename):
return 100

blueprint = MyBlueprint("blueprint", __name__, static_folder="static")
blueprint = MyBlueprint(
"blueprint",
__name__,
static_folder="static",
static_url_path="/blueprint-static",
)
app.register_blueprint(blueprint)

# try/finally, in case other tests use this app for Blueprint tests.
Expand All @@ -237,7 +255,7 @@ def get_send_file_max_age(self, filename):
unexpected_max_age = 7200
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = unexpected_max_age
rv = blueprint.send_static_file("index.html")
cc = parse_cache_control_header(rv.headers["Cache-Control"])
cc = parse_cache_control(rv.headers["Cache-Control"])
assert cc.max_age == 100
rv.close()
finally:
Expand Down
7 changes: 6 additions & 1 deletion tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@

import click
import pytest
from _pytest.monkeypatch import notset

# I kept the fix from pull #6072
try:
from _pytest.monkeypatch import notset
except ImportError:
from _pytest.compat import NOTSET as notset
from click.testing import CliRunner

from flask import Blueprint
Expand Down
19 changes: 16 additions & 3 deletions tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import pytest
from werkzeug.http import parse_set_header
from werkzeug.datastructures import HeaderSet

# Fixed Deprecation of parse_set_header
if hasattr(HeaderSet, "from_header"):

def parse_header_set(value: str) -> HeaderSet:
return HeaderSet.from_header(value)

else:
from werkzeug.http import parse_set_header

def parse_header_set(value: str) -> HeaderSet:
return parse_set_header(value)


import flask.views

Expand All @@ -10,7 +23,7 @@ def common_test(app):
assert c.get("/").data == b"GET"
assert c.post("/").data == b"POST"
assert c.put("/").status_code == 405
meths = parse_set_header(c.open("/", method="OPTIONS").headers["Allow"])
meths = parse_header_set(c.open("/", method="OPTIONS").headers["Allow"])
assert sorted(meths) == ["GET", "HEAD", "OPTIONS", "POST"]


Expand Down Expand Up @@ -73,7 +86,7 @@ def delete(self):

app.add_url_rule("/", view_func=BetterIndex.as_view("index"))

meths = parse_set_header(client.open("/", method="OPTIONS").headers["Allow"])
meths = parse_header_set(client.open("/", method="OPTIONS").headers["Allow"])
assert sorted(meths) == ["DELETE", "GET", "HEAD", "OPTIONS", "POST"]


Expand Down