diff --git a/CHANGES.rst b/CHANGES.rst index 64d5770c..049c7f6f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -21,6 +21,8 @@ Unreleased corresponding ``json.JSONEncoder`` and ``JSONDecoder`` classes, are removed. - The ``json.htmlsafe_dumps`` and ``htmlsafe_dump`` functions are removed. +- Importing ``escape`` and ``Markup`` from ``flask`` is deprecated. Import them + directly from ``markupsafe`` instead. :pr:`4996` - Use modern packaging metadata with ``pyproject.toml`` instead of ``setup.cfg``. :pr:`4947` - Ensure subdomains are applied with nested blueprints. :issue:`4834` diff --git a/docs/api.rst b/docs/api.rst index bf37700f..8729f6cd 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -217,10 +217,6 @@ Useful Functions and Classes .. autofunction:: send_from_directory -.. autofunction:: escape - -.. autoclass:: Markup - :members: escape, unescape, striptags Message Flashing ---------------- diff --git a/docs/security.rst b/docs/security.rst index 777e5112..3992e8da 100644 --- a/docs/security.rst +++ b/docs/security.rst @@ -23,7 +23,7 @@ in templates, but there are still other places where you have to be careful: - generating HTML without the help of Jinja2 -- calling :class:`~flask.Markup` on data submitted by users +- calling :class:`~markupsafe.Markup` on data submitted by users - sending out HTML from uploaded files, never do that, use the ``Content-Disposition: attachment`` header to prevent that problem. - sending out textfiles from uploaded files. Some browsers are using diff --git a/docs/templating.rst b/docs/templating.rst index f497de73..23cfee4c 100644 --- a/docs/templating.rst +++ b/docs/templating.rst @@ -115,7 +115,7 @@ markdown to HTML converter. There are three ways to accomplish that: -- In the Python code, wrap the HTML string in a :class:`~flask.Markup` +- In the Python code, wrap the HTML string in a :class:`~markupsafe.Markup` object before passing it to the template. This is in general the recommended way. - Inside the template, use the ``|safe`` filter to explicitly mark a diff --git a/src/flask/__init__.py b/src/flask/__init__.py index cc953ab1..2361bdb4 100644 --- a/src/flask/__init__.py +++ b/src/flask/__init__.py @@ -1,6 +1,3 @@ -from markupsafe import escape -from markupsafe import Markup - from . import json as json from .app import Flask as Flask from .app import Request as Request @@ -68,4 +65,28 @@ def __getattr__(name): ) return __request_ctx_stack + if name == "escape": + import warnings + from markupsafe import escape + + warnings.warn( + "'flask.escape' is deprecated and will be removed in Flask 2.4. Import" + " 'markupsafe.escape' instead.", + DeprecationWarning, + stacklevel=2, + ) + return escape + + if name == "escape": + import warnings + from markupsafe import Markup + + warnings.warn( + "'flask.Markup' is deprecated and will be removed in Flask 2.4. Import" + " 'markupsafe.Markup' instead.", + DeprecationWarning, + stacklevel=2, + ) + return Markup + raise AttributeError(name) diff --git a/tests/test_basic.py b/tests/test_basic.py index 48d41b1e..9c9d83e7 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -9,6 +9,7 @@ from platform import python_implementation import pytest import werkzeug.serving +from markupsafe import Markup from werkzeug.exceptions import BadRequest from werkzeug.exceptions import Forbidden from werkzeug.exceptions import NotFound @@ -472,7 +473,7 @@ def test_session_special_types(app, client): def dump_session_contents(): flask.session["t"] = (1, 2, 3) flask.session["b"] = b"\xff" - flask.session["m"] = flask.Markup("") + flask.session["m"] = Markup("") flask.session["u"] = the_uuid flask.session["d"] = now flask.session["t_tag"] = {" t": "not-a-tuple"} @@ -486,8 +487,8 @@ def test_session_special_types(app, client): assert s["t"] == (1, 2, 3) assert type(s["b"]) == bytes assert s["b"] == b"\xff" - assert type(s["m"]) == flask.Markup - assert s["m"] == flask.Markup("") + assert type(s["m"]) == Markup + assert s["m"] == Markup("") assert s["u"] == the_uuid assert s["d"] == now assert s["t_tag"] == {" t": "not-a-tuple"} @@ -611,7 +612,7 @@ def test_extended_flashing(app): def index(): flask.flash("Hello World") flask.flash("Hello World", "error") - flask.flash(flask.Markup("Testing"), "warning") + flask.flash(Markup("Testing"), "warning") return "" @app.route("/test/") @@ -620,7 +621,7 @@ def test_extended_flashing(app): assert list(messages) == [ "Hello World", "Hello World", - flask.Markup("Testing"), + Markup("Testing"), ] return "" @@ -631,7 +632,7 @@ def test_extended_flashing(app): assert list(messages) == [ ("message", "Hello World"), ("error", "Hello World"), - ("warning", flask.Markup("Testing")), + ("warning", Markup("Testing")), ] return "" @@ -650,7 +651,7 @@ def test_extended_flashing(app): ) assert list(messages) == [ ("message", "Hello World"), - ("warning", flask.Markup("Testing")), + ("warning", Markup("Testing")), ] return "" @@ -659,7 +660,7 @@ def test_extended_flashing(app): messages = flask.get_flashed_messages(category_filter=["message", "warning"]) assert len(messages) == 2 assert messages[0] == "Hello World" - assert messages[1] == flask.Markup("Testing") + assert messages[1] == Markup("Testing") return "" # Create new test client on each test to clean flashed messages. diff --git a/tests/test_json_tag.py b/tests/test_json_tag.py index 7d11b963..677160a6 100644 --- a/tests/test_json_tag.py +++ b/tests/test_json_tag.py @@ -3,8 +3,8 @@ from datetime import timezone from uuid import uuid4 import pytest +from markupsafe import Markup -from flask import Markup from flask.json.tag import JSONTag from flask.json.tag import TaggedJSONSerializer diff --git a/tests/test_templating.py b/tests/test_templating.py index 863417c0..c9fb3754 100644 --- a/tests/test_templating.py +++ b/tests/test_templating.py @@ -3,6 +3,7 @@ import logging import pytest import werkzeug.serving from jinja2 import TemplateNotFound +from markupsafe import Markup import flask @@ -73,7 +74,7 @@ def test_escaping(app, client): @app.route("/") def index(): return flask.render_template( - "escaping_template.html", text=text, html=flask.Markup(text) + "escaping_template.html", text=text, html=Markup(text) ) lines = client.get("/").data.splitlines() @@ -93,7 +94,7 @@ def test_no_escaping(app, client): @app.route("/") def index(): return flask.render_template( - "non_escaping_template.txt", text=text, html=flask.Markup(text) + "non_escaping_template.txt", text=text, html=Markup(text) ) lines = client.get("/").data.splitlines()