From 3b2bfcf29a0c9f940aa08dbe382e09f75b006ed0 Mon Sep 17 00:00:00 2001 From: Nikolaus Waxweiler Date: Thu, 13 Dec 2018 14:43:53 +0000 Subject: [PATCH] Treat Mapping objects as dicts --- Lib/fontTools/misc/plistlib.py | 9 +++++++-- Tests/misc/plistlib_test.py | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Lib/fontTools/misc/plistlib.py b/Lib/fontTools/misc/plistlib.py index fe6959368..a0e1003f7 100644 --- a/Lib/fontTools/misc/plistlib.py +++ b/Lib/fontTools/misc/plistlib.py @@ -6,6 +6,11 @@ from datetime import datetime from base64 import b64encode, b64decode from numbers import Integral +try: + from collections.abc import Mapping # python >= 3.3 +except ImportError: + from collections import Mapping + try: from functools import singledispatch except ImportError: @@ -384,7 +389,7 @@ if singledispatch is not None: _make_element.register(bool)(_bool_element) _make_element.register(Integral)(_integer_element) _make_element.register(float)(_real_element) - _make_element.register(dict)(_dict_element) + _make_element.register(Mapping)(_dict_element) _make_element.register(list)(_array_element) _make_element.register(tuple)(_array_element) _make_element.register(datetime)(_date_element) @@ -404,7 +409,7 @@ else: return _integer_element(value, ctx) elif isinstance(value, float): return _real_element(value, ctx) - elif isinstance(value, dict): + elif isinstance(value, Mapping): return _dict_element(value, ctx) elif isinstance(value, (list, tuple)): return _array_element(value, ctx) diff --git a/Tests/misc/plistlib_test.py b/Tests/misc/plistlib_test.py index 041f33280..c86652983 100644 --- a/Tests/misc/plistlib_test.py +++ b/Tests/misc/plistlib_test.py @@ -14,6 +14,10 @@ from fontTools.ufoLib.plistlib import ( ) import pytest +try: + from collections.abc import Mapping # python >= 3.3 +except ImportError: + from collections import Mapping PY2 = sys.version_info < (3,) if PY2: @@ -530,6 +534,25 @@ def test_non_ascii_bytes(): plistlib.dumps("\U0001f40d".encode("utf-8"), use_builtin_types=False) +class CustomMapping(Mapping): + a = {"a": 1, "b": 2} + + def __getitem__(self, key): + return self.a[key] + + def __iter__(self): + return iter(self.a) + + def __len__(self): + return len(self.a) + + +def test_custom_mapping(): + test_mapping = CustomMapping() + data = plistlib.dumps(test_mapping) + assert plistlib.loads(data) == {"a": 1, "b": 2} + + if __name__ == "__main__": import sys