1 | # -*- coding: utf-8 -*- |
---|
2 | # |
---|
3 | # Copyright (C)2006-2009 Edgewall Software |
---|
4 | # Copyright (C) 2006 Christopher Lenz <cmlenz@gmx.de> |
---|
5 | # All rights reserved. |
---|
6 | # |
---|
7 | # This software is licensed as described in the file COPYING, which |
---|
8 | # you should have received as part of this distribution. The terms |
---|
9 | # are also available at http://trac.edgewall.org/wiki/TracLicense. |
---|
10 | # |
---|
11 | # This software consists of voluntary contributions made by many |
---|
12 | # individuals. For the exact contribution history, see the revision |
---|
13 | # history and logs, available at http://trac.edgewall.org/log/. |
---|
14 | |
---|
15 | """Utility functions for converting to web formats""" |
---|
16 | |
---|
17 | # to_json is really a wrapper for trac.util.presentation.to_json, but we have lots of fallbacks for compatibility |
---|
18 | # trac.util.presentation.to_json is present from Trac 0.12 |
---|
19 | # If that's not present, we fall back to the default Python json module, present from Python 2.6 onwards |
---|
20 | # If that's not present, we have a copy of the to_json method, which we will remove once Trac 0.11 support is removed |
---|
21 | # And finally, the to_json method requires trac.util.text.javascript_quote, which is only present from Trac 0.11.3, so we have a copy of that too |
---|
22 | |
---|
23 | import re |
---|
24 | |
---|
25 | try: |
---|
26 | # to_json is present from Trac 0.12 onwards - should remove once Trac 0.11 support is removed |
---|
27 | from trac.util.presentation import to_json |
---|
28 | except ImportError: |
---|
29 | try: |
---|
30 | # If we have Python 2.6 onwards, use the json method directly |
---|
31 | from json import dumps |
---|
32 | |
---|
33 | def to_json(value): |
---|
34 | """Encode `value` to JSON.""" |
---|
35 | return dumps(value, sort_keys=True, separators=(',', ':')) |
---|
36 | except ImportError: |
---|
37 | # javascript_quote is present from Trac 0.11.3 onwards - should remove once Trac 0.11.2 support is removed |
---|
38 | try: |
---|
39 | from trac.util.text import javascript_quote |
---|
40 | except ImportError: |
---|
41 | _js_quote = {'\\': '\\\\', '"': '\\"', '\b': '\\b', '\f': '\\f', |
---|
42 | '\n': '\\n', '\r': '\\r', '\t': '\\t', "'": "\\'"} |
---|
43 | for i in range(0x20): |
---|
44 | _js_quote.setdefault(chr(i), '\\u%04x' % i) |
---|
45 | _js_quote_re = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t\']') |
---|
46 | def javascript_quote(text): |
---|
47 | """Quote strings for inclusion in javascript""" |
---|
48 | if not text: |
---|
49 | return '' |
---|
50 | def replace(match): |
---|
51 | return _js_quote[match.group(0)] |
---|
52 | return _js_quote_re.sub(replace, text) |
---|
53 | |
---|
54 | def to_json(value): |
---|
55 | """Encode `value` to JSON.""" |
---|
56 | if isinstance(value, basestring): |
---|
57 | return '"%s"' % javascript_quote(value) |
---|
58 | elif value is None: |
---|
59 | return 'null' |
---|
60 | elif value is False: |
---|
61 | return 'false' |
---|
62 | elif value is True: |
---|
63 | return 'true' |
---|
64 | elif isinstance(value, (int, long)): |
---|
65 | return str(value) |
---|
66 | elif isinstance(value, float): |
---|
67 | return repr(value) |
---|
68 | elif isinstance(value, (list, tuple)): |
---|
69 | return '[%s]' % ','.join(to_json(each) for each in value) |
---|
70 | elif isinstance(value, dict): |
---|
71 | return '{%s}' % ','.join('%s:%s' % (to_json(k), to_json(v)) |
---|
72 | for k, v in sorted(value.iteritems())) |
---|
73 | else: |
---|
74 | raise TypeError('Cannot encode type %s' % value.__class__.__name__) |
---|