diff --git a/README.rst b/README.rst index 5cf41fe..f2c46bf 100644 --- a/README.rst +++ b/README.rst @@ -227,6 +227,8 @@ As a note on performance_, both dicts and OrderedDicts have the same scaling for Comments +++++++++++++++++++++++++++++++++++++++ +*Warning: in the next major version, comment parsing will be opt-in, not default anymore (for performance reasons). Update your code now to pass `ignore_comments=True` explicitly if you want comment parsing.* + This package uses ``#`` and ``//`` for comments, which seem to be the most common conventions, though only the latter is valid javascript. For example, you could call ``loads`` on the following string:: diff --git a/json_tricks/_version.py b/json_tricks/_version.py index 28aa50a..2da49a6 100644 --- a/json_tricks/_version.py +++ b/json_tricks/_version.py @@ -1,3 +1,3 @@ -VERSION = '3.15.0' +VERSION = '3.15.1' diff --git a/json_tricks/nonp.py b/json_tricks/nonp.py index 0aafa95..39f1980 100644 --- a/json_tricks/nonp.py +++ b/json_tricks/nonp.py @@ -1,9 +1,9 @@ - +import warnings from json import loads as json_loads from os import fsync from sys import exc_info -from json_tricks.utils import is_py3, dict_default, gzip_compress, gzip_decompress +from json_tricks.utils import is_py3, dict_default, gzip_compress, gzip_decompress, JsonTricksDeprecation from .utils import str_type, NoNumpyException # keep 'unused' imports from .comment import strip_comments # keep 'unused' imports #TODO @mark: imports removed? @@ -176,7 +176,7 @@ def dump(obj, fp, sort_keys=None, cls=TricksEncoder, obj_encoders=DEFAULT_ENCODE return txt -def loads(string, preserve_order=True, ignore_comments=True, decompression=None, obj_pairs_hooks=DEFAULT_HOOKS, +def loads(string, preserve_order=True, ignore_comments=None, decompression=None, obj_pairs_hooks=DEFAULT_HOOKS, extra_obj_pairs_hooks=(), cls_lookup_map=None, allow_duplicates=True, conv_str_byte=False, **jsonkwargs): """ Convert a nested data structure to a json string. @@ -212,8 +212,16 @@ def loads(string, preserve_order=True, ignore_comments=True, decompression=None, 'for example bytevar.encode("utf-8") if utf-8 is the encoding. Alternatively you can ' 'force an attempt by passing conv_str_byte=True, but this may cause decoding issues.') .format(type(string))) - if ignore_comments: - string = strip_comments(string) + if ignore_comments or ignore_comments is None: + new_string = strip_comments(string) + if ignore_comments is None and not getattr(loads, '_ignore_comments_warned', False) and string != new_string: + warnings.warn('`json_tricks.load(s)` stripped some comments, but `ignore_comments` was ' + 'not passed; in the next major release, the behaviour when `ignore_comments` is not ' + 'passed will change; it is recommended to explicitly pass `ignore_comments=True` if ' + 'you want to strip comments; see https://github.com/mverleg/pyjson_tricks/issues/74', + JsonTricksDeprecation) + loads._ignore_comments_warned = True + string = new_string obj_pairs_hooks = tuple(obj_pairs_hooks) _cih_instance.cls_lookup_map = cls_lookup_map or {} _eih_instance.cls_lookup_map = cls_lookup_map or {} @@ -222,7 +230,7 @@ def loads(string, preserve_order=True, ignore_comments=True, decompression=None, return json_loads(string, object_pairs_hook=hook, **jsonkwargs) -def load(fp, preserve_order=True, ignore_comments=True, decompression=None, obj_pairs_hooks=DEFAULT_HOOKS, +def load(fp, preserve_order=True, ignore_comments=None, decompression=None, obj_pairs_hooks=DEFAULT_HOOKS, extra_obj_pairs_hooks=(), cls_lookup_map=None, allow_duplicates=True, conv_str_byte=False, **jsonkwargs): """ Convert a nested data structure to a json string. diff --git a/tests/test_bare.py b/tests/test_bare.py index a213174..d1d3091 100644 --- a/tests/test_bare.py +++ b/tests/test_bare.py @@ -12,12 +12,13 @@ from os.path import join from tempfile import mkdtemp +from _pytest.recwarn import warns from pytest import raises, fail from json_tricks import fallback_ignore_unknown, DuplicateJsonKeyException from json_tricks.nonp import strip_comments, dump, dumps, load, loads, \ ENCODING -from json_tricks.utils import is_py3, gzip_compress +from json_tricks.utils import is_py3, gzip_compress, JsonTricksDeprecation from .test_class import MyTestCls, CustomEncodeCls, SubClass, SuperClass, SlotsBase, SlotsDictABC, SlotsStr, \ SlotsABCDict, SlotsABC @@ -143,6 +144,12 @@ def test_file_path(): } """ +test_object_for_comment_strings = { + "hello": "Wor#d", "Bye": "\"M#rk\"", "yes\\\"": 5, + "quote": "\"th#t's\" what she said", + "list": [1, 1, "#", "\"", "\\", 8], "dict": {"q": 7} +} + test_json_duplicates = """{"test": 42, "test": 37}""" @@ -153,6 +160,45 @@ def test_strip_comments(): assert valid == test_json_without_comments.replace('#', '//') +def test_ignore_comments_deprecation(): + # https://github.com/mverleg/pyjson_tricks/issues/74 + + # First time should have deprecation warning + loads._ignore_comments_warned_ = False + with warns(JsonTricksDeprecation): + loads(test_json_with_comments) + + # Second time there should be no warning + # noinspection PyTypeChecker + with warns(None) as captured: + loaded = loads(test_json_with_comments) + assert len(captured) == 0 + assert loaded == test_object_for_comment_strings + + # Passing a string without comments should not have a warning + loads._ignore_comments_warned_ = False + # noinspection PyTypeChecker + with warns(None) as captured: + loaded = loads(test_json_without_comments) + assert len(captured) == 0 + + # Passing True for argument explicitly should not have a warning + loads._ignore_comments_warned_ = False + # noinspection PyTypeChecker + with warns(None) as captured: + loaded = loads(test_json_with_comments, ignore_comments=True) + assert len(captured) == 0 + assert loaded == test_object_for_comment_strings + + # Passing False for argument explicitly should not have a warning + loads._ignore_comments_warned_ = False + # noinspection PyTypeChecker + with warns(None) as captured: + loaded = loads(test_json_without_comments, ignore_comments=False) + assert len(captured) == 0 + assert loaded == test_object_for_comment_strings + + ordered_map = OrderedDict(( ('elephant', None), ('chicken', None), diff --git a/tests/test_np.py b/tests/test_np.py index 22520c0..8b37308 100644 --- a/tests/test_np.py +++ b/tests/test_np.py @@ -11,7 +11,6 @@ float16, float32, float64, complex64, complex128, zeros, ndindex from numpy.core.umath import exp from numpy.testing import assert_equal -from pytest import raises from json_tricks import numpy_encode from json_tricks.np import dump, dumps, load, loads