diff --git a/docs/index.rst b/docs/index.rst index c1a16a34cdf1f7c9b05368e86727fd4c564c2a48..0c4df873eab48403e4b7d00302e43aadc3a649ae 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -20,9 +20,6 @@ whose all keys are strings. You should avoid objects with keys different than strings, since they will always use a 4-byte length field. This is to be improved in a future release. -.. warning:: Take care for your data to be without cycles. Feeding the encoder cycles - will probably dump your interpreter's core. - Indices and tables ================== diff --git a/docs/usage.rst b/docs/usage.rst index 3b52e3f2047216880832ce6a31ea8c04a2577b6d..2685b863e69b0449d63420c5d77b4d07fb9ae054 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -1,6 +1,9 @@ Usage ===== +.. warning:: Take care for your data to be without cycles. Feeding the encoder cycles + will probably dump your interpreter's core. + MiniJSON implements the same interface as json or yaml, namely: .. warning:: Cycles are not automatically detected. They might make the application hang diff --git a/minijson.pyx b/minijson.pyx index b996151207dcc66078c6c418247934122cc5cdb1..156d2c65338f3eb3cc089a6c5246f776c7f4f3ba 100644 --- a/minijson.pyx +++ b/minijson.pyx @@ -317,27 +317,27 @@ cdef class MiniJSONEncoder: """ cdef: object _default - bint use_double + public bint use_double def __init__(self, default: tp.Optional[None] = None, - use_double: bool = False): + bint use_double = False): self._default = default self.use_double = use_double - cpdef bint should_double_be_used(self, double x): + def should_double_be_used(self, y) -> bool: """ A function that you are meant to overload that will decide on a per-case basis which representation should be used for given number. - - :param x: number to check + + :param y: number to check :return: True if double should be used, else False """ return self.use_double - cpdef default(self, v): + def default(self, v): """ Convert an object to a JSON-able representation. - + Overload this to provide your default function in other way that giving the callable as a parameter. @@ -512,12 +512,19 @@ cdef class MiniJSONEncoder: return offset else: v = self.default(data) + if not is_jsonable(v): + raise EncodingError('default returned a non-JSONable value!') return self.dump(v, cio) -cpdef int dump(object data, cio: io.BytesIO, default: tp.Callable) except -1: +cpdef int dump(object data, cio: io.BytesIO, default: tp.Optional[tp.Callable] = None) except -1: """ - Write an object to a stream + Write an object to a stream. + + Note that this will load the initial value of current default float encoding mode and remember + it throughout the streaming process, so you can't change it mid-value. + + To do so, please use :class:`~minijson.MiniJSONEncoder` :param data: object to write :param cio: stream to write to @@ -533,8 +540,13 @@ cpdef int dump(object data, cio: io.BytesIO, default: tp.Callable) except -1: cpdef bytes dumps(object data, default: tp.Optional[tp.Callable] = None): """ - Serialize given data to a MiniJSON representation + Serialize given data to a MiniJSON representation. + Note that this will load the initial value of current default float encoding mode and remember + it throughout the streaming process, so you can't change it mid-value. + + To do so, please use :class:`~minijson.MiniJSONEncoder` + :param data: data to serialize :param default: a function that should be used to convert non-JSONable objects to JSONable ones. Default, None, will raise an EncodingError upon encountering such a value @@ -552,6 +564,11 @@ cpdef bytes dumps_object(object data, default: tp.Optional[tp.Callable] = None): Note that subobject's :code:`__dict__` will not be copied. Use default for that. + Note that this will load the initial value of current default float encoding mode and remember + it throughout the streaming process, so you can't change it mid-value. + + To do so, please use :class:`~minijson.MiniJSONEncoder` + :param data: object to dump :param default: a function that should be used to convert non-JSONable objects to JSONable ones. Default, None, will raise an EncodingError upon encountering such a value diff --git a/setup.cfg b/setup.cfg index c840efff012fd3d8fce4e13d13a13d12052240ff..a0f4d8507f57be6a2cbf45eb8ed2a38fdc693690 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ # coding: utf-8 [metadata] -version = 2.5a1 +version = 2.5 name = minijson long_description = file: README.md long_description_content_type = text/markdown; charset=UTF-8 diff --git a/tests/test.sh b/tests/test.sh index 8b496fd88bf8d2ee44fb4d3f5287df609ef4c97f..f62c46f046e55340b0e5b67225882df7e15283f3 100644 --- a/tests/test.sh +++ b/tests/test.sh @@ -1,4 +1,4 @@ #!/bin/bash -pytest --cov=./ --cov-report=xml +pytest --cov=./ --cov-report=xml -vv coverage report diff --git a/tests/test_minijson.py b/tests/test_minijson.py index 4d3f2a8247969c5d90b43bc3ab8cc20a6e6f328f..a4e10d58f091201a69b69886d6e721c05f3c4a17 100644 --- a/tests/test_minijson.py +++ b/tests/test_minijson.py @@ -58,7 +58,17 @@ class TestMiniJSON(unittest.TestCase): a = Subclass({1: 2, 3: 4}) b = dumps(a) - self.assertEquals(loads(b), {1: 2, 3: 4}) + self.assertEqual(loads(b), {1: 2, 3: 4}) + + def test_should_double_be_used(self): + class Encoder(MiniJSONEncoder): + def should_double_be_used(self, y): + return y == 0 + + e = Encoder() + + self.assertEqual(len(e.encode(0.0)), 9) + self.assertEqual(len(e.encode(1.0)), 5) def test_subclasses_of_lists(self): """Assert that you can correctly serialize subclasses of list""" @@ -67,7 +77,7 @@ class TestMiniJSON(unittest.TestCase): a = Subclass([1, 2, 3]) b = dumps(a) - self.assertEquals(loads(b), [1, 2, 3]) + self.assertEqual(loads(b), [1, 2, 3]) def test_subclasses_of_tuples(self): """Assert that you can correctly serialize subclasses of tuple""" @@ -76,7 +86,7 @@ class TestMiniJSON(unittest.TestCase): a = Subclass((1, 2, 3)) b = dumps(a) - self.assertEquals(loads(b), [1, 2, 3]) + self.assertEqual(loads(b), [1, 2, 3]) def test_malformed(self): """Test unserializing malformed strings yields DecodingError"""