~ubuntu-branches/ubuntu/raring/glance/raring-updates

« back to all changes in this revision

Viewing changes to glance/openstack/common/jsonutils.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Adam Gandleman, Chuck Short
  • Date: 2012-08-16 13:58:32 UTC
  • mfrom: (1.1.41)
  • Revision ID: package-import@ubuntu.com-20120816135832-4m40ppptd1l073fr
Tags: 2012.2~f3-0ubuntu1
[ Adam Gandleman ]
* debian/patches/sql_conn.patch: Also set default sqlite path for
  in glance-api.conf. (LP: #1028711)
* debian/patches/fix-docs-build.patch: Fix docs build

[ Chuck Short ]
* New upstream version.
* debian/control: python-xattr is no longer a required depends.
  (LP: #1031396)
* debian/control: Move python-jsonschema to glance.
  (LP: #1030152)
* debian/control: Start the slow transition to python-glanceclient.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
 
 
3
# Copyright 2010 United States Government as represented by the
 
4
# Administrator of the National Aeronautics and Space Administration.
 
5
# Copyright 2011 Justin Santa Barbara
 
6
# All Rights Reserved.
 
7
#
 
8
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 
9
#    not use this file except in compliance with the License. You may obtain
 
10
#    a copy of the License at
 
11
#
 
12
#         http://www.apache.org/licenses/LICENSE-2.0
 
13
#
 
14
#    Unless required by applicable law or agreed to in writing, software
 
15
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
16
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
17
#    License for the specific language governing permissions and limitations
 
18
#    under the License.
 
19
 
 
20
'''
 
21
JSON related utilities.
 
22
 
 
23
This module provides a few things:
 
24
 
 
25
    1) A handy function for getting an object down to something that can be
 
26
    JSON serialized.  See to_primitive().
 
27
 
 
28
    2) Wrappers around loads() and dumps().  The dumps() wrapper will
 
29
    automatically use to_primitive() for you if needed.
 
30
 
 
31
    3) This sets up anyjson to use the loads() and dumps() wrappers if anyjson
 
32
    is available.
 
33
'''
 
34
 
 
35
 
 
36
import datetime
 
37
import inspect
 
38
import itertools
 
39
import json
 
40
import xmlrpclib
 
41
 
 
42
from glance.openstack.common import timeutils
 
43
 
 
44
 
 
45
def to_primitive(value, convert_instances=False, level=0):
 
46
    """Convert a complex object into primitives.
 
47
 
 
48
    Handy for JSON serialization. We can optionally handle instances,
 
49
    but since this is a recursive function, we could have cyclical
 
50
    data structures.
 
51
 
 
52
    To handle cyclical data structures we could track the actual objects
 
53
    visited in a set, but not all objects are hashable. Instead we just
 
54
    track the depth of the object inspections and don't go too deep.
 
55
 
 
56
    Therefore, convert_instances=True is lossy ... be aware.
 
57
 
 
58
    """
 
59
    nasty = [inspect.ismodule, inspect.isclass, inspect.ismethod,
 
60
             inspect.isfunction, inspect.isgeneratorfunction,
 
61
             inspect.isgenerator, inspect.istraceback, inspect.isframe,
 
62
             inspect.iscode, inspect.isbuiltin, inspect.isroutine,
 
63
             inspect.isabstract]
 
64
    for test in nasty:
 
65
        if test(value):
 
66
            return unicode(value)
 
67
 
 
68
    # value of itertools.count doesn't get caught by inspects
 
69
    # above and results in infinite loop when list(value) is called.
 
70
    if type(value) == itertools.count:
 
71
        return unicode(value)
 
72
 
 
73
    # FIXME(vish): Workaround for LP bug 852095. Without this workaround,
 
74
    #              tests that raise an exception in a mocked method that
 
75
    #              has a @wrap_exception with a notifier will fail. If
 
76
    #              we up the dependency to 0.5.4 (when it is released) we
 
77
    #              can remove this workaround.
 
78
    if getattr(value, '__module__', None) == 'mox':
 
79
        return 'mock'
 
80
 
 
81
    if level > 3:
 
82
        return '?'
 
83
 
 
84
    # The try block may not be necessary after the class check above,
 
85
    # but just in case ...
 
86
    try:
 
87
        # It's not clear why xmlrpclib created their own DateTime type, but
 
88
        # for our purposes, make it a datetime type which is explicitly
 
89
        # handled
 
90
        if isinstance(value, xmlrpclib.DateTime):
 
91
            value = datetime.datetime(*tuple(value.timetuple())[:6])
 
92
 
 
93
        if isinstance(value, (list, tuple)):
 
94
            o = []
 
95
            for v in value:
 
96
                o.append(to_primitive(v, convert_instances=convert_instances,
 
97
                                      level=level))
 
98
            return o
 
99
        elif isinstance(value, dict):
 
100
            o = {}
 
101
            for k, v in value.iteritems():
 
102
                o[k] = to_primitive(v, convert_instances=convert_instances,
 
103
                                    level=level)
 
104
            return o
 
105
        elif isinstance(value, datetime.datetime):
 
106
            return timeutils.strtime(value)
 
107
        elif hasattr(value, 'iteritems'):
 
108
            return to_primitive(dict(value.iteritems()),
 
109
                                convert_instances=convert_instances,
 
110
                                level=level + 1)
 
111
        elif hasattr(value, '__iter__'):
 
112
            return to_primitive(list(value),
 
113
                                convert_instances=convert_instances,
 
114
                                level=level)
 
115
        elif convert_instances and hasattr(value, '__dict__'):
 
116
            # Likely an instance of something. Watch for cycles.
 
117
            # Ignore class member vars.
 
118
            return to_primitive(value.__dict__,
 
119
                                convert_instances=convert_instances,
 
120
                                level=level + 1)
 
121
        else:
 
122
            return value
 
123
    except TypeError, e:
 
124
        # Class objects are tricky since they may define something like
 
125
        # __iter__ defined but it isn't callable as list().
 
126
        return unicode(value)
 
127
 
 
128
 
 
129
def dumps(value, default=to_primitive, **kwargs):
 
130
    return json.dumps(value, default=default, **kwargs)
 
131
 
 
132
 
 
133
def loads(s):
 
134
    return json.loads(s)
 
135
 
 
136
 
 
137
def load(s):
 
138
    return json.load(s)
 
139
 
 
140
 
 
141
try:
 
142
    import anyjson
 
143
except ImportError:
 
144
    pass
 
145
else:
 
146
    anyjson._modules.append((__name__, 'dumps', TypeError,
 
147
                                       'loads', ValueError, 'load'))
 
148
    anyjson.force_implementation(__name__)