Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-u-msgpack-python for openSUSE:Factory checked in at 2022-10-12 18:22:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-u-msgpack-python (Old) and /work/SRC/openSUSE:Factory/.python-u-msgpack-python.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-u-msgpack-python" Wed Oct 12 18:22:29 2022 rev:10 rq:1009898 version:2.7.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-u-msgpack-python/python-u-msgpack-python.changes 2020-08-01 12:30:34.982423388 +0200 +++ /work/SRC/openSUSE:Factory/.python-u-msgpack-python.new.2275/python-u-msgpack-python.changes 2022-10-12 18:22:31.685340176 +0200 @@ -1,0 +2,7 @@ +Tue Oct 11 16:38:21 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> + +- Update to Version 2.7.1 - 10/24/2020 + * Add Ext type value validation to Ext class and ext_serializable() decorator. + * Change string formatting from % to .format() throughout codebase. + +------------------------------------------------------------------- Old: ---- u-msgpack-python-2.6.0.tar.gz New: ---- u-msgpack-python-2.7.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-u-msgpack-python.spec ++++++ --- /var/tmp/diff_new_pack.zslnuI/_old 2022-10-12 18:22:32.553342345 +0200 +++ /var/tmp/diff_new_pack.zslnuI/_new 2022-10-12 18:22:32.557342355 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-u-msgpack-python # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-u-msgpack-python -Version: 2.6.0 +Version: 2.7.1 Release: 0 Summary: A MessagePack serializer and deserializer License: MIT ++++++ u-msgpack-python-2.6.0.tar.gz -> u-msgpack-python-2.7.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/u-msgpack-python-2.6.0/PKG-INFO new/u-msgpack-python-2.7.1/PKG-INFO --- old/u-msgpack-python-2.6.0/PKG-INFO 2020-04-25 10:39:46.034381400 +0200 +++ new/u-msgpack-python-2.7.1/PKG-INFO 2020-10-25 04:53:11.778906000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: u-msgpack-python -Version: 2.6.0 +Version: 2.7.1 Summary: A portable, lightweight MessagePack serializer and deserializer written in pure Python. Home-page: https://github.com/vsergeev/u-msgpack-python Author: vsergeev diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/u-msgpack-python-2.6.0/README.md new/u-msgpack-python-2.7.1/README.md --- old/u-msgpack-python-2.6.0/README.md 2020-04-25 10:31:46.000000000 +0200 +++ new/u-msgpack-python-2.7.1/README.md 2020-10-25 04:08:04.000000000 +0100 @@ -64,14 +64,14 @@ Serializing and deserializing a raw Ext type: ``` python ->>> # Create an Ext object with type 0x05 and data b"\x01\x02\x03" -... foo = umsgpack.Ext(0x05, b"\x01\x02\x03") +>>> # Create an Ext object with type 5 and data b"\x01\x02\x03" +... foo = umsgpack.Ext(5, b"\x01\x02\x03") >>> umsgpack.packb({u"stuff": foo, u"awesome": True}) b'\x82\xa5stuff\xc7\x03\x05\x01\x02\x03\xa7awesome\xc3' >>> >>> bar = umsgpack.unpackb(_) >>> print(bar['stuff']) -Ext Object (Type: 0x05, Data: 0x01 0x02 0x03) +Ext Object (Type: 5, Data: 0x01 0x02 0x03) >>> bar['stuff'].type 5 >>> bar['stuff'].data diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/u-msgpack-python-2.6.0/setup.py new/u-msgpack-python-2.7.1/setup.py --- old/u-msgpack-python-2.6.0/setup.py 2020-04-25 10:31:46.000000000 +0200 +++ new/u-msgpack-python-2.7.1/setup.py 2020-10-25 04:50:17.000000000 +0100 @@ -5,7 +5,7 @@ setup( name='u-msgpack-python', - version='2.6.0', + version='2.7.1', description='A portable, lightweight MessagePack serializer and deserializer written in pure Python.', author='vsergeev', author_email='v...@sergeev.io', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/u-msgpack-python-2.6.0/test_umsgpack.py new/u-msgpack-python-2.7.1/test_umsgpack.py --- old/u-msgpack-python-2.6.0/test_umsgpack.py 2020-04-25 10:21:55.000000000 +0200 +++ new/u-msgpack-python-2.7.1/test_umsgpack.py 2020-10-25 04:50:17.000000000 +0100 @@ -404,24 +404,24 @@ def test_pack_single(self): for (name, obj, data) in single_test_vectors: obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) self.assertEqual(umsgpack.packb(obj), data) def test_pack_composite(self): for (name, obj, data) in composite_test_vectors: obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) self.assertEqual(umsgpack.packb(obj), data) def test_pack_exceptions(self): for (name, obj, exception) in pack_exception_test_vectors: obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) with self.assertRaises(exception): umsgpack.packb(obj) @@ -429,8 +429,8 @@ def test_unpack_single(self): for (name, obj, data) in single_test_vectors: obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) unpacked = umsgpack.unpackb(data) @@ -452,14 +452,14 @@ def test_unpack_composite(self): for (name, obj, data) in composite_test_vectors: obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) self.assertEqual(umsgpack.unpackb(data), obj) def test_unpack_exceptions(self): for (name, data, exception) in unpack_exception_test_vectors: - print("\tTesting %s" % name) + print("\tTesting {:s}".format(name)) with self.assertRaises(exception): umsgpack.unpackb(data) @@ -469,8 +469,8 @@ for (name, obj, data) in compatibility_test_vectors: obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) self.assertEqual(umsgpack.packb(obj), data) @@ -481,8 +481,8 @@ for (name, obj, data) in compatibility_test_vectors: obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) unpacked = umsgpack.unpackb(data) @@ -539,17 +539,25 @@ self.assertEqual(umsgpack.unpackb(data, use_tuple=True), obj_tuple) def test_ext_exceptions(self): + # Test invalid Ext type type with self.assertRaises(TypeError): _ = umsgpack.Ext(5.0, b"") + # Test invalid data type with self.assertRaises(TypeError): _ = umsgpack.Ext(0, u"unicode string") + # Test out of range Ext type value + with self.assertRaises(ValueError): + _ = umsgpack.Ext(-129, b"data") + with self.assertRaises(ValueError): + _ = umsgpack.Ext(128, b"data") + def test_pack_ext_handler(self): for (name, obj, data) in ext_handlers_test_vectors: obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) packed = umsgpack.packb(obj, ext_handlers=ext_handlers) self.assertEqual(packed, data) @@ -557,8 +565,8 @@ def test_unpack_ext_handler(self): for (name, obj, data) in ext_handlers_test_vectors: obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) unpacked = umsgpack.unpackb(data, ext_handlers=ext_handlers) self.assertEqual(unpacked, obj) @@ -566,8 +574,8 @@ def test_pack_force_float_precision(self): for ((name, obj, data), precision) in zip(float_precision_test_vectors, ["single", "double"]): obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) packed = umsgpack.packb(obj, force_float_precision=precision) self.assertEqual(packed, data) @@ -575,8 +583,8 @@ def test_pack_naive_timestamp(self): for (name, obj, data, _) in naive_timestamp_test_vectors: obj_repr = repr(obj) - print("\t Testing %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) packed = umsgpack.packb(obj) self.assertEqual(packed, data) @@ -584,8 +592,8 @@ def test_unpack_naive_timestamp(self): for (name, _, data, obj) in naive_timestamp_test_vectors: obj_repr = repr(obj) - print("\t Testing %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) unpacked = umsgpack.unpackb(data) self.assertEqual(unpacked, obj) @@ -594,8 +602,8 @@ # Test overridden packing of datetime.datetime (name, obj, data) = override_ext_handlers_test_vectors[0] obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) packed = umsgpack.packb(obj, ext_handlers=override_ext_handlers) self.assertEqual(packed, data) @@ -604,12 +612,37 @@ # Test overridden unpacking of Ext type -1 (name, obj, data) = override_ext_handlers_test_vectors[1] obj_repr = repr(obj) - print("\tTesting %s: object %s" % - (name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) + print("\tTesting {:s}: object {:s}".format( + name, obj_repr if len(obj_repr) < 24 else obj_repr[0:24] + "...")) unpacked = umsgpack.unpackb(data, ext_handlers=override_ext_handlers) self.assertEqual(unpacked, obj) + def test_ext_handlers_subclass(self): + class Rectangle: + def __init__(self, length, width): + self.length = length + self.width = width + + def __eq__(self, other): + return self.length == other.length and self.width == other.width + + class Square(Rectangle): + def __init__(self, width): + Rectangle.__init__(self, width, width) + + # Test pack (packs base class) + packed = umsgpack.packb(Square(5), ext_handlers={ + Rectangle: lambda obj: umsgpack.Ext(0x10, umsgpack.packb([obj.length, obj.width])), + }) + self.assertEqual(packed, b"\xc7\x03\x10\x92\x05\x05") + + # Test unpack (unpacks base class) + unpacked = umsgpack.unpackb(packed, ext_handlers={ + 0x10: lambda ext: Rectangle(*umsgpack.unpackb(ext.data)), + }) + self.assertEqual(unpacked, Rectangle(5, 5)) + def test_ext_serializable(self): # Register test class @umsgpack.ext_serializable(0x20) @@ -656,6 +689,16 @@ class DummyClass: pass + # Test out of range Ext type value + with self.assertRaises(ValueError): + @umsgpack.ext_serializable(-129) + class DummyClass2: + pass + with self.assertRaises(ValueError): + @umsgpack.ext_serializable(128) + class DummyClass3: + pass + # Register class with missing packb() and unpackb() @umsgpack.ext_serializable(0x21) class IncompleteClass: @@ -669,8 +712,44 @@ with self.assertRaises(NotImplementedError): umsgpack.unpackb(b"\xd4\x21\x00") - # Unregister Ext serializable classes for future tests - umsgpack._ext_classes = {} + # Unregister Ext serializable classes to prevent interference with + # subsequent tests + umsgpack._ext_classes_to_code = {} + umsgpack._ext_code_to_classes = {} + + def test_ext_serializable_subclass(self): + @umsgpack.ext_serializable(0x10) + class Rectangle: + def __init__(self, length, width): + self.length = length + self.width = width + + def __eq__(self, other): + return self.length == other.length and self.width == other.width + + def packb(self): + return umsgpack.packb([self.length, self.width]) + + @classmethod + def unpackb(cls, data): + return cls(*umsgpack.unpackb(data)) + + class Square(Rectangle): + def __init__(self, width): + Rectangle.__init__(self, width, width) + + # Test pack (packs base class) + packed = umsgpack.packb(Square(5)) + self.assertEqual(packed, b"\xc7\x03\x10\x92\x05\x05") + + # Test unpack (unpacks base class) + unpacked = umsgpack.unpackb(packed) + self.assertEqual(unpacked, Rectangle(5, 5)) + + # Unregister Ext serializable classes to prevent interference with + # subsequent tests + umsgpack._ext_classes_to_code = {} + umsgpack._ext_code_to_classes = {} def test_streaming_writer(self): # Try first composite test vector @@ -687,11 +766,10 @@ def test_namespacing(self): # Get a list of global variables from umsgpack module - exported_vars = list(filter(lambda x: not x.startswith("_"), - dir(umsgpack))) + exported_vars = list([x for x in dir(umsgpack) if not x.startswith("_")]) # Ignore imports - exported_vars = list(filter(lambda x: x != "struct" and x != "collections" and x != "datetime" and x != - "sys" and x != "io" and x != "xrange" and x != "Hashable", exported_vars)) + exported_vars = list([x for x in exported_vars if x != "struct" and x != "collections" and x != "datetime" and x != + "sys" and x != "io" and x != "xrange" and x != "Hashable"]) self.assertTrue(len(exported_vars) == len(exported_vars_test_vector)) for var in exported_vars_test_vector: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/u-msgpack-python-2.6.0/u_msgpack_python.egg-info/PKG-INFO new/u-msgpack-python-2.7.1/u_msgpack_python.egg-info/PKG-INFO --- old/u-msgpack-python-2.6.0/u_msgpack_python.egg-info/PKG-INFO 2020-04-25 10:39:45.000000000 +0200 +++ new/u-msgpack-python-2.7.1/u_msgpack_python.egg-info/PKG-INFO 2020-10-25 04:53:11.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: u-msgpack-python -Version: 2.6.0 +Version: 2.7.1 Summary: A portable, lightweight MessagePack serializer and deserializer written in pure Python. Home-page: https://github.com/vsergeev/u-msgpack-python Author: vsergeev diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/u-msgpack-python-2.6.0/umsgpack.py new/u-msgpack-python-2.7.1/umsgpack.py --- old/u-msgpack-python-2.6.0/umsgpack.py 2020-04-25 10:31:46.000000000 +0200 +++ new/u-msgpack-python-2.7.1/umsgpack.py 2020-10-25 04:50:17.000000000 +0100 @@ -1,4 +1,4 @@ -# u-msgpack-python v2.6.0 - v at sergeev.io +# u-msgpack-python v2.7.1 - v at sergeev.io # https://github.com/vsergeev/u-msgpack-python # # u-msgpack-python is a lightweight MessagePack serializer and deserializer @@ -31,7 +31,7 @@ # THE SOFTWARE. # """ -u-msgpack-python v2.6.0 - v at sergeev.io +u-msgpack-python v2.7.1 - v at sergeev.io https://github.com/vsergeev/u-msgpack-python u-msgpack-python is a lightweight MessagePack serializer and deserializer @@ -54,10 +54,10 @@ else: from collections import Hashable -__version__ = "2.6.0" +__version__ = "2.7.1" "Module version string" -version = (2, 6, 0) +version = (2, 7, 1) "Module version tuple" @@ -80,23 +80,33 @@ type: application-defined type integer data: application-defined data byte array + TypeError: + Type is not an integer. + ValueError: + Type is out of range of -128 to 127. + TypeError:: + Data is not type 'bytes' (Python 3) or not type 'str' (Python 2). + Example: - >>> foo = umsgpack.Ext(0x05, b"\x01\x02\x03") + >>> foo = umsgpack.Ext(5, b"\x01\x02\x03") >>> umsgpack.packb({u"special stuff": foo, u"awesome": True}) '\x82\xa7awesome\xc3\xadspecial stuff\xc7\x03\x05\x01\x02\x03' >>> bar = umsgpack.unpackb(_) >>> print(bar["special stuff"]) - Ext Object (Type: 0x05, Data: 01 02 03) + Ext Object (Type: 5, Data: 01 02 03) >>> """ - # Check type is type int + # Check type is type int and in range if not isinstance(type, int): raise TypeError("ext type is not type integer") - # Check data is type bytes + elif not (-2**7 <= type <= 2**7 - 1): + raise ValueError("ext type value {:d} is out of range (-128 to 127)".format(type)) + # Check data is type bytes or str elif sys.version_info[0] == 3 and not isinstance(data, bytes): raise TypeError("ext data is not type \'bytes\'") elif sys.version_info[0] == 2 and not isinstance(data, str): raise TypeError("ext data is not type \'str\'") + self.type = type self.data = data @@ -117,8 +127,8 @@ """ String representation of this Ext object. """ - s = "Ext Object (Type: 0x%02x, Data: " % self.type - s += " ".join(["0x%02x" % ord(self.data[i:i + 1]) + s = "Ext Object (Type: {:d}, Data: ".format(self.type) + s += " ".join(["0x{:02}".format(ord(self.data[i:i + 1])) for i in xrange(min(len(self.data), 8))]) if len(self.data) > 8: s += " ..." @@ -140,7 +150,8 @@ # Ext Serializable Decorator ############################################################################## -_ext_classes = {} +_ext_class_to_type = {} +_ext_type_to_class = {} def ext_serializable(ext_type): @@ -155,17 +166,25 @@ ext_type: application-defined Ext type code Raises: + TypeError: + Ext type is not an integer. + ValueError: + Ext type is out of range of -128 to 127. ValueError: Ext type or class already registered. """ def wrapper(cls): - if ext_type in _ext_classes: - raise ValueError("Ext type 0x{:02x} already registered with class {:s}".format(ext_type, repr(_ext_classes[ext_type]))) - elif cls in _ext_classes: - raise ValueError("Class {:s} already registered with Ext type 0x{:02x}".format(repr(cls), ext_type)) + if not isinstance(ext_type, int): + raise TypeError("Ext type is not type integer") + elif not (-2**7 <= ext_type <= 2**7 - 1): + raise ValueError("Ext type value {:d} is out of range of -128 to 127".format(ext_type)) + elif ext_type in _ext_type_to_class: + raise ValueError("Ext type {:d} already registered with class {:s}".format(ext_type, repr(_ext_type_to_class[ext_type]))) + elif cls in _ext_class_to_type: + raise ValueError("Class {:s} already registered with Ext type {:d}".format(repr(cls), ext_type)) - _ext_classes[ext_type] = cls - _ext_classes[cls] = ext_type + _ext_type_to_class[ext_type] = cls + _ext_class_to_type[cls] = ext_type return cls @@ -472,9 +491,9 @@ _pack_nil(obj, fp, options) elif ext_handlers and obj.__class__ in ext_handlers: _pack_ext(ext_handlers[obj.__class__](obj), fp, options) - elif obj.__class__ in _ext_classes: + elif obj.__class__ in _ext_class_to_type: try: - _pack_ext(Ext(_ext_classes[obj.__class__], obj.packb()), fp, options) + _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) except AttributeError: raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(obj.__class__))) elif isinstance(obj, bool): @@ -506,9 +525,19 @@ _pack_ext(ext_handlers[t](obj), fp, options) else: raise UnsupportedTypeException( - "unsupported type: %s" % str(type(obj))) + "unsupported type: {:s}".format(str(type(obj)))) + elif _ext_class_to_type: + # Linear search for superclass + t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) + if t: + try: + _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) + except AttributeError: + raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(t))) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) else: - raise UnsupportedTypeException("unsupported type: %s" % str(type(obj))) + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) # Pack for Python 3, with unicode 'str' type, 'bytes' type, and no 'long' type @@ -549,9 +578,9 @@ _pack_nil(obj, fp, options) elif ext_handlers and obj.__class__ in ext_handlers: _pack_ext(ext_handlers[obj.__class__](obj), fp, options) - elif obj.__class__ in _ext_classes: + elif obj.__class__ in _ext_class_to_type: try: - _pack_ext(Ext(_ext_classes[obj.__class__], obj.packb()), fp, options) + _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) except AttributeError: raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(obj.__class__))) elif isinstance(obj, bool): @@ -583,10 +612,20 @@ _pack_ext(ext_handlers[t](obj), fp, options) else: raise UnsupportedTypeException( - "unsupported type: %s" % str(type(obj))) + "unsupported type: {:s}".format(str(type(obj)))) + elif _ext_class_to_type: + # Linear search for superclass + t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) + if t: + try: + _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) + except AttributeError: + raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(t))) + else: + raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) else: raise UnsupportedTypeException( - "unsupported type: %s" % str(type(obj))) + "unsupported type: {:s}".format(str(type(obj)))) def _packb2(obj, **options): @@ -698,21 +737,21 @@ return struct.unpack(">I", _read_except(fp, 4))[0] elif code == b'\xcf': return struct.unpack(">Q", _read_except(fp, 8))[0] - raise Exception("logic error, not int: 0x%02x" % ord(code)) + raise Exception("logic error, not int: 0x{:02x}".format(ord(code))) def _unpack_reserved(code, fp, options): if code == b'\xc1': raise ReservedCodeException( - "encountered reserved code: 0x%02x" % ord(code)) + "encountered reserved code: 0x{:02x}".format(ord(code))) raise Exception( - "logic error, not reserved code: 0x%02x" % ord(code)) + "logic error, not reserved code: 0x{:02x}".format(ord(code))) def _unpack_nil(code, fp, options): if code == b'\xc0': return None - raise Exception("logic error, not nil: 0x%02x" % ord(code)) + raise Exception("logic error, not nil: 0x{:02x}".format(ord(code))) def _unpack_boolean(code, fp, options): @@ -720,7 +759,7 @@ return False elif code == b'\xc3': return True - raise Exception("logic error, not boolean: 0x%02x" % ord(code)) + raise Exception("logic error, not boolean: 0x{:02x}".format(ord(code))) def _unpack_float(code, fp, options): @@ -728,7 +767,7 @@ return struct.unpack(">f", _read_except(fp, 4))[0] elif code == b'\xcb': return struct.unpack(">d", _read_except(fp, 8))[0] - raise Exception("logic error, not float: 0x%02x" % ord(code)) + raise Exception("logic error, not float: 0x{:02x}".format(ord(code))) def _unpack_string(code, fp, options): @@ -741,7 +780,7 @@ elif code == b'\xdb': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not string: 0x%02x" % ord(code)) + raise Exception("logic error, not string: 0x{:02x}".format(ord(code))) # Always return raw bytes in compatibility mode global compatibility @@ -765,7 +804,7 @@ elif code == b'\xc6': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not binary: 0x%02x" % ord(code)) + raise Exception("logic error, not binary: 0x{:02x}".format(ord(code))) return _read_except(fp, length) @@ -788,7 +827,7 @@ elif code == b'\xc9': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not ext: 0x%02x" % ord(code)) + raise Exception("logic error, not ext: 0x{:02x}".format(ord(code))) ext_type = struct.unpack("b", _read_except(fp, 1))[0] ext_data = _read_except(fp, length) @@ -799,11 +838,11 @@ return ext_handlers[ext_type](Ext(ext_type, ext_data)) # Unpack with ext classes, if type is registered - if ext_type in _ext_classes: + if ext_type in _ext_type_to_class: try: - return _ext_classes[ext_type].unpackb(ext_data) + return _ext_type_to_class[ext_type].unpackb(ext_data) except AttributeError: - raise NotImplementedError("Ext serializable class {:s} is missing implementation of unpackb()".format(repr(_ext_classes[ext_type]))) + raise NotImplementedError("Ext serializable class {:s} is missing implementation of unpackb()".format(repr(_ext_type_to_class[ext_type]))) # Timestamp extension if ext_type == -1: @@ -829,7 +868,7 @@ microseconds = struct.unpack(">I", ext_data[0:4])[0] // 1000 else: raise UnsupportedTimestampException( - "unsupported timestamp with data length %d" % len(ext_data)) + "unsupported timestamp with data length {:d}".format(len(ext_data))) return _epoch + datetime.timedelta(seconds=seconds, microseconds=microseconds) @@ -843,7 +882,7 @@ elif code == b'\xdd': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not array: 0x%02x" % ord(code)) + raise Exception("logic error, not array: 0x{:02x}".format(ord(code))) if options.get('use_tuple'): return tuple((_unpack(fp, options) for i in xrange(length))) @@ -865,7 +904,7 @@ elif code == b'\xdf': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not map: 0x%02x" % ord(code)) + raise Exception("logic error, not map: 0x{:02x}".format(ord(code))) d = {} if not options.get('use_ordered_dict') else collections.OrderedDict() for _ in xrange(length): @@ -877,10 +916,10 @@ k = _deep_list_to_tuple(k) elif not isinstance(k, Hashable): raise UnhashableKeyException( - "encountered unhashable key: %s, %s" % (str(k), str(type(k)))) + "encountered unhashable key: \"{:s}\" ({:s})".format(str(k), str(type(k)))) elif k in d: raise DuplicateKeyException( - "encountered duplicate key: %s, %s" % (str(k), str(type(k)))) + "encountered duplicate key: \"{:s}\" ({:s})".format(str(k), str(type(k)))) # Unpack value v = _unpack(fp, options) @@ -889,7 +928,7 @@ d[k] = v except TypeError: raise UnhashableKeyException( - "encountered unhashable key: %s" % str(k)) + "encountered unhashable key: \"{:s}\"".format(str(k))) return d