py: Add native json printing using existing print framework.
Also add start of ujson module with dumps implemented. Enabled in unix and stmhal ports. Test passes on both.
This commit is contained in:
parent
8a9b999f1c
commit
612045f53f
71
extmod/modujson.c
Normal file
71
extmod/modujson.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_PY_UJSON
|
||||
|
||||
STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
|
||||
vstr_t vstr;
|
||||
vstr_init(&vstr, 8);
|
||||
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, &vstr, obj, PRINT_JSON);
|
||||
mp_obj_t ret = mp_obj_new_str(vstr.buf, vstr.len, false);
|
||||
vstr_clear(&vstr);
|
||||
return ret;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_ujson_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ujson) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dumps), (mp_obj_t)&mod_ujson_dumps_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_ujson_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_ujson_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_ujson_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_ujson_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_ujson = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_ujson,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ujson_globals,
|
||||
};
|
||||
|
||||
#endif //MICROPY_PY_UJSON
|
@ -89,3 +89,4 @@ extern struct _dummy_t mp_sys_stderr_obj;
|
||||
// extmod modules
|
||||
extern const mp_obj_module_t mp_module_uctypes;
|
||||
extern const mp_obj_module_t mp_module_zlibd;
|
||||
extern const mp_obj_module_t mp_module_ujson;
|
||||
|
@ -200,6 +200,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
|
||||
#if MICROPY_PY_ZLIBD
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_zlibd), (mp_obj_t)&mp_module_zlibd },
|
||||
#endif
|
||||
#if MICROPY_PY_UJSON
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ujson), (mp_obj_t)&mp_module_ujson },
|
||||
#endif
|
||||
|
||||
// extra builtin modules as defined by a port
|
||||
MICROPY_PORT_BUILTIN_MODULES
|
||||
|
@ -390,6 +390,10 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PY_ZLIBD (0)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_UJSON
|
||||
#define MICROPY_PY_UJSON (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Hooks for a port to add builtins */
|
||||
|
||||
|
3
py/obj.h
3
py/obj.h
@ -187,7 +187,8 @@ typedef enum {
|
||||
PRINT_STR = 0,
|
||||
PRINT_REPR = 1,
|
||||
PRINT_EXC = 2, // Special format for printing exception in unhandled exception message
|
||||
PRINT_EXC_SUBCLASS = 4, // Internal flag for printing exception subclasses
|
||||
PRINT_JSON = 3,
|
||||
PRINT_EXC_SUBCLASS = 0x80, // Internal flag for printing exception subclasses
|
||||
} mp_print_kind_t;
|
||||
|
||||
typedef void (*mp_print_fun_t)(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o, mp_print_kind_t kind);
|
||||
|
14
py/objbool.c
14
py/objbool.c
@ -41,10 +41,18 @@ typedef struct _mp_obj_bool_t {
|
||||
|
||||
STATIC void bool_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_bool_t *self = self_in;
|
||||
if (self->value) {
|
||||
print(env, "True");
|
||||
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
|
||||
if (self->value) {
|
||||
print(env, "true");
|
||||
} else {
|
||||
print(env, "false");
|
||||
}
|
||||
} else {
|
||||
print(env, "False");
|
||||
if (self->value) {
|
||||
print(env, "True");
|
||||
} else {
|
||||
print(env, "False");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,9 @@ STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, mp_uint_t *cur) {
|
||||
STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_dict_t *self = self_in;
|
||||
bool first = true;
|
||||
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
|
||||
kind = PRINT_REPR;
|
||||
}
|
||||
print(env, "{");
|
||||
mp_uint_t cur = 0;
|
||||
mp_map_elem_t *next = NULL;
|
||||
@ -68,9 +71,9 @@ STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env
|
||||
print(env, ", ");
|
||||
}
|
||||
first = false;
|
||||
mp_obj_print_helper(print, env, next->key, PRINT_REPR);
|
||||
mp_obj_print_helper(print, env, next->key, kind);
|
||||
print(env, ": ");
|
||||
mp_obj_print_helper(print, env, next->value, PRINT_REPR);
|
||||
mp_obj_print_helper(print, env, next->value, kind);
|
||||
}
|
||||
print(env, "}");
|
||||
}
|
||||
|
@ -49,12 +49,15 @@ STATIC mp_obj_t list_pop(mp_uint_t n_args, const mp_obj_t *args);
|
||||
|
||||
STATIC void list_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
mp_obj_list_t *o = o_in;
|
||||
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
|
||||
kind = PRINT_REPR;
|
||||
}
|
||||
print(env, "[");
|
||||
for (mp_uint_t i = 0; i < o->len; i++) {
|
||||
if (i > 0) {
|
||||
print(env, ", ");
|
||||
}
|
||||
mp_obj_print_helper(print, env, o->items[i], PRINT_REPR);
|
||||
mp_obj_print_helper(print, env, o->items[i], kind);
|
||||
}
|
||||
print(env, "]");
|
||||
}
|
||||
|
@ -38,7 +38,11 @@ typedef struct _mp_obj_none_t {
|
||||
} mp_obj_none_t;
|
||||
|
||||
STATIC void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
print(env, "None");
|
||||
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
|
||||
print(env, "null");
|
||||
} else {
|
||||
print(env, "None");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t none_unary_op(mp_uint_t op, mp_obj_t o_in) {
|
||||
|
32
py/objstr.c
32
py/objstr.c
@ -92,9 +92,41 @@ void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *e
|
||||
print(env, "%c", quote_char);
|
||||
}
|
||||
|
||||
#if MICROPY_PY_UJSON
|
||||
STATIC void str_print_json(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, mp_uint_t str_len) {
|
||||
print(env, "\"");
|
||||
for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
|
||||
if (*s == '"' || *s == '\\' || *s == '/') {
|
||||
print(env, "\\%c", *s);
|
||||
} else if (32 <= *s && *s <= 126) {
|
||||
print(env, "%c", *s);
|
||||
} else if (*s == '\b') {
|
||||
print(env, "\\b");
|
||||
} else if (*s == '\f') {
|
||||
print(env, "\\f");
|
||||
} else if (*s == '\n') {
|
||||
print(env, "\\n");
|
||||
} else if (*s == '\r') {
|
||||
print(env, "\\r");
|
||||
} else if (*s == '\t') {
|
||||
print(env, "\\t");
|
||||
} else {
|
||||
print(env, "\\u%04x", *s);
|
||||
}
|
||||
}
|
||||
print(env, "\"");
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
GET_STR_DATA_LEN(self_in, str_data, str_len);
|
||||
bool is_bytes = MP_OBJ_IS_TYPE(self_in, &mp_type_bytes);
|
||||
#if MICROPY_PY_UJSON
|
||||
if (kind == PRINT_JSON) {
|
||||
str_print_json(print, env, str_data, str_len);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (kind == PRINT_STR && !is_bytes) {
|
||||
print(env, "%.*s", str_len, str_data);
|
||||
} else {
|
||||
|
@ -91,8 +91,44 @@ STATIC void uni_print_quoted(void (*print)(void *env, const char *fmt, ...), voi
|
||||
print(env, "%c", quote_char);
|
||||
}
|
||||
|
||||
#if MICROPY_PY_UJSON
|
||||
STATIC void uni_print_json(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) {
|
||||
print(env, "\"");
|
||||
const byte *s = str_data, *top = str_data + str_len;
|
||||
while (s < top) {
|
||||
unichar ch;
|
||||
ch = utf8_get_char(s);
|
||||
s = utf8_next_char(s);
|
||||
if (ch == '"' || ch == '\\' || ch == '/') {
|
||||
print(env, "\\%c", ch);
|
||||
} else if (32 <= ch && ch <= 126) {
|
||||
print(env, "%c", ch);
|
||||
} else if (*s == '\b') {
|
||||
print(env, "\\b");
|
||||
} else if (*s == '\f') {
|
||||
print(env, "\\f");
|
||||
} else if (*s == '\n') {
|
||||
print(env, "\\n");
|
||||
} else if (*s == '\r') {
|
||||
print(env, "\\r");
|
||||
} else if (*s == '\t') {
|
||||
print(env, "\\t");
|
||||
} else {
|
||||
print(env, "\\u%04x", ch);
|
||||
}
|
||||
}
|
||||
print(env, "\"");
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC void uni_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
GET_STR_DATA_LEN(self_in, str_data, str_len);
|
||||
#if MICROPY_PY_UJSON
|
||||
if (kind == PRINT_JSON) {
|
||||
uni_print_json(print, env, str_data, str_len);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (kind == PRINT_STR) {
|
||||
print(env, "%.*s", str_len, str_data);
|
||||
} else {
|
||||
|
@ -43,17 +43,26 @@ STATIC mp_obj_t mp_obj_new_tuple_iterator(mp_obj_tuple_t *tuple, mp_uint_t cur);
|
||||
|
||||
void mp_obj_tuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
mp_obj_tuple_t *o = o_in;
|
||||
print(env, "(");
|
||||
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
|
||||
print(env, "[");
|
||||
} else {
|
||||
print(env, "(");
|
||||
kind = PRINT_REPR;
|
||||
}
|
||||
for (mp_uint_t i = 0; i < o->len; i++) {
|
||||
if (i > 0) {
|
||||
print(env, ", ");
|
||||
}
|
||||
mp_obj_print_helper(print, env, o->items[i], PRINT_REPR);
|
||||
mp_obj_print_helper(print, env, o->items[i], kind);
|
||||
}
|
||||
if (o->len == 1) {
|
||||
print(env, ",");
|
||||
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
|
||||
print(env, "]");
|
||||
} else {
|
||||
if (o->len == 1) {
|
||||
print(env, ",");
|
||||
}
|
||||
print(env, ")");
|
||||
}
|
||||
print(env, ")");
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_obj_tuple_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
|
1
py/py.mk
1
py/py.mk
@ -112,6 +112,7 @@ PY_O_BASENAME = \
|
||||
pfenv_printf.o \
|
||||
../extmod/moductypes.o \
|
||||
../extmod/modzlibd.o \
|
||||
../extmod/modujson.o \
|
||||
|
||||
# prepend the build destination prefix to the py object files
|
||||
PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME))
|
||||
|
@ -463,3 +463,8 @@ Q(deleter)
|
||||
Q(zlibd)
|
||||
Q(decompress)
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_UJSON
|
||||
Q(ujson)
|
||||
Q(dumps)
|
||||
#endif
|
||||
|
@ -57,6 +57,7 @@
|
||||
#define MICROPY_PY_IO_FILEIO (1)
|
||||
#define MICROPY_PY_UCTYPES (1)
|
||||
#define MICROPY_PY_ZLIBD (1)
|
||||
#define MICROPY_PY_UJSON (1)
|
||||
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
|
||||
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)
|
||||
|
23
tests/extmod/ujson_dumps.py
Normal file
23
tests/extmod/ujson_dumps.py
Normal file
@ -0,0 +1,23 @@
|
||||
try:
|
||||
import ujson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
print(json.dumps(False))
|
||||
print(json.dumps(True))
|
||||
print(json.dumps(None))
|
||||
print(json.dumps(1))
|
||||
print(json.dumps(1.2))
|
||||
print(json.dumps('abc'))
|
||||
print(json.dumps('\x01\x7e\x7f\x80\u1234'))
|
||||
print(json.dumps([]))
|
||||
print(json.dumps([1]))
|
||||
print(json.dumps([1, 2]))
|
||||
print(json.dumps([1, True]))
|
||||
print(json.dumps(()))
|
||||
print(json.dumps((1,)))
|
||||
print(json.dumps((1, 2)))
|
||||
print(json.dumps((1, (2, 3))))
|
||||
print(json.dumps({}))
|
||||
print(json.dumps({"a":1}))
|
||||
print(json.dumps({"a":(2,[3,None])}))
|
@ -3,6 +3,7 @@
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import platform
|
||||
import argparse
|
||||
from glob import glob
|
||||
|
||||
@ -37,6 +38,11 @@ def run_tests(pyb, tests, args):
|
||||
if pyb is not None:
|
||||
skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead
|
||||
|
||||
# Some tests are known to fail on 64-bit machines
|
||||
if pyb is None and platform.architecture()[0] == '64bit':
|
||||
skip_tests.add('extmod/uctypes_ptr_le.py')
|
||||
skip_tests.add('extmod/uctypes_ptr_native_le.py')
|
||||
|
||||
# Some tests are known to fail with native emitter
|
||||
# Remove them from the below when they work
|
||||
if args.emit == 'native':
|
||||
@ -153,10 +159,10 @@ def main():
|
||||
if args.test_dirs is None:
|
||||
if pyb is None:
|
||||
# run PC tests
|
||||
test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc', 'unicode', 'unix')
|
||||
test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc', 'unicode', 'extmod', 'unix')
|
||||
else:
|
||||
# run pyboard tests
|
||||
test_dirs = ('basics', 'micropython', 'float', 'misc', 'pyb', 'pybnative', 'inlineasm')
|
||||
test_dirs = ('basics', 'micropython', 'float', 'misc', 'extmod', 'pyb', 'pybnative', 'inlineasm')
|
||||
else:
|
||||
# run tests from these directories
|
||||
test_dirs = args.test_dirs
|
||||
|
@ -58,6 +58,7 @@
|
||||
|
||||
#define MICROPY_PY_UCTYPES (1)
|
||||
#define MICROPY_PY_ZLIBD (1)
|
||||
#define MICROPY_PY_UJSON (1)
|
||||
|
||||
// Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc.
|
||||
// names in exception messages (may require more RAM).
|
||||
|
Loading…
Reference in New Issue
Block a user