Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 153 lines (117 sloc) 5.039 kB
b146d82 @mitsuhiko Added wrapper module around simplejson/json for much simplified custo…
authored
1 # -*- coding: utf-8 -*-
2 """
3 flask.jsonimpl
4 ~~~~~~~~~~~~~~
5
6 Implementation helpers for the JSON support in Flask.
7
8 :copyright: (c) 2012 by Armin Ronacher.
9 :license: BSD, see LICENSE for more details.
10 """
11 from datetime import datetime
12 from .globals import current_app, request
13
14 from werkzeug.http import http_date
15
16 # Use the same json implementation as itsdangerous on which we
17 # depend anyways.
18 from itsdangerous import simplejson as _json
19
20
21 # figure out if simplejson escapes slashes. This behavior was changed
22 # from one version to another without reason.
23 _slash_escape = '\\/' not in _json.dumps('/')
24
25
26 __all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump',
27 'htmlsafe_dumps', 'JSONDecoder', 'JSONEncoder',
28 'jsonify']
29
30
31 class JSONEncoder(_json.JSONEncoder):
32 """The default Flask JSON encoder. This one extends the default simplejson
33 encoder by also supporting ``datetime`` objects as well as ``Markup``
34 objects which are serialized as RFC 822 datetime strings (same as the HTTP
35 date format). In order to support more data types override the
36 :meth:`default` method.
37 """
38
39 def default(self, o):
40 """Implement this method in a subclass such that it returns a
41 serializable object for ``o``, or calls the base implementation (to
42 raise a ``TypeError``).
43
44 For example, to support arbitrary iterators, you could implement
45 default like this::
46
47 def default(self, o):
48 try:
49 iterable = iter(o)
50 except TypeError:
51 pass
52 else:
53 return list(iterable)
54 return JSONEncoder.default(self, o)
55 """
56 if isinstance(o, datetime):
57 return http_date(o)
58 if hasattr(o, '__html__'):
59 return unicode(o.__html__())
60 return _json.JSONEncoder.default(self, o)
61
62
63 class JSONDecoder(_json.JSONDecoder):
64 """The default JSON decoder. This one does not change the behavior from
65 the default simplejson encoder. Consult the :mod:`json` documentation
66 for more information. This decoder is not only used for the load
67 functions of this module but also :attr:`~flask.Request`.
68 """
69
70
71 def dumps(obj, **kwargs):
72 """Serialize ``obj`` to a JSON formatted ``str`` by using the application's
05c6502 @mitsuhiko Let json.* work even without app on the stack and added tests
authored
73 configured encoder (:attr:`~flask.Flask.json_encoder`) if there is an
74 application on the stack.
b146d82 @mitsuhiko Added wrapper module around simplejson/json for much simplified custo…
authored
75 """
05c6502 @mitsuhiko Let json.* work even without app on the stack and added tests
authored
76 if current_app:
77 kwargs.setdefault('cls', current_app.json_encoder)
b146d82 @mitsuhiko Added wrapper module around simplejson/json for much simplified custo…
authored
78 return _json.dumps(obj, **kwargs)
79
80
81 def dump(obj, fp, **kwargs):
82 """Like :func:`dumps` but writes into a file object."""
05c6502 @mitsuhiko Let json.* work even without app on the stack and added tests
authored
83 if current_app:
84 kwargs.setdefault('cls', current_app.json_encoder)
b146d82 @mitsuhiko Added wrapper module around simplejson/json for much simplified custo…
authored
85 return _json.dump(obj, fp, **kwargs)
86
87
88 def loads(s, **kwargs):
89 """Unserialize a JSON object from a string ``s`` by using the application's
05c6502 @mitsuhiko Let json.* work even without app on the stack and added tests
authored
90 configured decoder (:attr:`~flask.Flask.json_decoder`) if there is an
91 application on the stack.
b146d82 @mitsuhiko Added wrapper module around simplejson/json for much simplified custo…
authored
92 """
05c6502 @mitsuhiko Let json.* work even without app on the stack and added tests
authored
93 if current_app:
94 kwargs.setdefault('cls', current_app.json_decoder)
b146d82 @mitsuhiko Added wrapper module around simplejson/json for much simplified custo…
authored
95 return _json.loads(s, **kwargs)
96
97
98 def load(fp, **kwargs):
99 """Like :func:`loads` but reads from a file object.
100 """
05c6502 @mitsuhiko Let json.* work even without app on the stack and added tests
authored
101 if current_app:
102 kwargs.setdefault('cls', current_app.json_decoder)
b146d82 @mitsuhiko Added wrapper module around simplejson/json for much simplified custo…
authored
103 return _json.load(fp, **kwargs)
104
105
106 def htmlsafe_dumps(obj, **kwargs):
107 """Works exactly like :func:`dumps` but is safe for use in ``<script>``
108 tags. It accepts the same arguments and returns a JSON string. Note that
109 this is available in templates through the ``|tojson`` filter but it will
110 have to be wrapped in ``|safe`` unless **true** XHTML is being used.
111 """
112 rv = dumps(obj, **kwargs)
113 if _slash_escape:
114 rv = rv.replace('/', '\\/')
115 return rv.replace('<!', '<\\u0021')
116
117
118 def htmlsafe_dump(obj, fp, **kwargs):
119 """Like :func:`htmlsafe_dumps` but writes into a file object."""
120 fp.write(htmlsafe_dumps(obj, **kwargs))
121
122
123 def jsonify(*args, **kwargs):
124 """Creates a :class:`~flask.Response` with the JSON representation of
125 the given arguments with an `application/json` mimetype. The arguments
126 to this function are the same as to the :class:`dict` constructor.
127
128 Example usage::
129
130 @app.route('/_get_current_user')
131 def get_current_user():
132 return jsonify(username=g.user.username,
133 email=g.user.email,
134 id=g.user.id)
135
136 This will send a JSON response like this to the browser::
137
138 {
139 "username": "admin",
140 "email": "admin@localhost",
141 "id": 42
142 }
143
144 This requires Python 2.6 or an installed version of simplejson. For
145 security reasons only objects are supported toplevel. For more
146 information about this, have a look at :ref:`json-security`.
147
148 .. versionadded:: 0.2
149 """
150 return current_app.response_class(dumps(dict(*args, **kwargs),
151 indent=None if request.is_xhr else 2),
152 mimetype='application/json')
Something went wrong with that request. Please try again.