From 1810554927c8cc5b6d150b4aaa121985362a2ccc Mon Sep 17 00:00:00 2001 From: Ales Teska Date: Tue, 6 Apr 2021 19:12:46 +0200 Subject: [PATCH] Experimental implementation of the On Demand API. --- cysimdjson/cysimdjson.pyx | 447 ++++++++++--------------------- cysimdjson/jsoninter.h | 167 +++--------- perftest/test_benchmark.py | 16 +- test/test_array/__init__.py | 18 +- test/test_document/__init__.py | 39 +++ test/test_document/document.json | 8 +- 6 files changed, 245 insertions(+), 450 deletions(-) diff --git a/cysimdjson/cysimdjson.pyx b/cysimdjson/cysimdjson.pyx index 66b9841..a9f5ddc 100644 --- a/cysimdjson/cysimdjson.pyx +++ b/cysimdjson/cysimdjson.pyx @@ -28,316 +28,193 @@ cdef extern from "simdjson/simdjson.h" namespace "simdjson": SIMDJSON_VERSION_MINOR SIMDJSON_VERSION_REVISION + cdef enum simdjson_json_type "simdjson::ondemand::json_type": + json_type_array "simdjson::ondemand::json_type::array", + json_type_object "simdjson::ondemand::json_type::object", + json_type_number "simdjson::ondemand::json_type::number", + json_type_string "simdjson::ondemand::json_type::string", + json_type_boolean "simdjson::ondemand::json_type::boolean", + json_type_null "simdjson::ondemand::json_type::null" -cdef extern from "simdjson/simdjson.h" namespace "simdjson::dom": - cdef cppclass simdjson_object "simdjson::dom::object": +cdef extern from "simdjson/simdjson.h" namespace "simdjson::ondemand": - cppclass iterator: - iterator() - simdjson_object operator*() - iterator operator++() - bint operator==(iterator) - bint operator!=(iterator) + cdef cppclass simdjson_value "simdjson::ondemand::value": - string_view key() - uint32_t key_length() - const char *key_c_str() - simdjson_element value() + simdjson_value() - simdjson_object() + simdjson_json_type type() except +simdjson_error_handler + bool get_bool() except +simdjson_error_handler - iterator begin() - iterator end() - size_t size() + cdef cppclass simdjson_array "simdjson::ondemand::array": - simdjson_element at_pointer(const char*) except +simdjson_error_handler - simdjson_element operator[](const char*) except +simdjson_error_handler + simdjson_array() + simdjson_array_iterator begin() + simdjson_array_iterator end() - cdef cppclass simdjson_array "simdjson::dom::array": - cppclass iterator: - iterator() - - operator++() - bint operator!=(iterator) - simdjson_element operator*() + cdef cppclass simdjson_array_iterator "simdjson::ondemand::array_iterator": - simdjson_array() - - iterator begin() - iterator end() + simdjson_array_iterator() + + operator++() + bint operator!=(simdjson_array_iterator) + bint operator==(simdjson_array_iterator) + simdjson_value operator*() - size_t size() - size_t number_of_slots() - # simd_element at(int) except +simdjson_error_handler - # simd_element at_pointer(const char*) except +simdjson_error_handler + cdef cppclass simdjson_object "simdjson::ondemand::object": + simdjson_object() - cdef cppclass simdjson_element "simdjson::dom::element": + simdjson_value find_field(const char *key) except +simdjson_error_handler - simdjson_element() - simdjson_element_type type() except +simdjson_error_handler + cdef cppclass simdjson_document "simdjson::ondemand::document": - const char *get_c_str() except +simdjson_error_handler - size_t get_string_length() except +simdjson_error_handler + simdjson_document() - simdjson_array get_array() except +simdjson_error_handler - simdjson_element get_object() except +simdjson_error_handler + simdjson_json_type type() except +simdjson_error_handler + bool get_bool() except +simdjson_error_handler - cdef cppclass simdjson_parser "simdjson::dom::parser": + cdef cppclass simdjson_parser "simdjson::ondemand::parser": simdjson_parser() simdjson_parser(size_t max_capacity) - simdjson_element load(string) except + simdjson_error_handler - simdjson_element parse(const char * buf, size_t len, bool realloc_if_needed) except + simdjson_error_handler - - -cdef extern from "simdjson/simdjson.h" namespace "simdjson::dom::element_type": - cdef enum simdjson_element_type "simdjson::dom::element_type": - OBJECT, - ARRAY, - STRING, - INT64, - UINT64, - DOUBLE, - BOOL, - NULL_VALUE + simdjson_document iterate(const char * buf, size_t len, bool realloc_if_needed) except + simdjson_error_handler cdef extern from "jsoninter.h": - cdef int getitem_from_object(simdjson_object & object, string & key, simdjson_element & value) except + simdjson_error_handler - cdef int getitem_from_array(simdjson_array & array, int key, simdjson_element & value) except + simdjson_error_handler + PyObject * string_view_to_python_string(string_view & sv) + string get_active_implementation() - cdef int at_pointer_object(simdjson_object & element, string & key, simdjson_element & value) except + simdjson_error_handler - cdef int at_pointer_array(simdjson_array & array, string & key, simdjson_element & value) except + simdjson_error_handler + void parser_helper_iterate(simdjson_document document, simdjson_parser Parser, char * data_ptr, Py_ssize_t pysize, Py_ssize_t padding) + + void document_helper_to_object(simdjson_document document, simdjson_object obj) except + simdjson_error_handler + void document_helper_to_array(simdjson_document document, simdjson_array arr) except + simdjson_error_handler + cdef object document_helper_to_py_string(simdjson_document & document) except + simdjson_error_handler + cdef object document_helper_to_py_number(simdjson_document & document) except + simdjson_error_handler - cdef bool compare_type(simdjson_element_type a, simdjson_element_type b) except + simdjson_error_handler - cdef object to_string(simdjson_element & value, int * ok) except + simdjson_error_handler - cdef object to_int64(simdjson_element & value, int * ok) except + simdjson_error_handler - cdef object to_uint64(simdjson_element & value, int * ok) except + simdjson_error_handler - cdef object to_double(simdjson_element & value, int * ok) except + simdjson_error_handler - cdef object to_bool(simdjson_element & value, int * ok) except + simdjson_error_handler + void value_helper_to_object(simdjson_value & value, simdjson_object obj) except + simdjson_error_handler + void value_helper_to_array(simdjson_value & value, simdjson_array arr) except + simdjson_error_handler + cdef object value_helper_to_py_string(simdjson_value & value) except + simdjson_error_handler + cdef object value_helper_to_py_number(simdjson_value & value) except + simdjson_error_handler - cdef simdjson_array to_array(simdjson_element & value, int * ok) except + simdjson_error_handler - cdef simdjson_object to_object(simdjson_element & value, int * ok) except + simdjson_error_handler - PyObject * string_view_to_python_string(string_view & sv) - string get_active_implementation() +cdef class JSONArray: + cdef: + JSONDocument Document + simdjson_array Array + int Length -cdef class JSONArray: - cdef simdjson_array Array + def __cinit__(self, document): + self.Document = document + self.Length = -1 - def __cinit__(JSONArray self): - self.Array = simdjson_array() + def __iter__(JSONArray self): + + cdef simdjson_array_iterator it = self.Array.begin() + cdef simdjson_array_iterator it_end = self.Array.end() + cdef simdjson_value value - @staticmethod - cdef inline JSONArray build_JSONArray(simdjson_element value): - cdef JSONArray self = JSONArray.__new__(JSONArray) - cdef int ok - self.Array = to_array(value, &ok) - if ok != 0: - raise ValueError() - return self + while it != it_end: + value = dereference(it) + yield _unwrap_value(self.Document, value) + preincrement(it) def __contains__(JSONArray self, item): - # This is a full scan - for i in range(len(self)): - if self[i] == item: + # Full scan + for i in self: + if i == item: return True return False - def __getitem__(JSONArray self, key: int): - cdef simdjson_element v - ok = getitem_from_array(self.Array, key, v) - if ok != 0: - raise IndexError("Not found '{}'".format(key)) - return _wrap_element(v) - - def __len__(JSONArray self): - return self.Array.size() - - - def __iter__(JSONArray self): + #TODO: Once ready in SIMDJSON: return self.Array.size() - cdef simdjson_array.iterator it = self.Array.begin() - cdef simdjson_array.iterator it_end = self.Array.end() - - cdef simdjson_element element + if self.Length >= 0: + return self.Length + cdef int cnt = 0 + + cdef simdjson_array_iterator it = self.Array.begin() + cdef simdjson_array_iterator it_end = self.Array.end() while it != it_end: - element = dereference(it) - yield _wrap_element(element) + cnt += 1 preincrement(it) + self.Length = cnt - def at_pointer(JSONArray self, key): - cdef simdjson_element v - cdef int ok - - key_raw = key.encode('utf-8') - ok = at_pointer_array(self.Array, key_raw, v) - if ok != 0: - raise KeyError("Not found '{}'".format(key)) - - return _wrap_element(v) + return cnt cdef class JSONObject: - cdef simdjson_object Object - - - def __cinit__(JSONObject self): - self.Object = simdjson_object() - - - @staticmethod - cdef inline JSONObject build_JSONObject(simdjson_element value): - cdef JSONObject self = JSONObject.__new__(JSONObject) - cdef int ok - self.Object = to_object(value, &ok) - if ok != 0: - raise ValueError() - return self - - - def __contains__(JSONObject self, key): - cdef simdjson_element v - cdef int ok - key_raw = key.encode('utf-8') - ok = getitem_from_object(self.Object, key_raw, v) - return ok == 0 - - - def __iter__(self): - for _key in self.keys(): - yield _key - - - def items(self): - cdef int ok - cdef string_view sv - cdef simdjson_element v + cdef: + JSONDocument Document + simdjson_object Object - cdef simdjson_object.iterator it = self.Object.begin() - while it != self.Object.end(): - sv = it.key() - v = it.value() - yield string_view_to_python_string(sv), _wrap_element(v) - preincrement(it) + def __cinit__(self, document): + self.Document = document def __getitem__(JSONObject self, key): - cdef simdjson_element v - cdef int ok - key_raw = key.encode('utf-8') - ok = getitem_from_object(self.Object, key_raw, v) - if ok != 0: - raise KeyError("Not found '{}'".format(key)) - - return _wrap_element(v) - - - def __len__(JSONObject self): - cdef int ok - cdef string_view sv - - return self.Object.size() - - - def keys(JSONObject self): - cdef int ok - cdef string_view sv - - cdef simdjson_object.iterator it = self.Object.begin() - while it != self.Object.end(): - sv = it.key() - yield string_view_to_python_string(sv) - preincrement(it) - - - def at_pointer(JSONObject self, key): - cdef simdjson_element v - cdef int ok - - key_raw = key.encode('utf-8') - ok = at_pointer_object(self.Object, key_raw, v) - if ok != 0: - raise KeyError("Not found '{}'".format(key)) - - return _wrap_element(v) - - -cdef class JSONObjectDocument(JSONObject): - ''' - Represents a top-level JSON object (dictionary). - ''' - cdef object Data - cdef simdjson_element Element + cdef simdjson_value value + value = self.Object.find_field(key_raw) + return _unwrap_value(self.Document, value) - def __cinit__(JSONObjectDocument self): - self.Data = None +cdef class JSONDocument: -cdef inline JSONObjectDocument _build_JSONObjectDocument(simdjson_element element, object data): - cdef JSONObjectDocument self = JSONObjectDocument.__new__(JSONObjectDocument) - - cdef int ok - self.Object = to_object(element, &ok) - if ok != 0: - raise ValueError("Not an JSON object.") - - self.Element = element - self.Data = data - - return self - + cdef: + simdjson_document Document -cdef class JSONArrayDocument(JSONArray): - ''' - Represents a top-level JSON array. - ''' - cdef object Data - cdef simdjson_element Element + cdef get(JSONDocument self): + ''' + Get top-level object + ''' + cdef simdjson_json_type json_type = self.Document.type() + if json_type == json_type_object: + json_object = JSONObject(self) + document_helper_to_object(self.Document, json_object.Object) + return json_object - def __cinit__(JSONArrayDocument self): - self.Data = None + if json_type == json_type_array: + json_array = JSONArray(self) + document_helper_to_array(self.Document, json_array.Array) + return json_array + if json_type == json_type_number: + return document_helper_to_py_number(self.Document) -cdef inline JSONArrayDocument _build_JSONArrayDocument(simdjson_element element, object data): - cdef JSONArrayDocument self = JSONArrayDocument.__new__(JSONArrayDocument) + if json_type == json_type_string: + return document_helper_to_py_string(self.Document) - cdef int ok - self.Array = to_array(element, &ok) - if ok != 0: - raise ValueError("Not an JSON array.") + if json_type == json_type_boolean: + return self.Document.get_bool() - self.Element = element - self.Data = data + if json_type == json_type_null: + return None - return self + raise ValueError("Unknown JSON type") cdef class JSONParser: @@ -346,111 +223,71 @@ cdef class JSONParser: simdjson_parser Parser - def __cinit__(self, max_capacity=None): - if max_capacity is not None: - self.Parser = simdjson_parser.simdjson_parser(int(max_capacity)) - else: - self.Parser = simdjson_parser.simdjson_parser() + def __cinit__(self): + pass - def parse(self, event): + def parse(self, json): + json = json + b' ' * SIMDJSON_PADDING + cdef Py_ssize_t pysize cdef char * data_ptr - cdef int rc = PyBytes_AsStringAndSize(event, &data_ptr, &pysize) + cdef int rc = PyBytes_AsStringAndSize(json, &data_ptr, &pysize) if rc == -1: raise RuntimeError("Failed to get raw data") - cdef simdjson_element element = self.Parser.parse(data_ptr, pysize, 1) - return self._build(element, event) + doc = JSONDocument() + parser_helper_iterate(doc.Document, self.Parser, data_ptr, pysize, SIMDJSON_PADDING) + return doc.get() - def parse_in_place(self, event): + def parse_in_place(self, json, padding: int): ''' Skip the reallocation of the input event buffer. This method is little bit faster than parse() but you have to ensure proper padding of the event. ''' cdef Py_ssize_t pysize cdef char * data_ptr - cdef int rc = PyBytes_AsStringAndSize(event, &data_ptr, &pysize) + cdef int rc = PyBytes_AsStringAndSize(json, &data_ptr, &pysize) if rc == -1: raise RuntimeError("Failed to get raw data") - cdef simdjson_element element = self.Parser.parse(data_ptr, pysize, 0) - return self._build(element, event) - + doc = JSONDocument() + parser_helper_iterate(doc.Document, self.Parser, data_ptr, pysize, padding) + return doc.get() - def load(self, path): - cdef simdjson_element element = self.Parser.load(path) - return self._build(element, None) + def active_implementation(self): + return get_active_implementation() - cdef _build(self, simdjson_element element, event): - cdef simdjson_element_type et = element.type() - - if compare_type(et, OBJECT): - return _build_JSONObjectDocument(element, event) - elif compare_type(et, ARRAY): - return _build_JSONArrayDocument(element, event) +cdef inline object _unwrap_value(document, simdjson_value v): - else: - return _wrap_element(element) + cdef simdjson_json_type json_type = v.type() + if json_type == json_type_object: + json_object = JSONObject(document) + value_helper_to_object(v, json_object.Object) + return json_object - def active_implementation(self): - return get_active_implementation() + if json_type == json_type_array: + json_array = JSONArray(document) + value_helper_to_array(v, json_array.Array) + return json_array + if json_type == json_type_number: + return value_helper_to_py_number(v) -cdef inline object _wrap_element(simdjson_element v): - cdef int ok - cdef simdjson_element_type et = v.type() - - # String - if compare_type(et, STRING): - o = to_string(v, &ok) - if ok != 0: - raise ValueError() - return o - - # INT64 - if compare_type(et, INT64): - o = to_int64(v, &ok) - if ok != 0: - raise ValueError() - return o - - # DOUBLE - if compare_type(et, DOUBLE): - o = to_double(v, &ok) - if ok != 0: - raise ValueError() - return o - - # NULL / None - if compare_type(et, NULL_VALUE): - return None - - # UINT64 - if compare_type(et, UINT64): - o = to_uint64(v, &ok) - if ok != 0: - raise ValueError() - return o + if json_type == json_type_string: + return value_helper_to_py_string(v) - # BOOL - if compare_type(et, BOOL): - o = to_bool(v, &ok) - if ok != 0: - raise ValueError() - return o + if json_type == json_type_boolean: + return v.get_bool() - if compare_type(et, OBJECT): - return JSONObject.build_JSONObject(v) - - if compare_type(et, ARRAY): - return JSONArray.build_JSONArray(v) + if json_type == json_type_null: + return None - raise ValueError() + raise ValueError("Unknown JSON type") MAXSIZE_BYTES = SIMDJSON_MAXSIZE_BYTES diff --git a/cysimdjson/jsoninter.h b/cysimdjson/jsoninter.h index 5372b3c..8970649 100644 --- a/cysimdjson/jsoninter.h +++ b/cysimdjson/jsoninter.h @@ -3,158 +3,73 @@ using namespace simdjson; - -inline int getitem_from_object(dom::object & obj, const std::string & key, dom::element & value) { - auto error = obj[key].get(value); - if (error) { - return -1; - } - return 0; +inline PyObject * string_view_to_python_string(std::string_view & sv) { + return PyUnicode_FromStringAndSize( + sv.data(), + sv.length() + ); } - -inline int getitem_from_array(dom::array & array, int key, dom::element & value) { - // TODO: Handle negative key - auto error = array.at(key).get(value); - if (error) { - return -1; - } - return 0; +inline std::string get_active_implementation() { + return simdjson::active_implementation->description(); } -inline int at_pointer_object(dom::object & obj, std::string & key, dom::element & value) { - auto error = obj.at_pointer(key).get(value); - if (error) { - return -1; - } - return 0; +inline void parser_helper_iterate(ondemand::document & document, ondemand::parser & parser, char * data_ptr, Py_ssize_t pysize, Py_ssize_t padding) { + document = parser.iterate(data_ptr, pysize, padding); } -inline int at_pointer_array(dom::array & array, std::string & key, dom::element & value) { - auto error = array.at_pointer(key).get(value); - if (error) { - return -1; - } - return 0; +inline void document_helper_to_object(ondemand::document & document, ondemand::object & obj) { + obj = document.get_object(); } +inline void document_helper_to_array(ondemand::document & document, ondemand::array & arr) { + arr = document.get_array(); +} -inline bool compare_type(dom::element_type a, dom::element_type b) { - return a == b; +inline void value_helper_to_object(ondemand::value & value, ondemand::object & obj) { + obj = value.get_object(); } +inline void value_helper_to_array(ondemand::value & value, ondemand::array & arr) { + arr = value.get_array(); +} -inline PyObject * to_string(dom::element & value, int * ok) { - std::string_view dst; - auto error = value.get_string().get(dst); - if (error) { - std::cerr << error << std::endl; - *ok = -1; - return NULL; - } - *ok = 0; +inline PyObject * value_helper_to_py_string(ondemand::value & value) { + std::string_view dst = value.get_string(); return PyUnicode_FromStringAndSize( dst.data(), dst.length() ); } - -inline PyObject * to_int64(dom::element & value, int * ok) { - int64_t dst; - auto error = value.get_int64().get(dst); - if (error) { - std::cerr << error << std::endl; - *ok = -1; - return NULL; - } - - *ok = 0; - return PyLong_FromLongLong(dst); -} - - -inline PyObject * to_double(dom::element & value, int * ok) { - double dst; - auto error = value.get_double().get(dst); - if (error) { - std::cerr << error << std::endl; - *ok = -1; - return NULL; - } - - *ok = 0; - return PyFloat_FromDouble(dst); -} - - -inline PyObject * to_uint64(dom::element & value, int * ok) { - uint64_t dst; - auto error = value.get_uint64().get(dst); - if (error) { - std::cerr << error << std::endl; - *ok = -1; - return NULL; - } - - *ok = 0; - return PyLong_FromUnsignedLongLong(dst); -} - - -inline PyObject * to_bool(dom::element & value, int * ok) { - bool dst; - auto error = value.get_bool().get(dst); - if (error) { - std::cerr << error << std::endl; - *ok = -1; - return NULL; - } - - *ok = 0; - if (dst) - { Py_RETURN_TRUE; } - else - { Py_RETURN_TRUE; } +inline PyObject * document_helper_to_py_string(ondemand::document & value) { + std::string_view dst = value.get_string(); + return PyUnicode_FromStringAndSize( + dst.data(), + dst.length() + ); } -inline dom::array to_array(dom::element & value, int * ok) { - dom::array dst; - auto error = value.get_array().get(dst); - if (error) { - std::cerr << error << std::endl; - *ok = -1; - return dom::array(); +inline PyObject * value_helper_to_py_number(ondemand::value & value) { + try { + int64_t vi64 = value.get_int64(); + return PyLong_FromLongLong(vi64); + } catch(...) { + double dbl = value.get_double(); + return PyFloat_FromDouble(dbl); } - *ok = 0; - return dst; } - -inline dom::object to_object(dom::element & value, int * ok) { - dom::object dst; - auto error = value.get_object().get(dst); - if (error) { - std::cerr << error << std::endl; - *ok = -1; - return dom::object(); +inline PyObject * document_helper_to_py_number(ondemand::document & value) { + try { + int64_t vi64 = value.get_int64(); + return PyLong_FromLongLong(vi64); + } catch(...) { + double dbl = value.get_double(); + return PyFloat_FromDouble(dbl); } - *ok = 0; - return dst; -} - - -inline PyObject * string_view_to_python_string(std::string_view & sv) { - return PyUnicode_FromStringAndSize( - sv.data(), - sv.length() - ); -} - -inline std::string get_active_implementation() { - return simdjson::active_implementation->description(); } diff --git a/perftest/test_benchmark.py b/perftest/test_benchmark.py index 834545d..0eac5ec 100644 --- a/perftest/test_benchmark.py +++ b/perftest/test_benchmark.py @@ -99,20 +99,6 @@ def perftest_cysimdjson_parse(jsonfile, number): ) -def perftest_cysimdjson_pad_parse(jsonfile, number): - import cysimdjson - - with open(jsonfile, 'rb') as f: - jsonb = f.read() + (b' ' * 1024) - - parser = cysimdjson.JSONParser() - - return benchmark( - "cysimdjson pad parse", - lambda: parser.parse_in_place(jsonb), - number=number - ) - def main(): test_set = [ perftest_orjson_parser, @@ -120,7 +106,7 @@ def main(): # perftest_libpy_simdjson_parser, perftest_pythonjson_loads, perftest_cysimdjson_parse, - perftest_cysimdjson_pad_parse, + # perftest_cysimdjson_pad_parse, ] jsonfile = jsonpath / "test.json" diff --git a/test/test_array/__init__.py b/test/test_array/__init__.py index f856d12..6f3f1ea 100644 --- a/test/test_array/__init__.py +++ b/test/test_array/__init__.py @@ -17,9 +17,9 @@ def test_iter_01(self): json_parsed = parser.parse(fo.read()) ar = json_parsed['array'] - self.assertEqual(len(ar), 10) - for i, n in enumerate(ar, 1): - self.assertEqual(i, n) + + self.assertEqual(list(i for i in ar), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + self.assertEqual(list(i for i in ar), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) def test_iter_02(self): @@ -31,3 +31,15 @@ def test_iter_02(self): for i, n in enumerate(json_parsed, 1): self.assertEqual(i, n) + + + def test_len_01(self): + + parser = cysimdjson.JSONParser() + + with open(os.path.join(THIS_DIR, 'array.json'), 'rb') as fo: + json_parsed = parser.parse(fo.read()) + + ar = json_parsed['array'] + self.assertEqual(len(ar), 10) + self.assertEqual(len(ar), 10) diff --git a/test/test_document/__init__.py b/test/test_document/__init__.py index 04cfc06..e11ceaf 100644 --- a/test/test_document/__init__.py +++ b/test/test_document/__init__.py @@ -8,6 +8,45 @@ class JSONDocumentTestCases(unittest.TestCase): + + def test_simple_01(self): + + parser = cysimdjson.JSONParser() + + with open(os.path.join(THIS_DIR, 'document.json'), 'rb') as fo: + json_parsed = parser.parse(fo.read()) + + self.assertEqual(json_parsed['foo'], 'bar') + self.assertEqual(json_parsed['true'], True) + self.assertEqual(json_parsed['false'], False) + self.assertEqual(json_parsed['null'], None) + self.assertEqual(json_parsed['int64'], -1234567890) + self.assertEqual(json_parsed['double'], -1234567890.11) + + self.assertEqual(json_parsed['foo'], 'bar') + + + def test_simple_02(self): + + parser = cysimdjson.JSONParser() + + with open(os.path.join(THIS_DIR, 'document.json'), 'rb') as fo: + json_parsed = parser.parse(fo.read()) + + with self.assertRaises(KeyError): + json_parsed['missing'] + + + def test_simple_03(self): + + parser = cysimdjson.JSONParser() + + with open(os.path.join(THIS_DIR, 'document.json'), 'rb') as fo: + json_parsed = parser.parse(fo.read()) + + self.assertEqual(json_parsed['document']['key4'], 40) + + def test_iter_01(self): parser = cysimdjson.JSONParser() diff --git a/test/test_document/document.json b/test/test_document/document.json index b27864b..e1b67f5 100644 --- a/test/test_document/document.json +++ b/test/test_document/document.json @@ -5,5 +5,11 @@ "key3": "3", "key4": 40, "key5": "50" - } + }, + "foo": "bar", + "true": true, + "false": false, + "null": null, + "int64": -1234567890, + "double": -1234567890.11, }