Skip to content

Instantly share code, notes, and snippets.

@sente
Forked from simonw/jsonlike.py
Created March 10, 2016 12:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sente/734916a5b428627fcc65 to your computer and use it in GitHub Desktop.
Save sente/734916a5b428627fcc65 to your computer and use it in GitHub Desktop.
Function for recursively checking that a Python data structure consists only of JSON-compatible primitives.
def is_jsonlike(obj):
# Recursively checks if obj is composed
# only of JSON-compatible primitives
t = type(obj)
if t in (str, unicode, int, float, bool, type(None)):
return True
elif t is dict:
for key, value in obj.items():
if type(key) not in (str, unicode):
return False
if not is_jsonlike(value):
return False
return True
elif t in (list, tuple):
return all(is_jsonlike(item) for item in obj)
else:
return False
import unittest
class JsonLikeTests(unittest.TestCase):
def assertGood(self, obj):
self.assert_(is_jsonlike(obj), '%s should pass is_jsonlike' % repr(obj))
def assertBad(self, obj):
self.assert_(not is_jsonlike(obj), '%s should not pass is_jsonlike' % repr(obj))
def test_primitives(self):
self.assertGood(1)
self.assertGood(1.5)
self.assertGood(-1)
self.assertGood(0)
self.assertGood(None)
self.assertGood('string')
self.assertGood(u'unicode')
self.assertGood(True)
self.assertGood(False)
def test_some_bad_objects(self):
import datetime
self.assertBad(datetime.datetime.now())
self.assertBad(datetime.date.today())
self.assertBad(object)
self.assertBad(set())
def test_simple_dict(self):
self.assertGood({"foo": "bar"})
self.assertGood({"foo": 1})
self.assertGood({u"bar": 1.5})
def test_dict_with_bad_keys(self):
# JSON-like dictionaries must have string keys
self.assertBad({1: "foo"})
self.assertBad({1.5: "foo"})
self.assertBad({1: "foo"})
self.assertBad({("tuple", "here"): "foo"})
def test_simple_list(self):
self.assertGood([])
self.assertGood([1, 2.5, "three", None, False, True, u'unicode'])
def test_simple_tuple(self):
self.assertGood(tuple())
self.assertGood((1, 2.5, "three", None, False, True, u'unicode'))
def test_complex_nested_object(self):
self.assertGood({
"nested": {
"tuple": (1, 3, 4.5, {"nested": "again"}),
"list": (1, 3, 4.5, {"another": {"nested": True}}),
}
})
self.assertBad({
"nested": {
"tuple": (1, 3, 4.5, {"nested": "again"}),
"list": (1, 3, 4.5, {"another": {"nested": True, "bad": object}}),
}
})
def test_subclasses_not_allowed(self):
# It's important people can't sneak subclasses
# of basic classes past the is_jsonlike function
class mystr(str):
pass
class myint(int):
pass
class mydict(dict):
pass
self.assertBad(mystr("hello"))
self.assertBad(myint(1))
self.assertBad({"foo": mydict({"bar": 1})})
if __name__ == '__main__':
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment