2173
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
1 import datetime
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
2 import functools
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
3 import decimal
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
4
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
5 __all__ = ['json', 'simplejson', 'stdjson']
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
6
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
7
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
8 def _is_aware(value):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
9 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
10 Determines if a given datetime.time is aware.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
11
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
12 The logic is described in Python's docs:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
13 http://docs.python.org/library/datetime.html#datetime.tzinfo
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
14 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
15 return (value.tzinfo is not None
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
16 and value.tzinfo.utcoffset(value) is not None)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
17
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
18
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
19 def _obj_dump(obj):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
20 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
21 Custom function for dumping objects to JSON, if obj has __json__ attribute
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
22 or method defined it will be used for serialization
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
23
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
24 :param obj:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
25 """
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
26
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
27 if isinstance(obj, complex):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
28 return [obj.real, obj.imag]
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
29 # See "Date Time String Format" in the ECMA-262 specification.
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
30 # some code borrowed from django 1.4
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
31 elif isinstance(obj, datetime.datetime):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
32 r = obj.isoformat()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
33 if obj.microsecond:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
34 r = r[:23] + r[26:]
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
35 if r.endswith('+00:00'):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
36 r = r[:-6] + 'Z'
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
37 return r
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
38 elif isinstance(obj, datetime.date):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
39 return obj.isoformat()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
40 elif isinstance(obj, decimal.Decimal):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
41 return str(obj)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
42 elif isinstance(obj, datetime.time):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
43 if _is_aware(obj):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
44 raise ValueError("JSON can't represent timezone-aware times.")
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
45 r = obj.isoformat()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
46 if obj.microsecond:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
47 r = r[:12]
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
48 return r
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
49 elif isinstance(obj, set):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
50 return list(obj)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
51 elif hasattr(obj, '__json__'):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
52 if callable(obj.__json__):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
53 return obj.__json__()
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
54 else:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
55 return obj.__json__
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
56 else:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
57 raise NotImplementedError
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
58
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
59
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
60 # Import simplejson
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
61 try:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
62 # import simplejson initially
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
63 import simplejson as _sj
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
64
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
65 def extended_encode(obj):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
66 try:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
67 return _obj_dump(obj)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
68 except NotImplementedError:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
69 pass
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
70 raise TypeError("%r is not JSON serializable" % (obj,))
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
71 # we handle decimals our own it makes unified behavior of json vs
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
72 # simplejson
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
73 _sj.dumps = functools.partial(_sj.dumps, default=extended_encode,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
74 use_decimal=False)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
75 _sj.dump = functools.partial(_sj.dump, default=extended_encode,
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
76 use_decimal=False)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
77 simplejson = _sj
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
78
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
79 except ImportError:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
80 # no simplejson set it to None
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
81 _sj = None
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
82
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
83
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
84 # simplejson not found try out regular json module
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
85 import json as _json
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
86
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
87
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
88 # extended JSON encoder for json
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
89 class ExtendedEncoder(_json.JSONEncoder):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
90 def default(self, obj):
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
91 try:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
92 return _obj_dump(obj)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
93 except NotImplementedError:
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
94 pass
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
95 return _json.JSONEncoder.default(self, obj)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
96 # monkey-patch JSON encoder to use extended version
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
97 _json.dumps = functools.partial(_json.dumps, cls=ExtendedEncoder)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
98 _json.dump = functools.partial(_json.dump, cls=ExtendedEncoder)
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
99 stdlib = _json
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
100
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
101 # set all available json modules
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
102 simplejson = _sj
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
103 stdjson = _json
|
Marcin Kuzminski <marcin@python-works.com>
parents:
diff
changeset
|
104 json = _sj if _sj else _json
|