return TaggedObject(tag = FALSE, value = o)
return TaggedObject(tag = _TYPES_TO_TAGS[type(o)], value = o)
+
+_NONE = TaggedObject(tag = VOID, value = None)
+_TRUE = TaggedObject(tag = TRUE, value = True)
+_FALSE = TaggedObject(tag = FALSE, value = False)
+
+_TAGS_TO_IN_RANGE_PREDICATES = collections.OrderedDict([
+ (INT8, lambda i: -128 <= i and i <= 127),
+ (INT16, lambda i: -32768 <= i and i <= 32767),
+ (INT32, lambda i: -2147483648 <= i and i <= 2147483647),
+ (INT64, lambda i: -9223372036854775808 <= i and i <= 9223372036854775807),
+])
+
+class TooWideError(Exception):
+ pass
+
+SMALLEST = object()
+
+def autotag(o, **kwargs):
+ preferred_integer_tag = kwargs.pop('preferred_integer_tag', DEFAULT_INTEGER_ENCODING)
+ preferred_string_tag = kwargs.pop('preferred_string_tag', DEFAULT_STRING_ENCODING)
+
+ if kwargs:
+ raise TypeError("autotag() got an unexpected keyword argument '{}'".format(
+ list(kwargs.keys())[0],
+ ))
+
+ if isinstance(o, TaggedObject):
+ return o
+
+ if o is None:
+ return _NONE
+
+ if o is True:
+ return _TRUE
+
+ if o is False:
+ return _FALSE
+
+ if isinstance(o, int):
+ if preferred_integer_tag is not SMALLEST and _TAGS_TO_IN_RANGE_PREDICATES[preferred_integer_tag](o):
+ return TaggedObject(tag = preferred_integer_tag, value = o)
+
+ else:
+ for tag, in_range_predicate in _TAGS_TO_IN_RANGE_PREDICATES.items():
+ if in_range_predicate(o):
+ return TaggedObject(tag = tag, value = o)
+
+ raise TooWideError("Integer {} is too wide to be serialized")
+
+ if isinstance(o, float):
+ raise Exception('Unsupported type {}'.format(type(o)))
+
+ if isinstance(o, str):
+ # TODO Support SMALLEST for preferred string tag
+ return TaggedObject(tag = preferred_string_tag, value = o)
+
+ if isinstance(o, list):
+ return TaggedObject(
+ tag = LIST,
+ value = [
+ autotag(
+ i,
+ preferred_integer_tag = preferred_integer_tag,
+ preferred_string_tag = preferred_string_tag,
+ ) for i in o
+ ],
+ )
+
+ if isinstance(o, dict):
+ return TaggedObject(
+ tag = DICTIONARY,
+ value = collections.OrderedDict([
+ (
+ autotag(
+ key,
+ preferred_integer_tag = preferred_integer_tag,
+ preferred_string_tag = preferred_string_tag,
+ ),
+ autotag(
+ value,
+ preferred_integer_tag = preferred_integer_tag,
+ preferred_string_tag = preferred_string_tag,
+ ),
+ ) for key, value in o.items()
+ ]),
+ )
+
+ raise Exception('Unsupported type {}'.format(type(o)))
--- /dev/null
+import collections
+import unittest
+
+from don import tags
+
+class AutoTagTests(unittest.TestCase):
+ def test_autotags_void(self):
+ self.assertEqual(
+ tags.autotag(None),
+ tags.TaggedObject(tag = tags.VOID, value = None),
+ )
+
+ def test_autotags_true(self):
+ self.assertEqual(
+ tags.autotag(True),
+ tags.TaggedObject(tag = tags.TRUE, value = True),
+ )
+
+ def test_autotags_false(self):
+ self.assertEqual(
+ tags.autotag(False),
+ tags.TaggedObject(tag = tags.FALSE, value = False),
+ )
+
+ def test_autotags_int_defaults_to_INT32(self):
+ self.assertEqual(
+ tags.autotag(127),
+ tags.TaggedObject(tag = tags.DEFAULT_INTEGER_ENCODING, value = 127),
+ )
+ self.assertEqual(
+ tags.autotag(-128),
+ tags.TaggedObject(tag = tags.DEFAULT_INTEGER_ENCODING, value = -128),
+ )
+ self.assertEqual(
+ tags.autotag(128),
+ tags.TaggedObject(tag = tags.DEFAULT_INTEGER_ENCODING, value = 128),
+ )
+ self.assertEqual(
+ tags.autotag(-129),
+ tags.TaggedObject(tag = tags.DEFAULT_INTEGER_ENCODING, value = -129),
+ )
+ self.assertEqual(
+ tags.autotag(-32768),
+ tags.TaggedObject(tag = tags.DEFAULT_INTEGER_ENCODING, value = -32768),
+ )
+ self.assertEqual(
+ tags.autotag(32767),
+ tags.TaggedObject(tag = tags.DEFAULT_INTEGER_ENCODING, value = 32767),
+ )
+ self.assertEqual(
+ tags.autotag(-32769),
+ tags.TaggedObject(tag = tags.DEFAULT_INTEGER_ENCODING, value = -32769),
+ )
+ self.assertEqual(
+ tags.autotag(32768),
+ tags.TaggedObject(tag = tags.DEFAULT_INTEGER_ENCODING, value = 32768),
+ )
+ self.assertEqual(
+ tags.autotag(-2147483648),
+ tags.TaggedObject(tag = tags.DEFAULT_INTEGER_ENCODING, value = -2147483648),
+ )
+ self.assertEqual(
+ tags.autotag(2147483647),
+ tags.TaggedObject(tag = tags.DEFAULT_INTEGER_ENCODING, value = 2147483647),
+ )
+ self.assertEqual(
+ tags.autotag(-2147483649),
+ tags.TaggedObject(tag = tags.INT64, value = -2147483649),
+ )
+ self.assertEqual(
+ tags.autotag(2147483648),
+ tags.TaggedObject(tag = tags.INT64, value = 2147483648),
+ )
+ self.assertEqual(
+ tags.autotag(-9223372036854775808),
+ tags.TaggedObject(tag = tags.INT64, value = -9223372036854775808),
+ )
+ self.assertEqual(
+ tags.autotag(9223372036854775807),
+ tags.TaggedObject(tag = tags.INT64, value = 9223372036854775807),
+ )
+
+ with self.assertRaises(tags.TooWideError):
+ tags.autotag(9223372036854775808)
+
+ with self.assertRaises(tags.TooWideError):
+ tags.autotag(-9223372036854775809)
+
+ def test_autotags_int_to_smallest_possible_type_when_preferred_type_is_smallest(self):
+ self.assertEqual(
+ tags.autotag(127, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT8, value = 127),
+ )
+ self.assertEqual(
+ tags.autotag(-128, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT8, value = -128),
+ )
+ self.assertEqual(
+ tags.autotag(128, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT16, value = 128),
+ )
+ self.assertEqual(
+ tags.autotag(-129, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT16, value = -129),
+ )
+ self.assertEqual(
+ tags.autotag(-32768, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT16, value = -32768),
+ )
+ self.assertEqual(
+ tags.autotag(32767, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT16, value = 32767),
+ )
+ self.assertEqual(
+ tags.autotag(-32769, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT32, value = -32769),
+ )
+ self.assertEqual(
+ tags.autotag(32768, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT32, value = 32768),
+ )
+ self.assertEqual(
+ tags.autotag(-2147483648, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT32, value = -2147483648),
+ )
+ self.assertEqual(
+ tags.autotag(2147483647, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT32, value = 2147483647),
+ )
+ self.assertEqual(
+ tags.autotag(-2147483649, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT64, value = -2147483649),
+ )
+ self.assertEqual(
+ tags.autotag(2147483648, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT64, value = 2147483648),
+ )
+ self.assertEqual(
+ tags.autotag(-9223372036854775808, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT64, value = -9223372036854775808),
+ )
+ self.assertEqual(
+ tags.autotag(9223372036854775807, preferred_integer_tag=tags.SMALLEST),
+ tags.TaggedObject(tag = tags.INT64, value = 9223372036854775807),
+ )
+
+ with self.assertRaises(tags.TooWideError):
+ tags.autotag(9223372036854775808, preferred_integer_tag=tags.SMALLEST)
+
+ with self.assertRaises(tags.TooWideError):
+ tags.autotag(-9223372036854775809, preferred_integer_tag=tags.SMALLEST)
+
+ def test_tags_integer_to_preferred_integer_tag(self):
+ self.assertEqual(
+ tags.autotag(42, preferred_integer_tag = tags.INT8),
+ tags.TaggedObject(tag = tags.INT8, value = 42),
+ )
+
+ self.assertEqual(
+ tags.autotag(42, preferred_integer_tag = tags.INT16),
+ tags.TaggedObject(tag = tags.INT16, value = 42),
+ )
+
+ self.assertEqual(
+ tags.autotag(42, preferred_integer_tag = tags.INT32),
+ tags.TaggedObject(tag = tags.INT32, value = 42),
+ )
+
+ self.assertEqual(
+ tags.autotag(42, preferred_integer_tag = tags.INT64),
+ tags.TaggedObject(tag = tags.INT64, value = 42),
+ )
+
+ def test_tags_string_to_utf8_by_default(self):
+ self.assertEqual(
+ tags.autotag('Hello, world'),
+ tags.TaggedObject(tag = tags.DEFAULT_STRING_ENCODING, value = 'Hello, world'),
+ )
+
+ def test_tags_string_to_preferred_string_encoding(self):
+ self.assertEqual(
+ tags.autotag('Hello, world', preferred_string_tag=tags.UTF8),
+ tags.TaggedObject(tag = tags.UTF8, value = 'Hello, world'),
+ )
+
+ self.assertEqual(
+ tags.autotag('Hello, world', preferred_string_tag=tags.UTF16),
+ tags.TaggedObject(tag = tags.UTF16, value = 'Hello, world'),
+ )
+
+ self.assertEqual(
+ tags.autotag('Hello, world', preferred_string_tag=tags.UTF32),
+ tags.TaggedObject(tag = tags.UTF32, value = 'Hello, world'),
+ )
+
+ def test_tags_list(self):
+ self.assertEqual(
+ tags.autotag([1,2,3]),
+ tags.TaggedObject(
+ tag = tags.LIST,
+ value = [
+ tags.TaggedObject(tag = tags.INT32, value = 1),
+ tags.TaggedObject(tag = tags.INT32, value = 2),
+ tags.TaggedObject(tag = tags.INT32, value = 3),
+ ],
+ ),
+ )
+
+ def test_tags_dictionary(self):
+ self.assertEqual(
+ tags.autotag(collections.OrderedDict([
+ ('foo', 1),
+ ('bar', True),
+ ])),
+ tags.TaggedObject(
+ tag = tags.DICTIONARY,
+ value = collections.OrderedDict([
+ (
+ tags.TaggedObject(tag = tags.UTF8, value = 'foo'),
+ tags.TaggedObject(tag = tags.INT32, value = 1),
+ ),
+ (
+ tags.TaggedObject(tag = tags.UTF8, value = 'bar'),
+ tags.TaggedObject(tag = tags.TRUE, value = True),
+ ),
+ ]),
+ ),
+ )
+
+unittest.main()