diff --git a/docs/api.rst b/docs/api.rst index 693a6854..85e67c2b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -20,7 +20,6 @@ Forms and Fields .. module:: flask_wtf.file .. autoclass:: FileField - :members: has_file .. autoclass:: FileAllowed @@ -34,8 +33,6 @@ CSRF Protection .. autoclass:: CSRFProtect :members: -.. autoclass:: CsrfProtect(...) - .. autoclass:: CSRFError :members: diff --git a/docs/changes.rst b/docs/changes.rst index cc9df180..9cb3a24a 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -1,11 +1,10 @@ Changes ======= -Version 0.16.0 +Version 1.0.0 -------------- -Unreleased - +- Deprecated items removal :pr:`484` Version 0.15.1 -------------- diff --git a/src/flask_wtf/__init__.py b/src/flask_wtf/__init__.py index 6133cbc2..27571a33 100644 --- a/src/flask_wtf/__init__.py +++ b/src/flask_wtf/__init__.py @@ -1,5 +1,4 @@ from .csrf import CSRFProtect -from .csrf import CsrfProtect from .form import FlaskForm from .form import Form from .recaptcha import Recaptcha diff --git a/src/flask_wtf/_compat.py b/src/flask_wtf/_compat.py index 926a5e60..50973e06 100644 --- a/src/flask_wtf/_compat.py +++ b/src/flask_wtf/_compat.py @@ -1,20 +1,6 @@ import warnings -def to_bytes(text): - """Transform string to bytes.""" - if isinstance(text, str): - text = text.encode("utf-8") - return text - - -def to_unicode(input_bytes, encoding="utf-8"): - """Decodes input_bytes to text if needed.""" - if not isinstance(input_bytes, str): - input_bytes = input_bytes.decode(encoding) - return input_bytes - - class FlaskWTFDeprecationWarning(DeprecationWarning): pass diff --git a/src/flask_wtf/csrf.py b/src/flask_wtf/csrf.py index 69a9b5a3..18e75971 100644 --- a/src/flask_wtf/csrf.py +++ b/src/flask_wtf/csrf.py @@ -2,8 +2,6 @@ import hmac import logging import os -import warnings -from functools import wraps from urllib.parse import urlparse from flask import Blueprint @@ -18,8 +16,6 @@ from wtforms import ValidationError from wtforms.csrf.core import CSRF -from ._compat import FlaskWTFDeprecationWarning - __all__ = ("generate_csrf", "validate_csrf", "CSRFProtect") logger = logging.getLogger(__name__) @@ -310,59 +306,6 @@ def some_view(): def _error_response(self, reason): raise CSRFError(reason) - def error_handler(self, view): - """Register a function that will generate the response for CSRF errors. - - .. deprecated:: 0.14 - Use the standard Flask error system with - ``@app.errorhandler(CSRFError)`` instead. This will be removed in - version 1.0. - - The function will be passed one argument, ``reason``. By default it - will raise a :class:`~flask_wtf.csrf.CSRFError`. :: - - @csrf.error_handler - def csrf_error(reason): - return render_template('error.html', reason=reason) - - Due to historical reasons, the function may either return a response - or raise an exception with :func:`flask.abort`. - """ - - warnings.warn( - FlaskWTFDeprecationWarning( - '"@csrf.error_handler" is deprecated. Use the standard Flask ' - 'error system with "@app.errorhandler(CSRFError)" instead. This ' - "will be removed in 1.0." - ), - stacklevel=2, - ) - - @wraps(view) - def handler(reason): - response = current_app.make_response(view(reason)) - raise CSRFError(response=response) - - self._error_response = handler - return view - - -class CsrfProtect(CSRFProtect): - """ - .. deprecated:: 0.14 - Renamed to :class:`~flask_wtf.csrf.CSRFProtect`. - """ - - def __init__(self, app=None): - warnings.warn( - FlaskWTFDeprecationWarning( - '"flask_wtf.CsrfProtect" has been renamed to "CSRFProtect" ' - "and will be removed in 1.0." - ), - stacklevel=2, - ) - super().__init__(app=app) - class CSRFError(BadRequest): """Raise if the client sends invalid CSRF data with the request. diff --git a/src/flask_wtf/file.py b/src/flask_wtf/file.py index 1a7dd624..b2166966 100644 --- a/src/flask_wtf/file.py +++ b/src/flask_wtf/file.py @@ -1,4 +1,3 @@ -import warnings from collections import abc from werkzeug.datastructures import FileStorage @@ -7,8 +6,6 @@ from wtforms.validators import StopValidation from wtforms.validators import ValidationError -from ._compat import FlaskWTFDeprecationWarning - class FileField(_FileField): """Werkzeug-aware subclass of :class:`wtforms.fields.FileField`.""" @@ -22,23 +19,6 @@ def process_formdata(self, valuelist): else: self.raw_data = () - def has_file(self): - """Return ``True`` if ``self.data`` is a - :class:`~werkzeug.datastructures.FileStorage` object. - - .. deprecated:: 0.14.1 - ``data`` is no longer set if the input is not a non-empty - ``FileStorage``. Check ``form.data is not None`` instead. - """ - - warnings.warn( - FlaskWTFDeprecationWarning( - '"has_file" is deprecated and will be removed in 1.0. The data is ' - "checked during processing instead." - ) - ) - return bool(self.data) - class FileRequired(DataRequired): """Validates that the data is a Werkzeug diff --git a/src/flask_wtf/form.py b/src/flask_wtf/form.py index 289e871b..9134b7dd 100644 --- a/src/flask_wtf/form.py +++ b/src/flask_wtf/form.py @@ -1,5 +1,3 @@ -import warnings - from flask import current_app from flask import request from flask import session @@ -11,7 +9,6 @@ from wtforms.meta import DefaultMeta from wtforms.widgets import HiddenInput -from ._compat import FlaskWTFDeprecationWarning from .csrf import _FlaskFormCSRF try: @@ -73,19 +70,6 @@ def get_translations(self, form): return translations def __init__(self, formdata=_Auto, **kwargs): - csrf_enabled = kwargs.pop("csrf_enabled", None) - - if csrf_enabled is not None: - warnings.warn( - FlaskWTFDeprecationWarning( - '"csrf_enabled" is deprecated and will be removed in 1.0. ' - "Pass meta={'csrf': False} instead." - ), - stacklevel=3, - ) - kwargs["meta"] = kwargs.get("meta") or {} - kwargs["meta"].setdefault("csrf", csrf_enabled) - super().__init__(formdata=formdata, **kwargs) def is_submitted(self): @@ -141,20 +125,3 @@ def _is_submitted(): """ return bool(request) and request.method in SUBMIT_METHODS - - -class Form(FlaskForm): - """ - .. deprecated:: 0.13 - Renamed to :class:`~flask_wtf.FlaskForm`. - """ - - def __init__(self, *args, **kwargs): - warnings.warn( - FlaskWTFDeprecationWarning( - '"flask_wtf.Form" has been renamed to "FlaskForm" ' - "and will be removed in 1.0." - ), - stacklevel=3, - ) - super().__init__(*args, **kwargs) diff --git a/src/flask_wtf/html5.py b/src/flask_wtf/html5.py deleted file mode 100644 index f07c6c54..00000000 --- a/src/flask_wtf/html5.py +++ /dev/null @@ -1,15 +0,0 @@ -import warnings - -from ._compat import FlaskWTFDeprecationWarning - -warnings.warn( - FlaskWTFDeprecationWarning( - '"flask_wtf.html5" will be removed in 1.0. ' - 'Import directly from "wtforms.fields.html5" ' - 'and "wtforms.widgets.html5".' - ), - stacklevel=2, -) - -from wtforms.widgets.html5 import * # noqa: E402, F401, F403 -from wtforms.fields.html5 import * # noqa: E402, F401, F403 diff --git a/src/flask_wtf/recaptcha/validators.py b/src/flask_wtf/recaptcha/validators.py index 3ff1ee0a..c3e92309 100644 --- a/src/flask_wtf/recaptcha/validators.py +++ b/src/flask_wtf/recaptcha/validators.py @@ -6,9 +6,6 @@ from werkzeug.urls import url_encode from wtforms import ValidationError -from .._compat import to_bytes -from .._compat import to_unicode - RECAPTCHA_VERIFY_SERVER = "https://www.google.com/recaptcha/api/siteverify" RECAPTCHA_ERROR_CODES = { "missing-input-secret": "The secret parameter is missing.", @@ -57,12 +54,12 @@ def _validate_recaptcha(self, response, remote_addr): {"secret": private_key, "remoteip": remote_addr, "response": response} ) - http_response = http.urlopen(RECAPTCHA_VERIFY_SERVER, to_bytes(data)) + http_response = http.urlopen(RECAPTCHA_VERIFY_SERVER, data.encode("utf-8")) if http_response.code != 200: return False - json_resp = json.loads(to_unicode(http_response.read())) + json_resp = json.loads(http_response.read()) if json_resp["success"]: return True diff --git a/tests/test_csrf_extension.py b/tests/test_csrf_extension.py index daf79162..637c63b6 100644 --- a/tests/test_csrf_extension.py +++ b/tests/test_csrf_extension.py @@ -1,15 +1,11 @@ import pytest -from flask import abort from flask import Blueprint from flask import g from flask import render_template_string -from flask import request from flask_wtf import FlaskForm -from flask_wtf._compat import FlaskWTFDeprecationWarning from flask_wtf.csrf import CSRFError from flask_wtf.csrf import CSRFProtect -from flask_wtf.csrf import CsrfProtect from flask_wtf.csrf import generate_csrf @@ -180,28 +176,3 @@ def assert_info(message): client.post("/") assert len(messages) == 1 assert messages[0] == "The CSRF token is missing." - - -def test_deprecated_csrfprotect(recwarn): - CsrfProtect() - w = recwarn.pop(FlaskWTFDeprecationWarning) - assert "CSRFProtect" in str(w.message) - - -def test_deprecated_error_handler(csrf, client, recwarn): - @csrf.error_handler - def handle_csrf_error(reason): - if "abort" in request.form: - abort(418) - - return "return" - - w = recwarn.pop(FlaskWTFDeprecationWarning) - assert "@app.errorhandler" in str(w.message) - - response = client.post("/", data={"abort": "1"}) - assert response.status_code == 418 - - response = client.post("/") - assert response.status_code == 200 - assert "return" in response.get_data(as_text=True) diff --git a/tests/test_file.py b/tests/test_file.py index 242c1736..e242a7ff 100644 --- a/tests/test_file.py +++ b/tests/test_file.py @@ -4,7 +4,6 @@ from wtforms import FileField as BaseFileField from flask_wtf import FlaskForm -from flask_wtf._compat import FlaskWTFDeprecationWarning from flask_wtf.file import FileAllowed from flask_wtf.file import FileField from flask_wtf.file import FileRequired @@ -127,9 +126,3 @@ class Meta: assert not F().validate() assert not F(f=FileStorage()).validate() assert F(f=FileStorage(filename="real")).validate() - - -def test_deprecated_filefield(recwarn, form): - assert not form().file.has_file() - w = recwarn.pop(FlaskWTFDeprecationWarning) - assert "has_file" in str(w.message) diff --git a/tests/test_form.py b/tests/test_form.py index b774b121..2c2cbd3d 100644 --- a/tests/test_form.py +++ b/tests/test_form.py @@ -6,13 +6,10 @@ from wtforms import HiddenField from wtforms import IntegerField from wtforms import StringField -from wtforms.form import FormMeta from wtforms.validators import DataRequired from wtforms.widgets import HiddenInput from flask_wtf import FlaskForm -from flask_wtf import Form -from flask_wtf._compat import FlaskWTFDeprecationWarning class BasicForm(FlaskForm): @@ -105,35 +102,6 @@ class Meta: assert "csrf_token" not in f.hidden_tag("count", "key") -def test_deprecated_form(req_ctx, recwarn): - class F(Form): - pass - - F() - w = recwarn.pop(FlaskWTFDeprecationWarning) - assert "FlaskForm" in str(w.message) - - -def test_custom_meta_with_deprecated_form(req_ctx, recwarn): - class FMeta(FormMeta): - pass - - class F(Form, metaclass=FMeta): - pass - - F() - recwarn.pop(FlaskWTFDeprecationWarning) - - -def test_deprecated_csrf_enabled(req_ctx, recwarn): - class F(FlaskForm): - pass - - F(csrf_enabled=False) - w = recwarn.pop(FlaskWTFDeprecationWarning) - assert "meta={'csrf': False}" in str(w.message) - - def test_set_default_message_language(app, client): @app.route("/default", methods=["POST"]) def default(): diff --git a/tests/test_html5.py b/tests/test_html5.py deleted file mode 100644 index c322dd4d..00000000 --- a/tests/test_html5.py +++ /dev/null @@ -1,7 +0,0 @@ -from flask_wtf._compat import FlaskWTFDeprecationWarning - - -def test_deprecated_html5(recwarn): - __import__("flask_wtf.html5") - w = recwarn.pop(FlaskWTFDeprecationWarning) - assert "wtforms.fields.html5" in str(w.message) diff --git a/tests/test_recaptcha.py b/tests/test_recaptcha.py index dfc1c8b0..483b5217 100644 --- a/tests/test_recaptcha.py +++ b/tests/test_recaptcha.py @@ -3,7 +3,6 @@ from markupsafe import Markup from flask_wtf import FlaskForm -from flask_wtf._compat import to_bytes from flask_wtf.recaptcha import RecaptchaField from flask_wtf.recaptcha.validators import http from flask_wtf.recaptcha.validators import Recaptcha @@ -86,7 +85,7 @@ def __init__(self, code, error="invalid-input-response", read_bytes=False): def read(self): if self.read_bytes: - return to_bytes(self.data) + return self.data.encode("utf-8") return self.data