flask / flask /

# -*- coding: utf-8 -*-

    Implementation helpers for the JSON support in Flask.

    :copyright: (c) 2012 by Armin Ronacher.
    :license: BSD, see LICENSE for more details.
from datetime import datetime
from .globals import current_app, request

from werkzeug.http import http_date

# Use the same json implementation as itsdangerous on which we
# depend anyways.
from itsdangerous import simplejson as _json

# figure out if simplejson escapes slashes.  This behavior was changed
# from one version to another without reason.
_slash_escape = '\\/' not in _json.dumps('/')

__all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump',
           'htmlsafe_dumps', 'JSONDecoder', 'JSONEncoder',

class JSONEncoder(_json.JSONEncoder):
    """The default Flask JSON encoder.  This one extends the default simplejson
    encoder by also supporting ``datetime`` objects as well as ``Markup``
    objects which are serialized as RFC 822 datetime strings (same as the HTTP
    date format).  In order to support more data types override the
    :meth:`default` method.

    def default(self, o):
        """Implement this method in a subclass such that it returns a
        serializable object for ``o``, or calls the base implementation (to
        raise a ``TypeError``).

        For example, to support arbitrary iterators, you could implement
        default like this::

            def default(self, o):
                    iterable = iter(o)
                except TypeError:
                    return list(iterable)
                return JSONEncoder.default(self, o)
        if isinstance(o, datetime):
            return http_date(o)
        if hasattr(o, '__html__'):
            return unicode(o.__html__())
        return _json.JSONEncoder.default(self, o)

class JSONDecoder(_json.JSONDecoder):
    """The default JSON decoder.  This one does not change the behavior from
    the default simplejson encoder.  Consult the :mod:`json` documentation
    for more information.  This decoder is not only used for the load
    functions of this module but also :attr:`~flask.Request`.

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.
    return _json.dumps(obj, **kwargs)

def dump(obj, fp, **kwargs):
    """Like :func:`dumps` but writes into a file object."""
    return _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.
    return _json.loads(s, **kwargs)

def load(fp, **kwargs):
    """Like :func:`loads` but reads from a file object.
    return _json.load(fp, **kwargs)

def htmlsafe_dumps(obj, **kwargs):
    """Works exactly like :func:`dumps` but is safe for use in ``<script>``
    tags.  It accepts the same arguments and returns a JSON string.  Note that
    this is available in templates through the ``|tojson`` filter but it will
    have to be wrapped in ``|safe`` unless **true** XHTML is being used.
    rv = dumps(obj, **kwargs)
    if _slash_escape:
        rv = rv.replace('/', '\\/')
    return rv.replace('<!', '<\\u0021')

def htmlsafe_dump(obj, fp, **kwargs):
    """Like :func:`htmlsafe_dumps` but writes into a file object."""
    fp.write(htmlsafe_dumps(obj, **kwargs))

def jsonify(*args, **kwargs):
    """Creates a :class:`~flask.Response` with the JSON representation of
    the given arguments with an `application/json` mimetype.  The arguments
    to this function are the same as to the :class:`dict` constructor.

    Example usage::

        def get_current_user():
            return jsonify(username=g.user.username,

    This will send a JSON response like this to the browser::

            "username": "admin",
            "email": "admin@localhost",
            "id": 42

    This requires Python 2.6 or an installed version of simplejson.  For
    security reasons only objects are supported toplevel.  For more
    information about this, have a look at :ref:`json-security`.

    .. versionadded:: 0.2
    return current_app.response_class(dumps(dict(*args, **kwargs),
        indent=None if request.is_xhr else 2),