forked from orbit-oss/flask
Merge branch '2.0.x'
This commit is contained in:
commit
83f7efa047
11 changed files with 76 additions and 44 deletions
|
|
@ -31,6 +31,8 @@ Unreleased
|
|||
- Roll back a change to the order that URL matching was done. The
|
||||
URL is again matched after the session is loaded, so the session is
|
||||
available in custom URL converters. :issue:`4053`
|
||||
- Re-add deprecated ``Config.from_json``, which was accidentally
|
||||
removed early. :issue:`4078`
|
||||
|
||||
|
||||
Version 2.0.0
|
||||
|
|
|
|||
|
|
@ -49,10 +49,10 @@ html_context = {
|
|||
]
|
||||
}
|
||||
html_sidebars = {
|
||||
"index": ["project.html", "localtoc.html", "searchbox.html"],
|
||||
"**": ["localtoc.html", "relations.html", "searchbox.html"],
|
||||
"index": ["project.html", "localtoc.html", "searchbox.html", "ethicalads.html"],
|
||||
"**": ["localtoc.html", "relations.html", "searchbox.html", "ethicalads.html"],
|
||||
}
|
||||
singlehtml_sidebars = {"index": ["project.html", "localtoc.html"]}
|
||||
singlehtml_sidebars = {"index": ["project.html", "localtoc.html", "ethicalads.html"]}
|
||||
html_static_path = ["_static"]
|
||||
html_favicon = "_static/flask-icon.png"
|
||||
html_logo = "_static/flask-icon.png"
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ of the argument like ``<converter:variable_name>``. ::
|
|||
@app.route('/user/<username>')
|
||||
def show_user_profile(username):
|
||||
# show the user profile for that user
|
||||
return f'User {username}'
|
||||
return f'User {escape(username)}'
|
||||
|
||||
@app.route('/post/<int:post_id>')
|
||||
def show_post(post_id):
|
||||
|
|
@ -256,7 +256,7 @@ of the argument like ``<converter:variable_name>``. ::
|
|||
@app.route('/path/<path:subpath>')
|
||||
def show_subpath(subpath):
|
||||
# show the subpath after /path/
|
||||
return f'Subpath {subpath}'
|
||||
return f'Subpath {escape(subpath)}'
|
||||
|
||||
Converter types:
|
||||
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ blinker==1.4
|
|||
# via -r requirements/tests.in
|
||||
certifi==2020.12.5
|
||||
# via requests
|
||||
cfgv==3.2.0
|
||||
cfgv==3.3.0
|
||||
# via pre-commit
|
||||
chardet==4.0.0
|
||||
# via requests
|
||||
click==8.0.0
|
||||
click==8.0.1
|
||||
# via pip-tools
|
||||
distlib==0.3.1
|
||||
# via virtualenv
|
||||
|
|
@ -44,9 +44,9 @@ imagesize==1.2.0
|
|||
# via sphinx
|
||||
iniconfig==1.1.1
|
||||
# via pytest
|
||||
jinja2==3.0.0
|
||||
jinja2==3.0.1
|
||||
# via sphinx
|
||||
markupsafe==2.0.0
|
||||
markupsafe==2.0.1
|
||||
# via jinja2
|
||||
mypy-extensions==0.4.3
|
||||
# via mypy
|
||||
|
|
@ -60,7 +60,7 @@ packaging==20.9
|
|||
# pytest
|
||||
# sphinx
|
||||
# tox
|
||||
pallets-sphinx-themes==2.0.0
|
||||
pallets-sphinx-themes==2.0.1
|
||||
# via -r requirements/docs.in
|
||||
pep517==0.10.0
|
||||
# via pip-tools
|
||||
|
|
@ -102,7 +102,7 @@ sphinx-issues==1.2.0
|
|||
# via -r requirements/docs.in
|
||||
sphinx-tabs==3.0.0
|
||||
# via -r requirements/docs.in
|
||||
git+https://github.com/sphinx-doc/sphinx.git@96dbe5e3
|
||||
sphinx==4.0.2
|
||||
# via
|
||||
# -r requirements/docs.in
|
||||
# pallets-sphinx-themes
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Pallets-Sphinx-Themes
|
||||
git+https://github.com/sphinx-doc/sphinx.git@96dbe5e3 # https://github.com/sphinx-doc/sphinx/issues/921
|
||||
Sphinx
|
||||
sphinx-issues
|
||||
sphinxcontrib-log-cabinet
|
||||
sphinx-tabs
|
||||
|
|
|
|||
|
|
@ -20,15 +20,15 @@ idna==2.10
|
|||
# via requests
|
||||
imagesize==1.2.0
|
||||
# via sphinx
|
||||
jinja2==3.0.0
|
||||
jinja2==3.0.1
|
||||
# via sphinx
|
||||
markupsafe==2.0.0
|
||||
markupsafe==2.0.1
|
||||
# via jinja2
|
||||
packaging==20.9
|
||||
# via
|
||||
# pallets-sphinx-themes
|
||||
# sphinx
|
||||
pallets-sphinx-themes==2.0.0
|
||||
pallets-sphinx-themes==2.0.1
|
||||
# via -r requirements/docs.in
|
||||
pygments==2.9.0
|
||||
# via
|
||||
|
|
@ -46,7 +46,7 @@ sphinx-issues==1.2.0
|
|||
# via -r requirements/docs.in
|
||||
sphinx-tabs==3.0.0
|
||||
# via -r requirements/docs.in
|
||||
git+https://github.com/sphinx-doc/sphinx.git@96dbe5e3
|
||||
sphinx==4.0.2
|
||||
# via
|
||||
# -r requirements/docs.in
|
||||
# pallets-sphinx-themes
|
||||
|
|
|
|||
|
|
@ -354,6 +354,8 @@ class Blueprint(Scaffold):
|
|||
bp_options["url_prefix"] = (
|
||||
state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/")
|
||||
)
|
||||
else:
|
||||
bp_options["url_prefix"] = state.url_prefix
|
||||
|
||||
bp_options["name_prefix"] = options.get("name_prefix", "") + self.name + "."
|
||||
blueprint.register(app, bp_options)
|
||||
|
|
|
|||
|
|
@ -202,6 +202,31 @@ class Config(dict):
|
|||
|
||||
return self.from_mapping(obj)
|
||||
|
||||
def from_json(self, filename: str, silent: bool = False) -> bool:
|
||||
"""Update the values in the config from a JSON file. The loaded
|
||||
data is passed to the :meth:`from_mapping` method.
|
||||
|
||||
:param filename: The path to the JSON file. This can be an
|
||||
absolute path or relative to the config root path.
|
||||
:param silent: Ignore the file if it doesn't exist.
|
||||
|
||||
.. deprecated:: 2.0.0
|
||||
Will be removed in Flask 2.1. Use :meth:`from_file` instead.
|
||||
This was removed early in 2.0.0, was added back in 2.0.1.
|
||||
|
||||
.. versionadded:: 0.11
|
||||
"""
|
||||
import warnings
|
||||
from . import json
|
||||
|
||||
warnings.warn(
|
||||
"'from_json' is deprecated and will be removed in Flask"
|
||||
" 2.1. Use 'from_file(path, json.load)' instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.from_file(filename, json.load, silent=silent)
|
||||
|
||||
def from_mapping(
|
||||
self, mapping: t.Optional[t.Mapping[str, t.Any]] = None, **kwargs: t.Any
|
||||
) -> bool:
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import typing as t
|
|||
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from _typeshed.wsgi import WSGIApplication # noqa: F401
|
||||
from werkzeug.datastructures import Headers # noqa: F401
|
||||
from wsgiref.types import WSGIApplication # noqa: F401
|
||||
from .wrappers import Response # noqa: F401
|
||||
|
||||
# The possible types that are directly convertible or are a Response object.
|
||||
|
|
|
|||
|
|
@ -868,3 +868,17 @@ def test_nested_blueprint_url_prefix(app, client):
|
|||
assert client.get("/parent/child/").data == b"Child"
|
||||
assert client.get("/parent/child/grandchild/").data == b"Grandchild"
|
||||
assert client.get("/parent/child/orange/").data == b"Apple"
|
||||
|
||||
|
||||
def test_nested_blueprint_url_prefix_only_parent_prefix(app, client):
|
||||
parent = flask.Blueprint("parent", __name__)
|
||||
child = flask.Blueprint("child", __name__)
|
||||
|
||||
@child.route("/child-endpoint")
|
||||
def child_index():
|
||||
return "Child"
|
||||
|
||||
parent.register_blueprint(child)
|
||||
app.register_blueprint(parent, url_prefix="/parent")
|
||||
|
||||
assert client.get("/parent/child-endpoint").data == b"Child"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import ssl
|
|||
import sys
|
||||
import types
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import click
|
||||
|
|
@ -29,8 +30,8 @@ from flask.cli import run_command
|
|||
from flask.cli import ScriptInfo
|
||||
from flask.cli import with_appcontext
|
||||
|
||||
cwd = os.getcwd()
|
||||
test_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "test_apps"))
|
||||
cwd = Path.cwd()
|
||||
test_path = (Path(__file__) / ".." / "test_apps").resolve()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
@ -152,29 +153,25 @@ def test_find_best_app(test_apps):
|
|||
(
|
||||
("test", cwd, "test"),
|
||||
("test.py", cwd, "test"),
|
||||
("a/test", os.path.join(cwd, "a"), "test"),
|
||||
("a/test", cwd / "a", "test"),
|
||||
("test/__init__.py", cwd, "test"),
|
||||
("test/__init__", cwd, "test"),
|
||||
# nested package
|
||||
(
|
||||
os.path.join(test_path, "cliapp", "inner1", "__init__"),
|
||||
test_path / "cliapp" / "inner1" / "__init__",
|
||||
test_path,
|
||||
"cliapp.inner1",
|
||||
),
|
||||
(
|
||||
os.path.join(test_path, "cliapp", "inner1", "inner2"),
|
||||
test_path / "cliapp" / "inner1" / "inner2",
|
||||
test_path,
|
||||
"cliapp.inner1.inner2",
|
||||
),
|
||||
# dotted name
|
||||
("test.a.b", cwd, "test.a.b"),
|
||||
(os.path.join(test_path, "cliapp.app"), test_path, "cliapp.app"),
|
||||
(test_path / "cliapp.app", test_path, "cliapp.app"),
|
||||
# not a Python file, will be caught during import
|
||||
(
|
||||
os.path.join(test_path, "cliapp", "message.txt"),
|
||||
test_path,
|
||||
"cliapp.message.txt",
|
||||
),
|
||||
(test_path / "cliapp" / "message.txt", test_path, "cliapp.message.txt"),
|
||||
),
|
||||
)
|
||||
def test_prepare_import(request, value, path, result):
|
||||
|
|
@ -193,7 +190,7 @@ def test_prepare_import(request, value, path, result):
|
|||
request.addfinalizer(reset_path)
|
||||
|
||||
assert prepare_import(value) == result
|
||||
assert sys.path[0] == path
|
||||
assert sys.path[0] == str(path)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
@ -278,9 +275,8 @@ def test_scriptinfo(test_apps, monkeypatch):
|
|||
assert obj.load_app() is app
|
||||
|
||||
# import app with module's absolute path
|
||||
cli_app_path = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), "test_apps", "cliapp", "app.py")
|
||||
)
|
||||
cli_app_path = str(test_path / "cliapp" / "app.py")
|
||||
|
||||
obj = ScriptInfo(app_import_path=cli_app_path)
|
||||
app = obj.load_app()
|
||||
assert app.name == "testapp"
|
||||
|
|
@ -302,19 +298,13 @@ def test_scriptinfo(test_apps, monkeypatch):
|
|||
pytest.raises(NoAppException, obj.load_app)
|
||||
|
||||
# import app from wsgi.py in current directory
|
||||
monkeypatch.chdir(
|
||||
os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), "test_apps", "helloworld")
|
||||
)
|
||||
)
|
||||
monkeypatch.chdir(test_path / "helloworld")
|
||||
obj = ScriptInfo()
|
||||
app = obj.load_app()
|
||||
assert app.name == "hello"
|
||||
|
||||
# import app from app.py in current directory
|
||||
monkeypatch.chdir(
|
||||
os.path.abspath(os.path.join(os.path.dirname(__file__), "test_apps", "cliapp"))
|
||||
)
|
||||
monkeypatch.chdir(test_path / "cliapp")
|
||||
obj = ScriptInfo()
|
||||
app = obj.load_app()
|
||||
assert app.name == "testapp"
|
||||
|
|
@ -513,7 +503,7 @@ def test_load_dotenv(monkeypatch):
|
|||
monkeypatch.setenv("EGGS", "3")
|
||||
monkeypatch.chdir(test_path)
|
||||
assert load_dotenv()
|
||||
assert os.getcwd() == test_path
|
||||
assert Path.cwd() == test_path
|
||||
# .flaskenv doesn't overwrite .env
|
||||
assert os.environ["FOO"] == "env"
|
||||
# set only in .flaskenv
|
||||
|
|
@ -533,9 +523,8 @@ def test_dotenv_path(monkeypatch):
|
|||
for item in ("FOO", "BAR", "EGGS"):
|
||||
monkeypatch._setitem.append((os.environ, item, notset))
|
||||
|
||||
cwd = os.getcwd()
|
||||
load_dotenv(os.path.join(test_path, ".flaskenv"))
|
||||
assert os.getcwd() == cwd
|
||||
load_dotenv(test_path / ".flaskenv")
|
||||
assert Path.cwd() == cwd
|
||||
assert "FOO" in os.environ
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue