Skip to content

Commit

Permalink
Merge pull request #1898 from RaHus/per_blueprint_jsoncoding_#1710
Browse files Browse the repository at this point in the history
Per blueprint jsoncoding #1710
  • Loading branch information
davidism authored Apr 24, 2017
2 parents 8d515a6 + 4305ebd commit 74b3f7e
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
7 changes: 7 additions & 0 deletions flask/blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ class Blueprint(_PackageBoundObject):
warn_on_modifications = False
_got_registered_once = False

#: Blueprint local JSON decoder class to use.
# Set to None to use the :class:`~flask.app.Flask.json_encoder`.
json_encoder = None
#: Blueprint local JSON decoder class to use.
# Set to None to use the :class:`~flask.app.Flask.json_decoder`.
json_decoder = None

def __init__(self, name, import_name, static_folder=None,
static_url_path=None, template_folder=None,
url_prefix=None, subdomain=None, url_defaults=None,
Expand Down
13 changes: 11 additions & 2 deletions flask/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from datetime import date
from .globals import current_app, request
from ._compat import text_type, PY2
from .ctx import has_request_context

from werkzeug.http import http_date
from jinja2 import Markup
Expand Down Expand Up @@ -91,7 +92,11 @@ class JSONDecoder(_json.JSONDecoder):
def _dump_arg_defaults(kwargs):
"""Inject default arguments for dump functions."""
if current_app:
kwargs.setdefault('cls', current_app.json_encoder)
bp = current_app.blueprints.get(request.blueprint,
None) if has_request_context() else None
kwargs.setdefault('cls',
bp.json_encoder if bp and bp.json_encoder
else current_app.json_encoder)
if not current_app.config['JSON_AS_ASCII']:
kwargs.setdefault('ensure_ascii', False)
kwargs.setdefault('sort_keys', current_app.config['JSON_SORT_KEYS'])
Expand All @@ -103,7 +108,11 @@ def _dump_arg_defaults(kwargs):
def _load_arg_defaults(kwargs):
"""Inject default arguments for load functions."""
if current_app:
kwargs.setdefault('cls', current_app.json_decoder)
bp = current_app.blueprints.get(request.blueprint,
None) if has_request_context() else None
kwargs.setdefault('cls',
bp.json_decoder if bp and bp.json_decoder
else current_app.json_decoder)
else:
kwargs.setdefault('cls', JSONDecoder)

Expand Down
35 changes: 35 additions & 0 deletions tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,41 @@ def index():
}), content_type='application/json')
assert rv.data == b'"<42>"'

def test_blueprint_json_customization(self):
class X(object):
def __init__(self, val):
self.val = val
class MyEncoder(flask.json.JSONEncoder):
def default(self, o):
if isinstance(o, X):
return '<%d>' % o.val
return flask.json.JSONEncoder.default(self, o)
class MyDecoder(flask.json.JSONDecoder):
def __init__(self, *args, **kwargs):
kwargs.setdefault('object_hook', self.object_hook)
flask.json.JSONDecoder.__init__(self, *args, **kwargs)
def object_hook(self, obj):
if len(obj) == 1 and '_foo' in obj:
return X(obj['_foo'])
return obj

blue = flask.Blueprint('blue', __name__)
blue.json_encoder = MyEncoder
blue.json_decoder = MyDecoder
@blue.route('/bp', methods=['POST'])
def index():
return flask.json.dumps(flask.request.get_json()['x'])

app = flask.Flask(__name__)
app.testing = True
app.register_blueprint(blue)

c = app.test_client()
rv = c.post('/bp', data=flask.json.dumps({
'x': {'_foo': 42}
}), content_type='application/json')
assert rv.data == b'"<42>"'

def test_modified_url_encoding(self):
class ModifiedRequest(flask.Request):
url_charset = 'euc-kr'
Expand Down

0 comments on commit 74b3f7e

Please sign in to comment.