From 9a1b25fce4ddd553d7cba01bab3df5841a24aeff Mon Sep 17 00:00:00 2001 From: David Lord Date: Wed, 3 Aug 2022 06:47:31 -0700 Subject: [PATCH 1/4] start version 2.2.1 --- CHANGES.rst | 6 ++++++ src/flask/__init__.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index bb67fdd4..2b021d88 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,9 @@ +Version 2.2.1 +------------- + +Unreleased + + Version 2.2.0 ------------- diff --git a/src/flask/__init__.py b/src/flask/__init__.py index b9f706be..6a993341 100644 --- a/src/flask/__init__.py +++ b/src/flask/__init__.py @@ -42,7 +42,7 @@ from .templating import render_template_string as render_template_string from .templating import stream_template as stream_template from .templating import stream_template_string as stream_template_string -__version__ = "2.2.0" +__version__ = "2.2.1.dev" def __getattr__(name): From 714ccefeca33db9e87e8ef4abd0008af05c32a4d Mon Sep 17 00:00:00 2001 From: David Lord Date: Wed, 3 Aug 2022 09:11:37 -0700 Subject: [PATCH 2/4] show deprecation warning on json_encoder/decoder access --- CHANGES.rst | 11 +++-- src/flask/app.py | 98 +++++++++++++++++++++++++++++++------- src/flask/blueprints.py | 83 +++++++++++++++++++++++++++----- src/flask/json/provider.py | 12 ++--- src/flask/scaffold.py | 5 +- 5 files changed, 167 insertions(+), 42 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 2b021d88..2cd3144b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,6 +3,9 @@ Version 2.2.1 Unreleased +- Setting or accessing ``json_encoder`` or ``json_decoder`` raises a + deprecation warning. :issue:`4732` + Version 2.2.0 ------------- @@ -50,18 +53,18 @@ Released 2022-08-01 provider can be set to use a different JSON library. ``flask.jsonify`` will call ``app.json.response``, other functions in ``flask.json`` will call corresponding functions in - ``app.json``. :pr:`4688` + ``app.json``. :pr:`4692` - JSON configuration is moved to attributes on the default ``app.json`` provider. ``JSON_AS_ASCII``, ``JSON_SORT_KEYS``, ``JSONIFY_MIMETYPE``, and ``JSONIFY_PRETTYPRINT_REGULAR`` are - deprecated. :pr:`4688` + deprecated. :pr:`4692` - Setting custom ``json_encoder`` and ``json_decoder`` classes on the app or a blueprint, and the corresponding ``json.JSONEncoder`` and ``JSONDecoder`` classes, are deprecated. JSON behavior can now be - overridden using the ``app.json`` provider interface. :pr:`4688` + overridden using the ``app.json`` provider interface. :pr:`4692` - ``json.htmlsafe_dumps`` and ``json.htmlsafe_dump`` are deprecated, - the function is built-in to Jinja now. :pr:`4688` + the function is built-in to Jinja now. :pr:`4692` - Refactor ``register_error_handler`` to consolidate error checking. Rewrite some error messages to be more consistent. :issue:`4559` - Use Blueprint decorators and functions intended for setup after diff --git a/src/flask/app.py b/src/flask/app.py index 2da0a9fa..965865f2 100644 --- a/src/flask/app.py +++ b/src/flask/app.py @@ -1,5 +1,6 @@ import functools import inspect +import json import logging import os import sys @@ -379,25 +380,86 @@ class Flask(Scaffold): ) self.config["USE_X_SENDFILE"] = value - #: The JSON encoder class to use. Defaults to - #: :class:`~flask.json.JSONEncoder`. - #: - #: .. deprecated:: 2.2 - #: Will be removed in Flask 2.3. Customize - #: :attr:`json_provider_class` instead. - #: - #: .. versionadded:: 0.10 - json_encoder: None = None + _json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None + _json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None - #: The JSON decoder class to use. Defaults to - #: :class:`~flask.json.JSONDecoder`. - #: - #: .. deprecated:: 2.2 - #: Will be removed in Flask 2.3. Customize - #: :attr:`json_provider_class` instead. - #: - #: .. versionadded:: 0.10 - json_decoder: None = None + @property # type: ignore[override] + def json_encoder(self) -> t.Type[json.JSONEncoder]: # type: ignore[override] + """The JSON encoder class to use. Defaults to + :class:`~flask.json.JSONEncoder`. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Customize + :attr:`json_provider_class` instead. + + .. versionadded:: 0.10 + """ + import warnings + + warnings.warn( + "'app.json_encoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + + if self._json_encoder is None: + from . import json + + return json.JSONEncoder + + return self._json_encoder + + @json_encoder.setter + def json_encoder(self, value: t.Type[json.JSONEncoder]) -> None: + import warnings + + warnings.warn( + "'app.json_encoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + self._json_encoder = value + + @property # type: ignore[override] + def json_decoder(self) -> t.Type[json.JSONDecoder]: # type: ignore[override] + """The JSON decoder class to use. Defaults to + :class:`~flask.json.JSONDecoder`. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Customize + :attr:`json_provider_class` instead. + + .. versionadded:: 0.10 + """ + import warnings + + warnings.warn( + "'app.json_decoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + + if self._json_decoder is None: + from . import json + + return json.JSONDecoder + + return self._json_decoder + + @json_decoder.setter + def json_decoder(self, value: t.Type[json.JSONDecoder]) -> None: + import warnings + + warnings.warn( + "'app.json_decoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + self._json_decoder = value json_provider_class: t.Type[JSONProvider] = DefaultJSONProvider """A subclass of :class:`~flask.json.provider.JSONProvider`. An diff --git a/src/flask/blueprints.py b/src/flask/blueprints.py index 17885136..104f8acf 100644 --- a/src/flask/blueprints.py +++ b/src/flask/blueprints.py @@ -1,3 +1,4 @@ +import json import os import typing as t from collections import defaultdict @@ -172,18 +173,76 @@ class Blueprint(Scaffold): _got_registered_once = False - #: Blueprint local JSON encoder class to use. Set to ``None`` to use - #: the app's :class:`~flask.Flask.json_encoder`. - #: - #: .. deprecated:: 2.2 - #: Will be removed in Flask 2.3. - json_encoder: None = None - #: Blueprint local JSON decoder class to use. Set to ``None`` to use - #: the app's :class:`~flask.Flask.json_decoder`. - #: - #: .. deprecated:: 2.2 - #: Will be removed in Flask 2.3. - json_decoder: None = None + _json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None + _json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None + + @property # type: ignore[override] + def json_encoder( # type: ignore[override] + self, + ) -> t.Union[t.Type[json.JSONEncoder], None]: + """Blueprint-local JSON encoder class to use. Set to ``None`` to use the app's. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Customize + :attr:`json_provider_class` instead. + + .. versionadded:: 0.10 + """ + import warnings + + warnings.warn( + "'bp.json_encoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + return self._json_encoder + + @json_encoder.setter + def json_encoder(self, value: t.Union[t.Type[json.JSONEncoder], None]) -> None: + import warnings + + warnings.warn( + "'bp.json_encoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + self._json_encoder = value + + @property # type: ignore[override] + def json_decoder( # type: ignore[override] + self, + ) -> t.Union[t.Type[json.JSONDecoder], None]: + """Blueprint-local JSON decoder class to use. Set to ``None`` to use the app's. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Customize + :attr:`json_provider_class` instead. + + .. versionadded:: 0.10 + """ + import warnings + + warnings.warn( + "'bp.json_decoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + return self._json_decoder + + @json_decoder.setter + def json_decoder(self, value: t.Union[t.Type[json.JSONDecoder], None]) -> None: + import warnings + + warnings.warn( + "'bp.json_decoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + self._json_decoder = value def __init__( self, diff --git a/src/flask/json/provider.py b/src/flask/json/provider.py index 025d9df5..cb6aae80 100644 --- a/src/flask/json/provider.py +++ b/src/flask/json/provider.py @@ -176,11 +176,11 @@ class DefaultJSONProvider(JSONProvider): :param obj: The data to serialize. :param kwargs: Passed to :func:`json.dumps`. """ - cls = self._app.json_encoder + cls = self._app._json_encoder bp = self._app.blueprints.get(request.blueprint) if request else None - if bp is not None and bp.json_encoder is not None: - cls = bp.json_encoder + if bp is not None and bp._json_encoder is not None: + cls = bp._json_encoder if cls is not None: import warnings @@ -235,11 +235,11 @@ class DefaultJSONProvider(JSONProvider): :param s: Text or UTF-8 bytes. :param kwargs: Passed to :func:`json.loads`. """ - cls = self._app.json_decoder + cls = self._app._json_decoder bp = self._app.blueprints.get(request.blueprint) if request else None - if bp is not None and bp.json_decoder is not None: - cls = bp.json_decoder + if bp is not None and bp._json_decoder is not None: + cls = bp._json_decoder if cls is not None: import warnings diff --git a/src/flask/scaffold.py b/src/flask/scaffold.py index 4d3356b8..1530a11e 100644 --- a/src/flask/scaffold.py +++ b/src/flask/scaffold.py @@ -1,4 +1,5 @@ import importlib.util +import json import os import pathlib import pkgutil @@ -78,14 +79,14 @@ class Scaffold: #: #: .. deprecated:: 2.2 #: Will be removed in Flask 2.3. - json_encoder: None = None + json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None #: JSON decoder class used by :func:`flask.json.loads`. If a #: blueprint sets this, it will be used instead of the app's value. #: #: .. deprecated:: 2.2 #: Will be removed in Flask 2.3. - json_decoder: None = None + json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None def __init__( self, From 0d87b22314d7d0f1a0aa6c3be340095412f6637e Mon Sep 17 00:00:00 2001 From: David Lord Date: Wed, 3 Aug 2022 16:39:35 -0700 Subject: [PATCH 3/4] update requirements --- .pre-commit-config.yaml | 2 +- requirements/dev.txt | 14 ++++++-------- requirements/docs.txt | 2 +- requirements/tests.txt | 4 ++-- requirements/typing.txt | 4 ++-- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8a2eef41..5d767e60 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: hooks: - id: black - repo: https://github.com/PyCQA/flake8 - rev: 5.0.2 + rev: 5.0.4 hooks: - id: flake8 additional_dependencies: diff --git a/requirements/dev.txt b/requirements/dev.txt index 50e233ec..03d224c1 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -16,7 +16,7 @@ click==8.1.3 # via # pip-compile-multi # pip-tools -distlib==0.3.4 +distlib==0.3.5 # via virtualenv filelock==3.7.1 # via @@ -24,13 +24,13 @@ filelock==3.7.1 # virtualenv greenlet==1.1.2 ; python_version < "3.11" # via -r requirements/tests.in -identify==2.5.1 +identify==2.5.3 # via pre-commit nodeenv==1.7.0 # via pre-commit -pep517==0.12.0 +pep517==0.13.0 # via build -pip-compile-multi==2.4.5 +pip-compile-multi==2.4.6 # via -r requirements/dev.in pip-tools==6.8.0 # via pip-compile-multi @@ -41,9 +41,7 @@ pre-commit==2.20.0 pyyaml==6.0 # via pre-commit six==1.16.0 - # via - # tox - # virtualenv + # via tox toml==0.10.2 # via # pre-commit @@ -52,7 +50,7 @@ toposort==1.7 # via pip-compile-multi tox==3.25.1 # via -r requirements/dev.in -virtualenv==20.15.1 +virtualenv==20.16.2 # via # pre-commit # tox diff --git a/requirements/docs.txt b/requirements/docs.txt index 54b8b492..2ac5f547 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -68,5 +68,5 @@ sphinxcontrib-qthelp==1.0.3 # via sphinx sphinxcontrib-serializinghtml==1.1.5 # via sphinx -urllib3==1.26.10 +urllib3==1.26.11 # via requests diff --git a/requirements/tests.txt b/requirements/tests.txt index 7a3f89d7..d9b7513c 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -7,9 +7,9 @@ # asgiref==3.5.2 # via -r requirements/tests.in -attrs==21.4.0 +attrs==22.1.0 # via pytest -blinker==1.4 +blinker==1.5 # via -r requirements/tests.in greenlet==1.1.2 ; python_version < "3.11" # via -r requirements/tests.in diff --git a/requirements/typing.txt b/requirements/typing.txt index 38ac50c2..a842e1cd 100644 --- a/requirements/typing.txt +++ b/requirements/typing.txt @@ -9,7 +9,7 @@ cffi==1.15.1 # via cryptography cryptography==37.0.4 # via -r requirements/typing.in -mypy==0.961 +mypy==0.971 # via -r requirements/typing.in mypy-extensions==0.4.3 # via mypy @@ -21,7 +21,7 @@ types-contextvars==2.4.7 # via -r requirements/typing.in types-dataclasses==0.6.6 # via -r requirements/typing.in -types-setuptools==62.6.1 +types-setuptools==63.2.3 # via -r requirements/typing.in typing-extensions==4.3.0 # via mypy From 52c54b2ce1e392c5d5cd9339a4a069e91edd1d01 Mon Sep 17 00:00:00 2001 From: David Lord Date: Wed, 3 Aug 2022 16:40:28 -0700 Subject: [PATCH 4/4] release version 2.2.1 --- CHANGES.rst | 2 +- src/flask/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 2cd3144b..70adbca9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,7 +1,7 @@ Version 2.2.1 ------------- -Unreleased +Released 2022-08-03 - Setting or accessing ``json_encoder`` or ``json_decoder`` raises a deprecation warning. :issue:`4732` diff --git a/src/flask/__init__.py b/src/flask/__init__.py index 6a993341..6acd1e0b 100644 --- a/src/flask/__init__.py +++ b/src/flask/__init__.py @@ -42,7 +42,7 @@ from .templating import render_template_string as render_template_string from .templating import stream_template as stream_template from .templating import stream_template_string as stream_template_string -__version__ = "2.2.1.dev" +__version__ = "2.2.1" def __getattr__(name):