From ac78da0bb02fc5c07c896a77d3fc2b32e7924407 Mon Sep 17 00:00:00 2001 From: "Michael E. Karpeles" Date: Fri, 26 Apr 2019 17:16:50 -0700 Subject: [PATCH 1/5] removed unused reference to url_join --- flask/blueprints.py | 1 - 1 file changed, 1 deletion(-) diff --git a/flask/blueprints.py b/flask/blueprints.py index 5ce5561e..c2158fe3 100644 --- a/flask/blueprints.py +++ b/flask/blueprints.py @@ -10,7 +10,6 @@ :license: BSD, see LICENSE for more details. """ from functools import update_wrapper -from werkzeug.urls import url_join from .helpers import _PackageBoundObject, _endpoint_from_view_func From 6142aa64ae4d0957d735b6b86c5abe15fea06504 Mon Sep 17 00:00:00 2001 From: brunoais Date: Sun, 14 Apr 2019 15:48:02 +0100 Subject: [PATCH 2/5] More explicit explanation: session testing Use a more explicit explanation on how to write code to test own code when sessions are needed. The previous code was not fully explicit that the client is supposed to be called after the session transaction and not during. --- docs/testing.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/testing.rst b/docs/testing.rst index 82e10328..bc9c0ea1 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -354,14 +354,15 @@ This however does not make it possible to also modify the session or to access the session before a request was fired. Starting with Flask 0.8 we provide a so called “session transaction” which simulates the appropriate calls to open a session in the context of the test client and to modify -it. At the end of the transaction the session is stored. This works -independently of the session backend used:: +it. At the end of the transaction the session is stored and ready to be +used by the test client. This works independently of the session backend used:: with app.test_client() as c: with c.session_transaction() as sess: sess['a_key'] = 'a value' - # once this is reached the session was stored + # once this is reached the session was stored and ready to be used by the client + c.get(...) Note that in this case you have to use the ``sess`` object instead of the :data:`flask.session` proxy. The object however itself will provide the From e2f4b53396f4676978f86492dae5d3952446df89 Mon Sep 17 00:00:00 2001 From: DamianSkrzypczak Date: Fri, 3 May 2019 20:59:22 +0200 Subject: [PATCH 3/5] Fix dev-server warning message readability (#3168) --- flask/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flask/cli.py b/flask/cli.py index d06cfee2..3eb93b3f 100644 --- a/flask/cli.py +++ b/flask/cli.py @@ -644,8 +644,8 @@ def show_server_banner(env, debug, app_import_path, eager_loading): if env == 'production': click.secho( - ' WARNING: Do not use the development server in a production' - ' environment.', fg='red') + ' WARNING: This is a development server. ' + 'Do not use it in a production deployment.', fg='red') click.secho(' Use a production WSGI server instead.', dim=True) if debug is not None: From a4f0f197962b27a002c45f5e27b13a8d4a27ee63 Mon Sep 17 00:00:00 2001 From: David Lord Date: Fri, 17 May 2019 08:39:16 -0700 Subject: [PATCH 4/5] don't push app context for test client json --- CHANGES.rst | 3 ++ flask/json/__init__.py | 94 ++++++++++++++++++++++++++++-------------- flask/testing.py | 10 ++--- tests/test_testing.py | 27 ++++++++++++ 4 files changed, 95 insertions(+), 39 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index bdf0c896..ddfead62 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -23,10 +23,13 @@ Unreleased handle ``RoutingExcpetion``, which is used internally during routing. This fixes the unexpected behavior that had been introduced in 1.0. (`#2986`_) +- Passing the ``json`` argument to ``app.test_client`` does not + push/pop an extra app context. (`#2900`_) .. _#2766: https://github.com/pallets/flask/issues/2766 .. _#2765: https://github.com/pallets/flask/pull/2765 .. _#2825: https://github.com/pallets/flask/pull/2825 +.. _#2900: https://github.com/pallets/flask/issues/2900 .. _#2933: https://github.com/pallets/flask/issues/2933 .. _#2986: https://github.com/pallets/flask/pull/2986 diff --git a/flask/json/__init__.py b/flask/json/__init__.py index fbe6b92f..c24286c9 100644 --- a/flask/json/__init__.py +++ b/flask/json/__init__.py @@ -89,33 +89,37 @@ class JSONDecoder(_json.JSONDecoder): """ -def _dump_arg_defaults(kwargs): +def _dump_arg_defaults(kwargs, app=None): """Inject default arguments for dump functions.""" - if current_app: - bp = current_app.blueprints.get(request.blueprint) if request else None + if app is None: + app = current_app + + if app: + bp = app.blueprints.get(request.blueprint) if request else None kwargs.setdefault( - 'cls', - bp.json_encoder if bp and bp.json_encoder - else current_app.json_encoder + 'cls', bp.json_encoder if bp and bp.json_encoder else app.json_encoder ) - if not current_app.config['JSON_AS_ASCII']: + if not app.config['JSON_AS_ASCII']: kwargs.setdefault('ensure_ascii', False) - kwargs.setdefault('sort_keys', current_app.config['JSON_SORT_KEYS']) + kwargs.setdefault('sort_keys', app.config['JSON_SORT_KEYS']) else: kwargs.setdefault('sort_keys', True) kwargs.setdefault('cls', JSONEncoder) -def _load_arg_defaults(kwargs): +def _load_arg_defaults(kwargs, app=None): """Inject default arguments for load functions.""" - if current_app: - bp = current_app.blueprints.get(request.blueprint) if request else None + if app is None: + app = current_app + + if app: + bp = app.blueprints.get(request.blueprint) if request else None kwargs.setdefault( 'cls', bp.json_decoder if bp and bp.json_decoder - else current_app.json_decoder + else app.json_decoder ) else: kwargs.setdefault('cls', JSONDecoder) @@ -164,17 +168,28 @@ def detect_encoding(data): return 'utf-8' -def dumps(obj, **kwargs): - """Serialize ``obj`` to a JSON formatted ``str`` by using the application's - configured encoder (:attr:`~flask.Flask.json_encoder`) if there is an - application on the stack. +def dumps(obj, app=None, **kwargs): + """Serialize ``obj`` to a JSON-formatted string. If there is an + app context pushed, use the current app's configured encoder + (:attr:`~flask.Flask.json_encoder`), or fall back to the default + :class:`JSONEncoder`. - This function can return ``unicode`` strings or ascii-only bytestrings by - default which coerce into unicode strings automatically. That behavior by - default is controlled by the ``JSON_AS_ASCII`` configuration variable - and can be overridden by the simplejson ``ensure_ascii`` parameter. + Takes the same arguments as the built-in :func:`json.dumps`, and + does some extra configuration based on the application. If the + simplejson package is installed, it is preferred. + + :param obj: Object to serialize to JSON. + :param app: App instance to use to configure the JSON encoder. + Uses ``current_app`` if not given, and falls back to the default + encoder when not in an app context. + :param kwargs: Extra arguments passed to :func:`json.dumps`. + + .. versionchanged:: 1.0.3 + + ``app`` can be passed directly, rather than requiring an app + context for configuration. """ - _dump_arg_defaults(kwargs) + _dump_arg_defaults(kwargs, app=app) encoding = kwargs.pop('encoding', None) rv = _json.dumps(obj, **kwargs) if encoding is not None and isinstance(rv, text_type): @@ -182,21 +197,37 @@ def dumps(obj, **kwargs): return rv -def dump(obj, fp, **kwargs): +def dump(obj, fp, app=None, **kwargs): """Like :func:`dumps` but writes into a file object.""" - _dump_arg_defaults(kwargs) + _dump_arg_defaults(kwargs, app=app) encoding = kwargs.pop('encoding', None) if encoding is not None: fp = _wrap_writer_for_text(fp, encoding) _json.dump(obj, fp, **kwargs) -def loads(s, **kwargs): - """Unserialize a JSON object from a string ``s`` by using the application's - configured decoder (:attr:`~flask.Flask.json_decoder`) if there is an - application on the stack. +def loads(s, app=None, **kwargs): + """Deserialize an object from a JSON-formatted string ``s``. If + there is an app context pushed, use the current app's configured + decoder (:attr:`~flask.Flask.json_decoder`), or fall back to the + default :class:`JSONDecoder`. + + Takes the same arguments as the built-in :func:`json.loads`, and + does some extra configuration based on the application. If the + simplejson package is installed, it is preferred. + + :param s: JSON string to deserialize. + :param app: App instance to use to configure the JSON decoder. + Uses ``current_app`` if not given, and falls back to the default + encoder when not in an app context. + :param kwargs: Extra arguments passed to :func:`json.dumps`. + + .. versionchanged:: 1.0.3 + + ``app`` can be passed directly, rather than requiring an app + context for configuration. """ - _load_arg_defaults(kwargs) + _load_arg_defaults(kwargs, app=app) if isinstance(s, bytes): encoding = kwargs.pop('encoding', None) if encoding is None: @@ -205,10 +236,9 @@ def loads(s, **kwargs): return _json.loads(s, **kwargs) -def load(fp, **kwargs): - """Like :func:`loads` but reads from a file object. - """ - _load_arg_defaults(kwargs) +def load(fp, app=None, **kwargs): + """Like :func:`loads` but reads from a file object.""" + _load_arg_defaults(kwargs, app=app) if not PY2: fp = _wrap_reader_for_text(fp, kwargs.pop('encoding', None) or 'utf-8') return _json.load(fp, **kwargs) diff --git a/flask/testing.py b/flask/testing.py index 4bf0ebc1..114c5cc3 100644 --- a/flask/testing.py +++ b/flask/testing.py @@ -73,14 +73,10 @@ def make_test_environ_builder( sep = b'?' if isinstance(url.query, bytes) else '?' path += sep + url.query + # TODO use EnvironBuilder.json_dumps once we require Werkzeug 0.15 if 'json' in kwargs: - assert 'data' not in kwargs, ( - "Client cannot provide both 'json' and 'data'." - ) - - # push a context so flask.json can use app's json attributes - with app.app_context(): - kwargs['data'] = json_dumps(kwargs.pop('json')) + assert 'data' not in kwargs, "Client cannot provide both 'json' and 'data'." + kwargs['data'] = json_dumps(kwargs.pop('json'), app=app) if 'content_type' not in kwargs: kwargs['content_type'] = 'application/json' diff --git a/tests/test_testing.py b/tests/test_testing.py index 14c66324..8c41d1fc 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -14,11 +14,17 @@ import pytest import flask import werkzeug +from flask import appcontext_popped from flask._compat import text_type from flask.cli import ScriptInfo from flask.json import jsonify from flask.testing import make_test_environ_builder, FlaskCliRunner +try: + import blinker +except ImportError: + blinker = None + def test_environ_defaults_from_config(app, client): app.config['SERVER_NAME'] = 'example.com:1234' @@ -306,6 +312,27 @@ def test_json_request_and_response(app, client): assert rv.get_json() == json_data +@pytest.mark.skipif(blinker is None, reason="blinker is not installed") +def test_client_json_no_app_context(app, client): + @app.route("/hello", methods=["POST"]) + def hello(): + return "Hello, {}!".format(flask.request.json["name"]) + + class Namespace(object): + count = 0 + + def add(self, app): + self.count += 1 + + ns = Namespace() + + with appcontext_popped.connected_to(ns.add, app): + rv = client.post("/hello", json={"name": "Flask"}) + + assert rv.get_data(as_text=True) == "Hello, Flask!" + assert ns.count == 1 + + def test_subdomain(): app = flask.Flask(__name__, subdomain_matching=True) app.config['SERVER_NAME'] = 'example.com' From 99660cc40984015cbbcd27d1cdc19376b2536443 Mon Sep 17 00:00:00 2001 From: David Lord Date: Fri, 17 May 2019 10:57:51 -0700 Subject: [PATCH 5/5] release version 1.0.3 --- CHANGES.rst | 8 ++++---- flask/__init__.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index ddfead62..5a076f89 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,7 +7,7 @@ Flask Changelog Version 1.0.3 ------------- -Unreleased +Released 2019-05-17 - :func:`send_file` encodes filenames as ASCII instead of Latin-1 (ISO-8859-1). This fixes compatibility with Gunicorn, which is @@ -37,7 +37,7 @@ Unreleased Version 1.0.2 ------------- -Released on May 2nd 2018 +Released 2018-05-02 - Fix more backwards compatibility issues with merging slashes between a blueprint prefix and route. (`#2748`_) @@ -51,7 +51,7 @@ Released on May 2nd 2018 Version 1.0.1 ------------- -Released on April 29th 2018 +Released 2018-04-29 - Fix registering partials (with no ``__name__``) as view functions. (`#2730`_) @@ -77,7 +77,7 @@ Released on April 29th 2018 Version 1.0 ----------- -Released on April 26th 2018 +Released 2018-04-26 - **Python 2.6 and 3.3 are no longer supported.** (`pallets/meta#24`_) - Bump minimum dependency versions to the latest stable versions: diff --git a/flask/__init__.py b/flask/__init__.py index 6e475ed1..59f0fff5 100644 --- a/flask/__init__.py +++ b/flask/__init__.py @@ -10,7 +10,7 @@ :license: BSD, see LICENSE for more details. """ -__version__ = '1.0.3.dev' +__version__ = '1.0.3' # utilities we import from Werkzeug and Jinja2 that are unused # in the module but are exported as public interface.