diff options
| author | Sandy Walsh <sandy.walsh@rackspace.com> | 2011-08-02 11:23:11 +0000 |
|---|---|---|
| committer | Tarmac <> | 2011-08-02 11:23:11 +0000 |
| commit | f05628dff7aebd15e3f3530295ece3372bf2dbec (patch) | |
| tree | 45877b5b999db41f2012cb3d336fe57001fe0e58 /nova/utils.py | |
| parent | efdd1bb019ac431d7d7a1923ff8580de1bb34217 (diff) | |
| parent | 51f4d4c2e0c7d9f066b328014aa955b150b62c3a (diff) | |
| download | nova-f05628dff7aebd15e3f3530295ece3372bf2dbec.tar.gz nova-f05628dff7aebd15e3f3530295ece3372bf2dbec.tar.xz nova-f05628dff7aebd15e3f3530295ece3372bf2dbec.zip | |
While we currently trap JSON encoding exceptions and bail out, for error notification it's more important that *some* form of the message gets out. So, we take complex notification payloads and convert them to something we know can be expressed in JSON.
Diffstat (limited to 'nova/utils.py')
| -rw-r--r-- | nova/utils.py | 74 |
1 files changed, 55 insertions, 19 deletions
diff --git a/nova/utils.py b/nova/utils.py index 737903f81..4ea623cc1 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -513,25 +513,61 @@ def utf8(value): return value -def to_primitive(value): - if type(value) is type([]) or type(value) is type((None,)): - o = [] - for v in value: - o.append(to_primitive(v)) - return o - elif type(value) is type({}): - o = {} - for k, v in value.iteritems(): - o[k] = to_primitive(v) - return o - elif isinstance(value, datetime.datetime): - return str(value) - elif hasattr(value, 'iteritems'): - return to_primitive(dict(value.iteritems())) - elif hasattr(value, '__iter__'): - return to_primitive(list(value)) - else: - return value +def to_primitive(value, convert_instances=False, level=0): + """Convert a complex object into primitives. + + Handy for JSON serialization. We can optionally handle instances, + but since this is a recursive function, we could have cyclical + data structures. + + To handle cyclical data structures we could track the actual objects + visited in a set, but not all objects are hashable. Instead we just + track the depth of the object inspections and don't go too deep. + + Therefore, convert_instances=True is lossy ... be aware. + + """ + if inspect.isclass(value): + return unicode(value) + + if level > 3: + return [] + + # The try block may not be necessary after the class check above, + # but just in case ... + try: + if type(value) is type([]) or type(value) is type((None,)): + o = [] + for v in value: + o.append(to_primitive(v, convert_instances=convert_instances, + level=level)) + return o + elif type(value) is type({}): + o = {} + for k, v in value.iteritems(): + o[k] = to_primitive(v, convert_instances=convert_instances, + level=level) + return o + elif isinstance(value, datetime.datetime): + return str(value) + elif hasattr(value, 'iteritems'): + return to_primitive(dict(value.iteritems()), + convert_instances=convert_instances, + level=level) + elif hasattr(value, '__iter__'): + return to_primitive(list(value), level) + elif convert_instances and hasattr(value, '__dict__'): + # Likely an instance of something. Watch for cycles. + # Ignore class member vars. + return to_primitive(value.__dict__, + convert_instances=convert_instances, + level=level + 1) + else: + return value + except TypeError, e: + # Class objects are tricky since they may define something like + # __iter__ defined but it isn't callable as list(). + return unicode(value) def dumps(value): |
