Hello community, here is the log from the commit of package python-json5 for openSUSE:Leap:15.2 checked in at 2020-04-18 18:41:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.2/python-json5 (Old) and /work/SRC/openSUSE:Leap:15.2/.python-json5.new.2738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-json5" Sat Apr 18 18:41:07 2020 rev:2 rq:795313 version:0.9.4 Changes: -------- --- /work/SRC/openSUSE:Leap:15.2/python-json5/python-json5.changes 2020-03-13 10:56:37.376402498 +0100 +++ /work/SRC/openSUSE:Leap:15.2/.python-json5.new.2738/python-json5.changes 2020-04-18 18:41:09.469969730 +0200 @@ -1,0 +2,31 @@ +Thu Apr 16 11:47:01 UTC 2020 - [email protected] + +- version update to 0.9.4 + * v0.9.4 (2020-03-26) + * [GitHub pull #38](https://github.com/dpranke/pyjson5/pull/38) + Fix from [email protected] for dumps() crashing when passed + an empty string as a key in an object. + * v0.9.3 (2020-03-17) + * [GitHub pull #35](https://github.com/dpranke/pyjson5/pull/35) + Fix from pastelmind@ for dump() not passing the right args to dumps(). + * Fix from [email protected] to remove the tests directory from + the setup call, making the package a bit smaller. + * v0.9.2 (2020-03-02) + * [GitHub pull #34](https://github.com/dpranke/pyjson5/pull/34) + Fix from roosephu@ for a badly formatted nested list. + * v0.9.1 (2020-02-09) + * [GitHub issue #33](https://github.com/dpranke/pyjson5/issues/33): + Fix stray trailing comma when dumping an object with an invalid key. + * v0.9.0 (2020-01-30) + * [GitHub issue #29](https://github.com/dpranke/pyjson5/issues/29): + Fix an issue where objects keys that started with a reserved + word were incorrectly quoted. + * [GitHub issue #30](https://github.com/dpranke/pyjson5/issues/30): + Fix an issue where dumps() incorrectly thought a data structure + was cyclic in some cases. + * [GitHub issue #32](https://github.com/dpranke/pyjson5/issues/32): + Allow for non-string keys in dicts passed to ``dump()``/``dumps()``. + Add an ``allow_duplicate_keys=False`` to prevent possible + ill-formed JSON that might result. + +------------------------------------------------------------------- Old: ---- pyjson5-0.8.5.tar.gz New: ---- pyjson5-0.9.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-json5.spec ++++++ --- /var/tmp/diff_new_pack.nZUouH/_old 2020-04-18 18:41:09.825970481 +0200 +++ /var/tmp/diff_new_pack.nZUouH/_new 2020-04-18 18:41:09.829970490 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-json5 # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,23 +12,25 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ +# %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-json5 -Version: 0.8.5 +Version: 0.9.4 Release: 0 -License: Apache-2.0 Summary: A Python implementation of the JSON5 data format -Url: https://github.com/dpranke/pyjson5 +License: Apache-2.0 Group: Development/Languages/Python +URL: https://github.com/dpranke/pyjson5 Source: https://github.com/dpranke/pyjson5/archive/v%{version}.tar.gz#/pyjson5-%{version}.tar.gz +BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros +Requires: python-setuptools BuildArch: noarch - %python_subpackages %description @@ -42,7 +44,6 @@ * Objects and arrays may end with trailing commas. * Strings can be single-quoted, and multi-line string literals are allowed. - %prep %setup -q -n pyjson5-%{version} @@ -55,7 +56,7 @@ %python_expand %fdupes %{buildroot}%{$python_sitelib} %check -%python_exec setup.py test +%pytest %files %{python_files} %doc README.md ++++++ pyjson5-0.8.5.tar.gz -> pyjson5-0.9.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyjson5-0.8.5/README.md new/pyjson5-0.9.4/README.md --- old/pyjson5-0.8.5/README.md 2019-07-05 04:18:45.000000000 +0200 +++ new/pyjson5-0.9.4/README.md 2020-03-27 00:12:33.000000000 +0100 @@ -52,17 +52,51 @@ ## Version History / Release Notes +* v0.9.4 (2020-03-26) + * [GitHub pull #38](https://github.com/dpranke/pyjson5/pull/38) + Fix from [email protected] for dumps() crashing when passed + an empty string as a key in an object. + +* v0.9.3 (2020-03-17) + * [GitHub pull #35](https://github.com/dpranke/pyjson5/pull/35) + Fix from pastelmind@ for dump() not passing the right args to dumps(). + * Fix from [email protected] to remove the tests directory from + the setup call, making the package a bit smaller. + +* v0.9.2 (2020-03-02) + * [GitHub pull #34](https://github.com/dpranke/pyjson5/pull/34) + Fix from roosephu@ for a badly formatted nested list. + +* v0.9.1 (2020-02-09) + * [GitHub issue #33](https://github.com/dpranke/pyjson5/issues/33): + Fix stray trailing comma when dumping an object with an invalid key. + +* v0.9.0 (2020-01-30) + * [GitHub issue #29](https://github.com/dpranke/pyjson5/issues/29): + Fix an issue where objects keys that started with a reserved + word were incorrectly quoted. + * [GitHub issue #30](https://github.com/dpranke/pyjson5/issues/30): + Fix an issue where dumps() incorrectly thought a data structure + was cyclic in some cases. + * [GitHub issue #32](https://github.com/dpranke/pyjson5/issues/32): + Allow for non-string keys in dicts passed to ``dump()``/``dumps()``. + Add an ``allow_duplicate_keys=False`` to prevent possible + ill-formed JSON that might result. + * v0.8.5 (2019-07-04) - * [GitHub issue #25](https://github.com/dpranke/pyjson5/issues/25): - Add LICENSE and README.md to the dist. - * [GitHub issue #26](https://github.com/dpranke/pyjson5/issues/26): - Fix printing of empty arrays and objects with indentation, fix - misreporting of the position on parse failures in some cases. + * [GitHub issue #25](https://github.com/dpranke/pyjson5/issues/25): + Add LICENSE and README.md to the dist. + * [GitHub issue #26](https://github.com/dpranke/pyjson5/issues/26): + Fix printing of empty arrays and objects with indentation, fix + misreporting of the position on parse failures in some cases. + * v0.8.4 (2019-06-11) * Updated the version history, too. + * v0.8.3 (2019-06-11) * Tweaked the README, bumped the version, forgot to update the version history :). + * v0.8.2 (2019-06-11) * Actually bump the version properly, to 0.8.2. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyjson5-0.8.5/json5/lib.py new/pyjson5-0.9.4/json5/lib.py --- old/pyjson5-0.8.5/json5/lib.py 2019-07-05 04:18:45.000000000 +0200 +++ new/pyjson5-0.9.4/json5/lib.py 2020-03-27 00:12:33.000000000 +0100 @@ -140,156 +140,248 @@ raise Exception('unknown el: ' + el) # pragma: no cover -def dumps(obj, quote_keys=False, trailing_commas=True, **kwargs): - """Serialize ``obj`` to a JSON5-formatted ``str``. +def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, + allow_nan=True, cls=None, indent=None, separators=None, + default=None, sort_keys=False, + quote_keys=False, trailing_commas=True, + allow_duplicate_keys=True, + **kwargs): + """Serialize ``obj`` to a JSON5-formatted stream to ``fp`` (a ``.write()``- + supporting file-like object). Supports the same arguments as ``json.dumps()``, except that: - The ``cls`` keyword is not supported. - - The ``encoding`` keyword is ignored; Unicode strings are always returned. + - The ``encoding`` keyword is ignored; Unicode strings are always written. - By default, object keys that are legal identifiers are not quoted; if you pass quote_keys=True, they will be. - By default, if lists and objects span multiple lines of output (i.e., when ``indent`` >=0), the last item will have a trailing comma after it. If you pass ``trailing_commas=False, it will not. - - Calling ``dumps(obj, quote_keys=True, trailing_commas=False)`` should - produce exactly the same output as ``json.dumps(obj).`` + - If you use a number, a boolean, or None as a key value in a dict, + it will be converted to the corresponding json string value, e.g. + "1", "true", or "null". By default, dump() will match the `json` + modules behavior and produce ill-formed JSON if you mix keys of + different types that have the same converted value, e.g.: + {1: "foo", "1": "bar"} produces '{"1": "foo", "1": "bar"}', an + object with duplicated keys. If you pass allow_duplicate_keys=False, + an exception will be raised instead. + + Calling ``dumps(obj, fp, quote_keys=True, trailing_commas=False, + allow_duplicate_keys=True)`` + should produce exactly the same output as ``json.dumps(obj, fp).`` """ - assert kwargs.get('cls', None) is None, 'Custom encoders are not supported' + fp.write(str(dumps(obj=obj, skipkeys=skipkeys, ensure_ascii=ensure_ascii, + check_circular=check_circular, allow_nan=allow_nan, + cls=cls, indent=indent, separators=separators, + default=default, sort_keys=sort_keys, + quote_keys=quote_keys, trailing_commas=trailing_commas, + allow_duplicate_keys=allow_duplicate_keys))) - if kwargs.get('check_circular', True): - seen = set() - else: - seen = None - return _dumps(obj, seen, quote_keys=quote_keys, - trailing_commas=trailing_commas, - **kwargs) - -def dump(obj, fp, quote_keys=False, trailing_commas=True, **kwargs): - """Serialize ``obj`` to a JSON5-formatted stream to ``fp`` (a ``.write()``- - supporting file-like object). +def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, + allow_nan=True, cls=None, indent=None, separators=None, + default=None, sort_keys=False, + quote_keys=False, trailing_commas=True, allow_duplicate_keys=True, + **kwargs): + """Serialize ``obj`` to a JSON5-formatted ``str``. Supports the same arguments as ``json.dumps()``, except that: - The ``cls`` keyword is not supported. - - The ``encoding`` keyword is ignored; Unicode strings are always written. + - The ``encoding`` keyword is ignored; Unicode strings are always returned. - By default, object keys that are legal identifiers are not quoted; if you pass quote_keys=True, they will be. - By default, if lists and objects span multiple lines of output (i.e., when ``indent`` >=0), the last item will have a trailing comma after it. If you pass ``trailing_commas=False, it will not. + - If you use a number, a boolean, or None as a key value in a dict, + it will be converted to the corresponding json string value, e.g. + "1", "true", or "null". By default, dump() will match the ``json`` + module's behavior and produce ill-formed JSON if you mix keys of + different types that have the same converted value, e.g.: + {1: "foo", "1": "bar"} produces '{"1": "foo", "1": "bar"}', an + object with duplicated keys. If you pass ``allow_duplicate_keys=False``, + an exception will be raised instead. + - Calling ``dumps(obj, fp, quote_keys=True, trailing_commas=False)`` should - produce exactly the same output as ``json.dumps(obj, fp).`` + Calling ``dumps(obj, quote_keys=True, trailing_commas=False, + allow_duplicate_keys=True)`` + should produce exactly the same output as ``json.dumps(obj).`` """ - s = dumps(obj, quote_keys=quote_keys, trailing_commas=trailing_commas, - **kwargs) - fp.write(str(s)) + assert kwargs.get('cls', None) is None, 'Custom encoders are not supported' + + if separators is None: + if indent is None: + separators = (u', ', u': ') + else: + separators = (u',', u': ') + + default = default or _raise_type_error + + if check_circular: + seen = set() + else: + seen = None + + level = 1 + is_key = False + _, v = _dumps(obj, skipkeys, ensure_ascii, check_circular, + allow_nan, indent, separators, default, sort_keys, + quote_keys, trailing_commas, allow_duplicate_keys, + seen, level, is_key) + return v -def _dumps(obj, seen, **kwargs): + +def _dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, indent, + separators, default, sort_keys, + quote_keys, trailing_commas, allow_duplicate_keys, + seen, level, is_key): + s = None if obj is True: - return u'true' + s = u'true' if obj is False: - return u'false' + s = u'false' if obj is None: - return u'null' + s = u'null' t = type(obj) if t == type('') or t == type(u''): - return _dump_str(obj, kwargs.get('ensure_ascii', True)) + if (is_key and _is_ident(obj) and not quote_keys + and not _is_reserved_word(obj)): + return True, obj + return True, _dump_str(obj, ensure_ascii) if t is float: - return _dump_float(obj, kwargs.get('allow_nan', True)) + s = _dump_float(obj,allow_nan) if t is int: - return str(obj) + s = str(obj) - if seen is not None: - i = id(obj) - if i in seen: - raise ValueError('Circular reference detected.') - else: - seen.add(i) + if is_key: + if s is not None: + return True, '"%s"' % s + if skipkeys: + return False, None + raise TypeError('invalid key %s' % repr(obj)) + + if s is not None: + return True, s - indent = kwargs.get('indent', None) - if indent is None: - separators = kwargs.get('separators', (u', ', u': ')) - else: - separators = kwargs.get('separators', (u',', u': ')) if indent is not None: - level = kwargs.get('level', 1) - nl = '\n' + end_str = '' + if trailing_commas: + end_str = ',' if type(indent) == int: if indent > 0: - indent = ' ' * indent + indent_str = '\n' + ' ' * indent * level + end_str += '\n' + ' ' * indent * (level - 1) else: - indent = '' + indent_str = '\n' + end_str += '\n' + else: + indent_str = '\n' + indent * level + end_str += '\n' + indent * (level - 1) else: - indent = '' - level = 0 - nl = '' + indent_str = '' + end_str = '' item_sep, kv_sep = separators - indent_str = nl + indent * level - if nl and kwargs.get('trailing_commas', True): - end_str = ',' + nl + indent * (level - 1) - else: - end_str = nl + indent * (level - 1) - item_sep += indent_str - kwargs['level'] = level + 1 + level += 1 - # In Python3, we'd check if this was an abc.Mapping. - # For now, just check for the attrs we need to iterate over the object. - if hasattr(t, 'keys') and hasattr(t, '__getitem__'): - return _dump_dict(obj, seen, item_sep, kv_sep, indent_str, end_str, - **kwargs) + if seen is not None: + i = id(obj) + if i in seen: + raise ValueError('Circular reference detected.') + else: + seen.add(i) - # In Python3, we'd check if this was an abc.Sequence. + # In Python3, we'd check if this was an abc.Mapping or an abc.Sequence. # For now, just check for the attrs we need to iterate over the object. - if hasattr(t, '__getitem__') and hasattr(t, '__iter__'): - if not obj: - return u'[]' - return (u'[' + indent_str + - item_sep.join([_dumps(el, seen, **kwargs) for el in obj]) + - end_str + u']') + if hasattr(t, 'keys') and hasattr(t, '__getitem__'): + s = _dump_dict(obj, skipkeys, ensure_ascii, + check_circular, allow_nan, indent, + separators, default, sort_keys, + quote_keys, trailing_commas, + allow_duplicate_keys, seen, level, + item_sep, kv_sep, indent_str, end_str) + elif hasattr(t, '__getitem__') and hasattr(t, '__iter__'): + s = _dump_array(obj, skipkeys, ensure_ascii, + check_circular, allow_nan, indent, + separators, default, sort_keys, + quote_keys, trailing_commas, + allow_duplicate_keys, seen, level, + item_sep, indent_str, end_str) + else: + s = default(obj) - return kwargs.get('default', _raise_type_error)(obj) + if seen is not None: + seen.remove(i) + return False, s -def _dump_dict(obj, seen, item_sep, kv_sep, indent_str, end_str, **kwargs): +def _dump_dict(obj, skipkeys, ensure_ascii, check_circular, allow_nan, + indent, separators, default, sort_keys, + quote_keys, trailing_commas, allow_duplicate_keys, + seen, level, item_sep, kv_sep, indent_str, end_str): if not obj: return u'{}' - if kwargs.get('sort_keys', False): + if sort_keys: keys = sorted(obj.keys()) else: keys = obj.keys() s = u'{' + indent_str - skipkeys = kwargs.get('skipkeys', False) - ensure_ascii = kwargs.get('ensure_ascii', True) - quote_keys = kwargs.get('quote_keys', False) - first_item = True + num_items_added = 0 + new_keys = set() for key in keys: - valid_key, key_str = _dumpkey(key, ensure_ascii, quote_keys) + valid_key, key_str = _dumps(key, skipkeys, ensure_ascii, check_circular, + allow_nan, indent, separators, default, + sort_keys, + quote_keys, trailing_commas, + allow_duplicate_keys, + seen, level, is_key=True) if valid_key: - if not first_item: + if not allow_duplicate_keys: + if key_str in new_keys: + raise ValueError('duplicate key %s' % repr(key)) + else: + new_keys.add(key_str) + if num_items_added: s += item_sep - s += key_str + kv_sep + _dumps(obj[key], seen, **kwargs) - first_item = False - elif skipkeys: - continue - else: + s += key_str + kv_sep + _dumps(obj[key], skipkeys, ensure_ascii, + check_circular, allow_nan, indent, + separators, default, sort_keys, + quote_keys, trailing_commas, + allow_duplicate_keys, + seen, level, is_key=False)[1] + num_items_added += 1 + elif not skipkeys: raise TypeError('invalid key %s' % repr(key)) + s += end_str + u'}' return s +def _dump_array(obj, skipkeys, ensure_ascii, check_circular, allow_nan, + indent, separators, default, sort_keys, + quote_keys, trailing_commas, allow_duplicate_keys, + seen, level, item_sep, indent_str, end_str): + if not obj: + return u'[]' + return (u'[' + indent_str + + item_sep.join([_dumps(el, skipkeys, ensure_ascii, check_circular, + allow_nan, indent, separators, default, + sort_keys, quote_keys, trailing_commas, + allow_duplicate_keys, + seen, level, False)[1] for el in obj]) + + end_str + u']') + + def _dump_float(obj, allow_nan): if allow_nan: if math.isnan(obj): @@ -304,14 +396,6 @@ return str(obj) -def _dumpkey(k, ensure_ascii, quote_keys): - if type(k) in (int, float, type(''), long, type(u'')) or k is None: - if not quote_keys and _is_ident(k) and not _is_reserved_word(k): - return True, k - return True, _dump_str(k, ensure_ascii) - return False, '' - - def _dump_str(obj, ensure_ascii): ret = ['"'] for ch in obj: @@ -355,13 +439,14 @@ def _is_ident(k): k = str(k) - if not _is_id_start(k[0]) and k[0] not in (u'$', u'_'): + if not k or not _is_id_start(k[0]) and k[0] not in (u'$', u'_'): return False for ch in k[1:]: if not _is_id_continue(ch) and ch not in (u'$', u'_'): return False return True + def _is_id_start(ch): return unicodedata.category(ch) in ( 'Lu', 'Ll', 'Li', 'Lt', 'Lm', 'Lo', 'Nl') @@ -379,7 +464,7 @@ if _reserved_word_re is None: # List taken from section 7.6.1 of ECMA-262. - _reserved_word_re = re.compile('|'.join([ + _reserved_word_re = re.compile('(' + '|'.join([ 'break', 'case', 'catch', @@ -416,7 +501,7 @@ 'void', 'while', 'with', - ])) + ]) + ')$') return _reserved_word_re.match(k) is not None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyjson5-0.8.5/json5/version.py new/pyjson5-0.9.4/json5/version.py --- old/pyjson5-0.8.5/json5/version.py 2019-07-05 04:18:45.000000000 +0200 +++ new/pyjson5-0.9.4/json5/version.py 2020-03-27 00:12:33.000000000 +0100 @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -VERSION = '0.8.5' +VERSION = '0.9.4' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyjson5-0.8.5/setup.py new/pyjson5-0.9.4/setup.py --- old/pyjson5-0.8.5/setup.py 2019-07-05 04:18:45.000000000 +0200 +++ new/pyjson5-0.9.4/setup.py 2020-03-27 00:12:33.000000000 +0100 @@ -29,8 +29,7 @@ setup( name='json5', - packages=find_packages(), - package_data={'': ['../README.md']}, + packages=find_packages(exclude=['tests']), entry_points={ 'console_scripts': [ 'pyjson5=json5.tool:main', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyjson5-0.8.5/tests/lib_test.py new/pyjson5-0.9.4/tests/lib_test.py --- old/pyjson5-0.8.5/tests/lib_test.py 2019-07-05 04:18:45.000000000 +0200 +++ new/pyjson5-0.9.4/tests/lib_test.py 2020-03-27 00:12:33.000000000 +0100 @@ -245,24 +245,56 @@ def check(self, obj, s): self.assertEqual(json5.dumps(obj), s) + def test_allow_duplicate_keys(self): + self.assertIn(json5.dumps({1: "foo", "1": "bar"}), + {'{"1": "foo", "1": "bar"}', + '{"1": "bar", "1": "foo"}'}) + + self.assertRaises(ValueError, json5.dumps, + {1: "foo", "1": "bar"}, + allow_duplicate_keys=False) + def test_arrays(self): self.check([], '[]') self.check([1, 2, 3], '[1, 2, 3]') + self.check([{'foo': 'bar'}, {'baz': 'quux'}], + '[{foo: "bar"}, {baz: "quux"}]') def test_bools(self): self.check(True, 'true') self.check(False, 'false') def test_check_circular(self): + # This tests a trivial cycle. l = [1, 2, 3] l[2] = l self.assertRaises(ValueError, json5.dumps, l) + + # This checks that json5 doesn't raise an error. However, + # the underlying Python implementation likely will. try: json5.dumps(l, check_circular=False) self.fail() # pragma: no cover except Exception as e: self.assertNotIn(str(e), 'Circular reference detected') + # This checks that repeated but non-circular references + # are okay. + x = [1, 2] + y = {"foo": x, "bar": x} + self.check(y, + '{foo: [1, 2], bar: [1, 2]}') + + # This tests a more complicated cycle. + x = {} + y = {} + z = {} + z['x'] = x + z['y'] = y + z['x']['y'] = y + z['y']['x'] = x + self.assertRaises(ValueError, json5.dumps, z) + def test_default(self): def _custom_serializer(obj): @@ -293,6 +325,8 @@ u'[\n 1,\n 2,\n 3,\n]') self.assertEqual(json5.dumps([1, 2, 3], indent='++'), u'[\n++1,\n++2,\n++3,\n]') + self.assertEqual(json5.dumps([[1, 2, 3]], indent=2), + u'[\n [\n 1,\n 2,\n 3,\n ],\n]') self.assertEqual(json5.dumps({}, indent=2), u'{}') @@ -320,6 +354,13 @@ def test_reserved_words_in_object_keys_are_quoted(self): self.check({'new': 1}, '{"new": 1}') + def test_identifiers_only_starting_with_reserved_words_are_not_quoted(self): + self.check({'newbie': 1}, '{newbie: 1}') + + def test_non_string_keys(self): + self.assertEqual(json5.dumps({False: 'a', 1: 'b', 2.0: 'c', None: 'd'}), + '{"false": "a", "1": "b", "2.0": "c", "null": "d"}') + def test_quote_keys(self): self.assertEqual(json5.dumps({"foo": 1}, quote_keys=True), '{"foo": 1}') @@ -335,9 +376,21 @@ '"\\u2028\\u2029\\b\\t\\f\\n\\r\\v\\\\\\0"') def test_skip_keys(self): - self.assertRaises(TypeError, json5.dumps, {"foo": 1, (1, 2): 2}) - self.assertEqual(json5.dumps({"foo": 1, (1, 2): 2}, skipkeys=True), - '{foo: 1}') + od = OrderedDict() + od[(1, 2)] = 2 + self.assertRaises(TypeError, json5.dumps, od) + self.assertEqual(json5.dumps(od, skipkeys=True), '{}') + + od['foo'] = 1 + self.assertEqual(json5.dumps(od, skipkeys=True), '{foo: 1}') + + # Also test that having an invalid key as the last element + # doesn't incorrectly add a trailing comma (see + # https://github.com/dpranke/pyjson5/issues/33). + od = OrderedDict() + od['foo'] = 1 + od[(1, 2)] = 2 + self.assertEqual(json5.dumps(od, skipkeys=True), '{foo: 1}') def test_sort_keys(self): od = OrderedDict() @@ -369,6 +422,9 @@ # we can't test this there. pass + def test_empty_key(self): + self.assertEqual(json5.dumps({'': 'value'}), '{"": "value"}') + if __name__ == '__main__': # pragma: no cover unittest.main()
