diff --git a/CHANGES b/CHANGES index fd9d110c..6a1ee7c7 100644 --- a/CHANGES +++ b/CHANGES @@ -30,6 +30,10 @@ Release date to be decided. - The config object is now available to the template as a real global and not through a context processor which makes it available even in imported templates by default. +- Added an option to generate non-ascii encoded JSON which should result + in less bytes being transmitted over the network. It's disabled by + default to not cause confusion with existing libraries that might expect + ``flask.json.dumps`` to return bytestrings by default. Version 0.9 ----------- diff --git a/docs/config.rst b/docs/config.rst index 7a32fb84..134fe36d 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -142,6 +142,13 @@ The following configuration values are used internally by Flask: ``PREFERRED_URL_SCHEME`` The URL scheme that should be used for URL generation if no URL scheme is available. This defaults to ``http``. +``JSON_AS_ASCII`` By default Flask serialize object to + ascii-encoded JSON. If this is set to + ``False`` Flask will not encode to ASCII + and output strings as-is and return + unicode strings. ``jsonfiy`` will + automatically encode it in ``utf-8`` + then for transport for instance. ================================= ========================================= .. admonition:: More on ``SERVER_NAME`` @@ -184,6 +191,9 @@ The following configuration values are used internally by Flask: .. versionadded:: 0.9 ``PREFERRED_URL_SCHEME`` +.. versionadded:: 0.10 + ``JSON_AS_ASCII`` + Configuring from Files ---------------------- diff --git a/flask/app.py b/flask/app.py index 87ba933e..9d291b3a 100644 --- a/flask/app.py +++ b/flask/app.py @@ -274,7 +274,8 @@ class Flask(_PackageBoundObject): 'SEND_FILE_MAX_AGE_DEFAULT': 12 * 60 * 60, # 12 hours 'TRAP_BAD_REQUEST_ERRORS': False, 'TRAP_HTTP_EXCEPTIONS': False, - 'PREFERRED_URL_SCHEME': 'http' + 'PREFERRED_URL_SCHEME': 'http', + 'JSON_AS_ASCII': True }) #: The rule object to use for URL rules created. This is used by diff --git a/flask/json.py b/flask/json.py index 1593a326..a85bdc63 100644 --- a/flask/json.py +++ b/flask/json.py @@ -68,20 +68,37 @@ 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) + if not current_app.config['JSON_AS_ASCII']: + kwargs.setdefault('ensure_ascii', False) + + +def _load_arg_defaults(kwargs): + """Inject default arguments for load functions.""" + if current_app: + kwargs.setdefault('cls', current_app.json_decoder) + + 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. + + 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 overriden by the simplejson ``ensure_ascii`` parameter. """ - if current_app: - kwargs.setdefault('cls', current_app.json_encoder) + _dump_arg_defaults(kwargs) return _json.dumps(obj, **kwargs) def dump(obj, fp, **kwargs): """Like :func:`dumps` but writes into a file object.""" - if current_app: - kwargs.setdefault('cls', current_app.json_encoder) + _dump_arg_defaults(kwargs) return _json.dump(obj, fp, **kwargs) @@ -90,16 +107,14 @@ def loads(s, **kwargs): configured decoder (:attr:`~flask.Flask.json_decoder`) if there is an application on the stack. """ - if current_app: - kwargs.setdefault('cls', current_app.json_decoder) + _load_arg_defaults(kwargs) return _json.loads(s, **kwargs) def load(fp, **kwargs): """Like :func:`loads` but reads from a file object. """ - if current_app: - kwargs.setdefault('cls', current_app.json_decoder) + _load_arg_defaults(kwargs) return _json.load(fp, **kwargs) diff --git a/flask/testsuite/helpers.py b/flask/testsuite/helpers.py index ee5312e0..31f0dcb4 100644 --- a/flask/testsuite/helpers.py +++ b/flask/testsuite/helpers.py @@ -79,6 +79,19 @@ class JSONTestCase(FlaskTestCase): self.assert_equal(rv.mimetype, 'application/json') self.assert_equal(flask.json.loads(rv.data), d) + def test_json_as_unicode(self): + app = flask.Flask(__name__) + + app.config['JSON_AS_ASCII'] = True + with app.app_context(): + rv = flask.json.dumps(u'\N{SNOWMAN}') + self.assert_equal(rv, '"\\u2603"') + + app.config['JSON_AS_ASCII'] = False + with app.app_context(): + rv = flask.json.dumps(u'\N{SNOWMAN}') + self.assert_equal(rv, u'"\u2603"') + def test_json_attr(self): app = flask.Flask(__name__) @app.route('/add', methods=['POST'])