Skip to content

Commit 4a36076

Browse files
author
Oliver Joos
committed
Merge remote-tracking branch 'peterzuger/ujson-dump-separators' into dev
2 parents 483b91e + 16df159 commit 4a36076

File tree

5 files changed

+112
-12
lines changed

5 files changed

+112
-12
lines changed

extmod/modujson.c

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,117 @@
3131
#include "py/parsenum.h"
3232
#include "py/runtime.h"
3333
#include "py/stream.h"
34+
#include "py/nlr.h"
3435

3536
#if MICROPY_PY_UJSON
3637

37-
STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) {
38-
mp_get_stream_raise(stream, MP_STREAM_OP_WRITE);
39-
mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor};
40-
mp_obj_print_helper(&print, obj, PRINT_JSON);
38+
static void mod_ujson_separators(mp_obj_t separators_in, const char **item_separator, const char **key_separator) {
39+
if (separators_in == mp_const_none) {
40+
*item_separator = ", ";
41+
*key_separator = ": ";
42+
} else {
43+
mp_obj_t *items;
44+
size_t len;
45+
mp_obj_tuple_get(separators_in, &len, &items);
46+
47+
if (len != 2) {
48+
mp_raise_ValueError(MP_ERROR_TEXT("too many values to unpack (expected 2)"));
49+
}
50+
51+
*item_separator = mp_obj_str_get_str(items[0]);
52+
*key_separator = mp_obj_str_get_str(items[1]);
53+
}
54+
}
55+
56+
const char *ujson_item_separator = ", ";
57+
const char *ujson_key_separator = ": ";
58+
59+
STATIC mp_obj_t mod_ujson_dump(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
60+
enum {ARG_indent, ARG_separators};
61+
const mp_arg_t allowed_args[] = {
62+
{ MP_QSTR_indent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
63+
{ MP_QSTR_separators, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
64+
};
65+
66+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
67+
mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
68+
69+
if (args[ARG_indent].u_obj != mp_const_none) {
70+
mp_raise_NotImplementedError(MP_ERROR_TEXT("indent is not None"));
71+
}
72+
73+
mp_get_stream_raise(pos_args[1], MP_STREAM_OP_WRITE);
74+
75+
const char *old_item_separator = ujson_item_separator;
76+
const char *old_key_separator = ujson_key_separator;
77+
bool raise = false;
78+
mod_ujson_separators(args[ARG_separators].u_obj, &ujson_item_separator, &ujson_key_separator);
79+
80+
nlr_buf_t nlr;
81+
if (nlr_push(&nlr) == 0) {
82+
mp_print_t print = {MP_OBJ_TO_PTR(pos_args[1]), mp_stream_write_adaptor};
83+
mp_obj_print_helper(&print, pos_args[0], PRINT_JSON);
84+
nlr_pop();
85+
} else {
86+
raise = true;
87+
}
88+
89+
// revert old values in case of nested dump
90+
ujson_item_separator = old_item_separator;
91+
ujson_key_separator = old_key_separator;
92+
93+
// Re-raise the exception
94+
if (raise) {
95+
nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val));
96+
}
97+
4198
return mp_const_none;
4299
}
43-
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump);
100+
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dump_obj, 2, mod_ujson_dump);
101+
102+
STATIC mp_obj_t mod_ujson_dumps(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
103+
enum {ARG_indent, ARG_separators};
104+
const mp_arg_t allowed_args[] = {
105+
{ MP_QSTR_indent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
106+
{ MP_QSTR_separators, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
107+
};
108+
109+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
110+
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
111+
112+
if (args[ARG_indent].u_obj != mp_const_none) {
113+
mp_raise_NotImplementedError(MP_ERROR_TEXT("indent is not None"));
114+
}
44115

45-
STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
46116
vstr_t vstr;
47117
mp_print_t print;
48118
vstr_init_print(&vstr, 8, &print);
49-
mp_obj_print_helper(&print, obj, PRINT_JSON);
119+
120+
const char *old_item_separator = ujson_item_separator;
121+
const char *old_key_separator = ujson_key_separator;
122+
bool raise = false;
123+
mod_ujson_separators(args[ARG_separators].u_obj, &ujson_item_separator, &ujson_key_separator);
124+
125+
nlr_buf_t nlr;
126+
if (nlr_push(&nlr) == 0) {
127+
mp_obj_print_helper(&print, pos_args[0], PRINT_JSON);
128+
nlr_pop();
129+
} else {
130+
raise = true;
131+
}
132+
133+
// revert old values in case of nested dump
134+
ujson_item_separator = old_item_separator;
135+
ujson_key_separator = old_key_separator;
136+
137+
// Re-raise the exception
138+
if (raise) {
139+
nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val));
140+
}
141+
50142
return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
51143
}
52-
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps);
144+
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dumps_obj, 1, mod_ujson_dumps);
53145

54146
// The function below implements a simple non-recursive JSON parser.
55147
//

py/obj.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,10 @@ typedef enum {
490490
PRINT_EXC_SUBCLASS = 0x80, // Internal flag for printing exception subclasses
491491
} mp_print_kind_t;
492492

493+
// separators for ujson
494+
extern const char *ujson_item_separator;
495+
extern const char *ujson_key_separator;
496+
493497
typedef struct _mp_obj_iter_buf_t {
494498
mp_obj_base_t base;
495499
mp_obj_t buf[3];

py/objdict.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
7272
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
7373
kind = PRINT_REPR;
7474
}
75+
const char *item_separator = (kind == PRINT_JSON) ? ujson_item_separator : ", ";
76+
const char *key_separator = (kind == PRINT_JSON) ? ujson_key_separator : ": ";
7577
if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) {
7678
mp_printf(print, "%q(", self->base.type->name);
7779
}
@@ -80,7 +82,7 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
8082
mp_map_elem_t *next = NULL;
8183
while ((next = dict_iter_next(self, &cur)) != NULL) {
8284
if (!first) {
83-
mp_print_str(print, ", ");
85+
mp_print_str(print, item_separator);
8486
}
8587
first = false;
8688
bool add_quote = MICROPY_PY_UJSON && kind == PRINT_JSON && !mp_obj_is_str_or_bytes(next->key);
@@ -91,7 +93,7 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
9193
if (add_quote) {
9294
mp_print_str(print, "\"");
9395
}
94-
mp_print_str(print, ": ");
96+
mp_print_str(print, key_separator);
9597
mp_obj_print_helper(print, next->value, kind);
9698
}
9799
mp_print_str(print, "}");

py/objlist.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ STATIC void list_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t k
4747
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
4848
kind = PRINT_REPR;
4949
}
50+
const char *item_separator = (kind == PRINT_JSON) ? ujson_item_separator : ", ";
5051
mp_print_str(print, "[");
5152
for (size_t i = 0; i < o->len; i++) {
5253
if (i > 0) {
53-
mp_print_str(print, ", ");
54+
mp_print_str(print, item_separator);
5455
}
5556
mp_obj_print_helper(print, o->items[i], kind);
5657
}

py/objtuple.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ void mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t
4545
mp_print_str(print, "(");
4646
kind = PRINT_REPR;
4747
}
48+
const char *item_separator = (kind == PRINT_JSON) ? ujson_item_separator : ", ";
4849
for (size_t i = 0; i < o->len; i++) {
4950
if (i > 0) {
50-
mp_print_str(print, ", ");
51+
mp_print_str(print, item_separator);
5152
}
5253
mp_obj_print_helper(print, o->items[i], kind);
5354
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy