75 lines
1.7 KiB
Python
75 lines
1.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""A convenience class for objects which can be converted to JSON."""
|
|
|
|
from __future__ import print_function
|
|
|
|
_BUILTINS = (str, int, float, bool, type(None))
|
|
|
|
|
|
class Structured(object):
|
|
"""An object with a approved set of public properties (.VISIBLE_KEYS)"""
|
|
|
|
def _Keys(self):
|
|
seen = set()
|
|
for cls in type(self).mro():
|
|
for k in getattr(cls, 'VISIBLE_KEYS', ()):
|
|
if k not in seen:
|
|
yield k
|
|
seen.add(k)
|
|
|
|
def ToDict(self):
|
|
return ToStructure(self)
|
|
|
|
|
|
def ToStructure(value):
|
|
"""Makes an object JSON-encodable.
|
|
|
|
Args:
|
|
value: An object which can be converted to a JSON-encodable object.
|
|
|
|
Returns:
|
|
An object which is legal to pass into json.dumps(obj), namely
|
|
type JSONEncodable = (
|
|
str | int | float | NoneType | dict<str, JSONEncodable> |
|
|
list<JSONEncodable>
|
|
|
|
Raises:
|
|
StackOverflow if the object has circular references (parent -> child ->
|
|
parent).
|
|
"""
|
|
if isinstance(value, _BUILTINS):
|
|
return value
|
|
|
|
elif hasattr(value, '_Keys'):
|
|
ret = {}
|
|
for k in value._Keys(): # pylint: disable=protected-access
|
|
v = ToStructure(getattr(value, k, None))
|
|
if v is not None:
|
|
ret[k] = v
|
|
return ret
|
|
|
|
elif isinstance(value, dict):
|
|
ret = {}
|
|
for k, v in value.items():
|
|
v = ToStructure(v)
|
|
if v is not None:
|
|
ret[k] = v
|
|
return ret
|
|
|
|
else:
|
|
try:
|
|
iterator = iter(value)
|
|
except TypeError:
|
|
return None
|
|
|
|
ret = []
|
|
for element in iterator:
|
|
v = ToStructure(element)
|
|
if v is not None:
|
|
ret.append(v)
|
|
|
|
return ret |