From 483b2e91ad9ed5f6c51b3009177daf59dc55c892 Mon Sep 17 00:00:00 2001 From: Chris Liechti Date: Mon, 30 Nov 2020 16:40:56 +0100 Subject: [PATCH 01/14] py/builtinimport: support relative import in custom __import__ callbacks The globals need to be forwarded from the callers context. --- py/builtinimport.c | 17 ++++++++++++++--- py/runtime.c | 2 +- tests/import/import_override2.py | 17 +++++++++++++++++ tests/import/import_override2.py.exp | 13 +++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 tests/import/import_override2.py create mode 100644 tests/import/import_override2.py.exp diff --git a/py/builtinimport.c b/py/builtinimport.c index bdc82e77c8f74..3522c6b5f6ef3 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -255,7 +255,11 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { mp_obj_t module_name = args[0]; mp_obj_t fromtuple = mp_const_none; + mp_obj_t globals = mp_const_none; mp_int_t level = 0; + if (n_args >= 2) { + globals = args[1]; + } if (n_args >= 4) { fromtuple = args[3]; if (n_args >= 5) { @@ -278,15 +282,22 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // "Relative imports use a module's __name__ attribute to determine that // module's position in the package hierarchy." level--; - mp_obj_t this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__)); + if (globals == mp_const_none) { + globals = MP_OBJ_FROM_PTR(mp_globals_get()); + } else { + if (!mp_obj_is_type(globals, &mp_type_dict)) { + mp_raise_TypeError(MP_ERROR_TEXT("globals must be dict")); + } + } + mp_obj_t this_name_q = mp_obj_dict_get(globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__)); assert(this_name_q != MP_OBJ_NULL); #if MICROPY_CPYTHON_COMPAT if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) { // This is a module run by -m command-line switch, get its real name from backup attribute - this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + this_name_q = mp_obj_dict_get(globals, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); } #endif - mp_map_t *globals_map = &mp_globals_get()->map; + mp_map_t *globals_map = &((mp_obj_dict_t *)globals)->map; mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); bool is_pkg = (elem != NULL); diff --git a/py/runtime.c b/py/runtime.c index c12271f4e2cf5..e768abfb19402 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1373,7 +1373,7 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { // build args array mp_obj_t args[5]; args[0] = MP_OBJ_NEW_QSTR(name); - args[1] = mp_const_none; // TODO should be globals + args[1] = MP_OBJ_FROM_PTR(mp_globals_get()); // globals of the current context args[2] = mp_const_none; // TODO should be locals args[3] = fromlist; args[4] = level; diff --git a/tests/import/import_override2.py b/tests/import/import_override2.py new file mode 100644 index 0000000000000..27f02fcc298fa --- /dev/null +++ b/tests/import/import_override2.py @@ -0,0 +1,17 @@ +# test overriding __import__ combined with importing from the filesystem + + +def custom_import(name, globals, locals, fromlist, level): + print("import", name, fromlist, level) + return orig_import(name, globals, locals, fromlist, level) + + +orig_import = __import__ +try: + __import__("builtins").__import__ = custom_import +except AttributeError: + print("SKIP") + raise SystemExit + +# import calls __import__ behind the scenes +import pkg7.subpkg1.subpkg2.mod3 diff --git a/tests/import/import_override2.py.exp b/tests/import/import_override2.py.exp new file mode 100644 index 0000000000000..3f590b8504279 --- /dev/null +++ b/tests/import/import_override2.py.exp @@ -0,0 +1,13 @@ +import pkg7.subpkg1.subpkg2.mod3 None 0 +pkg __name__: pkg7 +pkg __name__: pkg7.subpkg1 +pkg __name__: pkg7.subpkg1.subpkg2 +import ('mod1',) 3 +import pkg7.mod1 True 0 +mod1 +import mod2 ('bar',) 3 +mod2 +mod1.foo +mod2.bar +import ('mod1',) 4 +ValueError From 823eefb680e75a1d38cad4b18ec5a5ca92d8751a Mon Sep 17 00:00:00 2001 From: Chris Liechti Date: Mon, 30 Nov 2020 17:53:56 +0100 Subject: [PATCH 02/14] py/builtinimport: fix CI fails --- py/builtinimport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/builtinimport.c b/py/builtinimport.c index 3522c6b5f6ef3..aa755ce1c09bd 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -297,7 +297,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { this_name_q = mp_obj_dict_get(globals, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); } #endif - mp_map_t *globals_map = &((mp_obj_dict_t *)globals)->map; + mp_map_t *globals_map = mp_obj_dict_get_map(globals); mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); bool is_pkg = (elem != NULL); From 3bf30661574f8c3506106c2d0574659bc11f0b28 Mon Sep 17 00:00:00 2001 From: Chris Liechti Date: Wed, 2 Dec 2020 00:38:30 +0100 Subject: [PATCH 03/14] extmod/uasyncio: support for overriden __import__ globals() needs to be provided in case __import__ is a Python function --- extmod/uasyncio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/uasyncio/__init__.py b/extmod/uasyncio/__init__.py index 08f924cf29b9b..dd246fbfa67f5 100644 --- a/extmod/uasyncio/__init__.py +++ b/extmod/uasyncio/__init__.py @@ -24,6 +24,6 @@ def __getattr__(attr): mod = _attrs.get(attr, None) if mod is None: raise AttributeError(attr) - value = getattr(__import__(mod, None, None, True, 1), attr) + value = getattr(__import__(mod, globals(), None, True, 1), attr) globals()[attr] = value return value From 0109a24e604cd36b45560e79503f723b39d87e3f Mon Sep 17 00:00:00 2001 From: Oliver Joos Date: Wed, 16 Dec 2020 21:25:18 +0100 Subject: [PATCH 04/14] tests/extmod: Add test for the precision of utime functions. According to documentation time() has a precision of at least 1 second. This test runs for 2.5 seconds and calls all utime functions every 100ms. Then it checks if they returned enough different results. All functions with sub-second precision will return ~25 results. This test passes with 15 results or more. Functions that do not exist are skipped silently. --- tests/extmod/utime_res.py | 65 +++++++++++++++++++++++++++++++++++ tests/extmod/utime_res.py.exp | 9 +++++ 2 files changed, 74 insertions(+) create mode 100644 tests/extmod/utime_res.py create mode 100644 tests/extmod/utime_res.py.exp diff --git a/tests/extmod/utime_res.py b/tests/extmod/utime_res.py new file mode 100644 index 0000000000000..4b624334836f1 --- /dev/null +++ b/tests/extmod/utime_res.py @@ -0,0 +1,65 @@ +# test utime resolutions + +try: + import utime +except ImportError: + print("SKIP") + raise SystemExit + + +def gmtime_time(): + return utime.gmtime(utime.time()) + + +def localtime_time(): + return utime.localtime(utime.time()) + + +def test(): + TEST_TIME = 2500 + EXPECTED_MAP = ( + # (function name, min. number of results in 2.5 sec) + ("time", 3), + ("gmtime", 3), + ("localtime", 3), + ("gmtime_time", 3), + ("localtime_time", 3), + ("ticks_ms", 15), + ("ticks_us", 15), + ("ticks_ns", 15), + ("ticks_cpu", 15), + ) + + # call time functions + results_map = {} + end_time = utime.ticks_ms() + TEST_TIME + while utime.ticks_diff(end_time, utime.ticks_ms()) > 0: + utime.sleep_ms(100) + for func_name, _ in EXPECTED_MAP: + try: + time_func = getattr(utime, func_name, None) or globals()[func_name] + now = time_func() # may raise AttributeError + except (KeyError, AttributeError): + continue + try: + results_map[func_name].add(now) + except KeyError: + results_map[func_name] = {now} + + # check results + for func_name, min_len in EXPECTED_MAP: + print("Testing %s" % func_name) + results = results_map.get(func_name) + if results is None: + pass + elif func_name == "ticks_cpu" and results == {0}: + # ticks_cpu() returns 0 on some ports (e.g. unix) + pass + elif len(results) < min_len: + print( + "%s() returns %s result%s in %s ms, expecting >= %s" + % (func_name, len(results), "s"[: len(results) != 1], TEST_TIME, min_len) + ) + + +test() diff --git a/tests/extmod/utime_res.py.exp b/tests/extmod/utime_res.py.exp new file mode 100644 index 0000000000000..08c2d82950603 --- /dev/null +++ b/tests/extmod/utime_res.py.exp @@ -0,0 +1,9 @@ +Testing time +Testing gmtime +Testing localtime +Testing gmtime_time +Testing localtime_time +Testing ticks_ms +Testing ticks_us +Testing ticks_ns +Testing ticks_cpu From bd1e1e7f5b8178b73a3b39da957837e7dcbe5907 Mon Sep 17 00:00:00 2001 From: Oliver Joos Date: Wed, 16 Dec 2020 22:35:52 +0100 Subject: [PATCH 05/14] unix/modtime: Fix time() precision on unix ports with non-double floats. With MICROPY_FLOAT_IMPL_FLOAT the results of utime.time(), gmtime() and localtime() change only every 129 seconds. As one consequence tests/extmod/vfs_lfs_mtime.py will fail on a unix port with LFS support. With this patch these functions only return floats if MICROPY_FLOAT_IMPL_DOUBLE is used. Otherwise they return integers. --- ports/unix/modtime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/unix/modtime.c b/ports/unix/modtime.c index e08409e20e3e9..284022838d878 100644 --- a/ports/unix/modtime.c +++ b/ports/unix/modtime.c @@ -67,7 +67,7 @@ static inline int msec_sleep_tv(struct timeval *tv) { #endif STATIC mp_obj_t mod_time_time(void) { - #if MICROPY_PY_BUILTINS_FLOAT + #if ((MICROPY_PY_BUILTINS_FLOAT) && (MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE)) struct timeval tv; gettimeofday(&tv, NULL); mp_float_t val = tv.tv_sec + (mp_float_t)tv.tv_usec / 1000000; @@ -137,7 +137,7 @@ STATIC mp_obj_t mod_time_gm_local_time(size_t n_args, const mp_obj_t *args, stru if (n_args == 0) { t = time(NULL); } else { - #if MICROPY_PY_BUILTINS_FLOAT + #if ((MICROPY_PY_BUILTINS_FLOAT) && (MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE)) mp_float_t val = mp_obj_get_float(args[0]); t = (time_t)MICROPY_FLOAT_C_FUN(trunc)(val); #else From 3ae7d8ed45a3d423efa4a82173441d06e6bca5bb Mon Sep 17 00:00:00 2001 From: Oliver Joos Date: Sun, 20 Dec 2020 18:23:04 +0100 Subject: [PATCH 06/14] unix/modtime: Remove unnecessary parenthesis to keep a consistent style. --- ports/unix/modtime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/unix/modtime.c b/ports/unix/modtime.c index 284022838d878..91c0a19413092 100644 --- a/ports/unix/modtime.c +++ b/ports/unix/modtime.c @@ -67,7 +67,7 @@ static inline int msec_sleep_tv(struct timeval *tv) { #endif STATIC mp_obj_t mod_time_time(void) { - #if ((MICROPY_PY_BUILTINS_FLOAT) && (MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE)) + #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE struct timeval tv; gettimeofday(&tv, NULL); mp_float_t val = tv.tv_sec + (mp_float_t)tv.tv_usec / 1000000; @@ -137,7 +137,7 @@ STATIC mp_obj_t mod_time_gm_local_time(size_t n_args, const mp_obj_t *args, stru if (n_args == 0) { t = time(NULL); } else { - #if ((MICROPY_PY_BUILTINS_FLOAT) && (MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE)) + #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE mp_float_t val = mp_obj_get_float(args[0]); t = (time_t)MICROPY_FLOAT_C_FUN(trunc)(val); #else From f416bd8855e0f2af671390e0af35e366f0db47c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Z=C3=BCger?= Date: Wed, 3 Feb 2021 09:24:25 +0100 Subject: [PATCH 07/14] extmod/modujson.c: Make ujson-dump/dumps kw-functions --- extmod/modujson.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/extmod/modujson.c b/extmod/modujson.c index 8dff673580279..2f96b1b3aac9e 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -31,25 +31,52 @@ #include "py/parsenum.h" #include "py/runtime.h" #include "py/stream.h" +#include "py/nlr.h" #if MICROPY_PY_UJSON -STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) { - mp_get_stream_raise(stream, MP_STREAM_OP_WRITE); - mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor}; - mp_obj_print_helper(&print, obj, PRINT_JSON); +STATIC mp_obj_t mod_ujson_dump(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum {ARG_indent, ARG_separators}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_indent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + { MP_QSTR_separators, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_indent].u_obj != mp_const_none) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("indent is not None")); + } + + mp_get_stream_raise(pos_args[1], MP_STREAM_OP_WRITE); + mp_print_t print = {MP_OBJ_TO_PTR(pos_args[1]), mp_stream_write_adaptor}; + mp_obj_print_helper(&print, pos_args[0], PRINT_JSON); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dump_obj, 2, mod_ujson_dump); + +STATIC mp_obj_t mod_ujson_dumps(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum {ARG_indent, ARG_separators}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_indent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + { MP_QSTR_separators, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_indent].u_obj != mp_const_none) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("indent is not None")); + } -STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) { vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 8, &print); - mp_obj_print_helper(&print, obj, PRINT_JSON); + mp_obj_print_helper(&print, pos_args[0], PRINT_JSON); return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dumps_obj, 1, mod_ujson_dumps); // The function below implements a simple non-recursive JSON parser. // From 765a49468b5fc4e4c760f1ac88b7f14202fb7c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Z=C3=BCger?= Date: Wed, 3 Feb 2021 09:27:13 +0100 Subject: [PATCH 08/14] extmod/modujson.c: Catch and re-raise exceptions during printing --- extmod/modujson.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/extmod/modujson.c b/extmod/modujson.c index 2f96b1b3aac9e..261b6b920a841 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -50,8 +50,16 @@ STATIC mp_obj_t mod_ujson_dump(size_t n_args, const mp_obj_t *pos_args, mp_map_t } mp_get_stream_raise(pos_args[1], MP_STREAM_OP_WRITE); - mp_print_t print = {MP_OBJ_TO_PTR(pos_args[1]), mp_stream_write_adaptor}; - mp_obj_print_helper(&print, pos_args[0], PRINT_JSON); + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_print_t print = {MP_OBJ_TO_PTR(pos_args[1]), mp_stream_write_adaptor}; + mp_obj_print_helper(&print, pos_args[0], PRINT_JSON); + nlr_pop(); + } else { + // Re-raise the exception + nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dump_obj, 2, mod_ujson_dump); @@ -73,7 +81,15 @@ STATIC mp_obj_t mod_ujson_dumps(size_t n_args, const mp_obj_t *pos_args, mp_map_ vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 8, &print); - mp_obj_print_helper(&print, pos_args[0], PRINT_JSON); + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_print_helper(&print, pos_args[0], PRINT_JSON); + nlr_pop(); + } else { + // Re-raise the exception + nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); + } return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dumps_obj, 1, mod_ujson_dumps); From 70ef973e3e44003fac58aead9dd42640338f513c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Z=C3=BCger?= Date: Wed, 3 Feb 2021 10:40:33 +0100 Subject: [PATCH 09/14] py/obj: Add global separators for ujson --- extmod/modujson.c | 3 +++ py/obj.h | 4 ++++ py/objdict.c | 6 ++++-- py/objlist.c | 3 ++- py/objtuple.c | 3 ++- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/extmod/modujson.c b/extmod/modujson.c index 261b6b920a841..dbe928dfa57d8 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -35,6 +35,9 @@ #if MICROPY_PY_UJSON +const char *ujson_item_separator = ", "; +const char *ujson_key_separator = ": "; + STATIC mp_obj_t mod_ujson_dump(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum {ARG_indent, ARG_separators}; const mp_arg_t allowed_args[] = { diff --git a/py/obj.h b/py/obj.h index 6a040b77739c2..945e4de22c707 100644 --- a/py/obj.h +++ b/py/obj.h @@ -490,6 +490,10 @@ typedef enum { PRINT_EXC_SUBCLASS = 0x80, // Internal flag for printing exception subclasses } mp_print_kind_t; +// separators for ujson +extern const char *ujson_item_separator; +extern const char *ujson_key_separator; + typedef struct _mp_obj_iter_buf_t { mp_obj_base_t base; mp_obj_t buf[3]; diff --git a/py/objdict.c b/py/objdict.c index 4e51f259e7ff4..ac7daa25ce282 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -72,6 +72,8 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { kind = PRINT_REPR; } + const char *item_separator = (kind == PRINT_JSON) ? ujson_item_separator : ", "; + const char *key_separator = (kind == PRINT_JSON) ? ujson_key_separator : ": "; if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) { mp_printf(print, "%q(", self->base.type->name); } @@ -80,7 +82,7 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ mp_map_elem_t *next = NULL; while ((next = dict_iter_next(self, &cur)) != NULL) { if (!first) { - mp_print_str(print, ", "); + mp_print_str(print, item_separator); } first = false; 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_ if (add_quote) { mp_print_str(print, "\""); } - mp_print_str(print, ": "); + mp_print_str(print, key_separator); mp_obj_print_helper(print, next->value, kind); } mp_print_str(print, "}"); diff --git a/py/objlist.c b/py/objlist.c index 8c989facc0dfe..b5711f6a5ab13 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -47,10 +47,11 @@ STATIC void list_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t k if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { kind = PRINT_REPR; } + const char *item_separator = (kind == PRINT_JSON) ? ujson_item_separator : ", "; mp_print_str(print, "["); for (size_t i = 0; i < o->len; i++) { if (i > 0) { - mp_print_str(print, ", "); + mp_print_str(print, item_separator); } mp_obj_print_helper(print, o->items[i], kind); } diff --git a/py/objtuple.c b/py/objtuple.c index 07a560ac08aac..472e497c56b26 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -45,9 +45,10 @@ void mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t mp_print_str(print, "("); kind = PRINT_REPR; } + const char *item_separator = (kind == PRINT_JSON) ? ujson_item_separator : ", "; for (size_t i = 0; i < o->len; i++) { if (i > 0) { - mp_print_str(print, ", "); + mp_print_str(print, item_separator); } mp_obj_print_helper(print, o->items[i], kind); } From 16df159b3d0300fc8c649aebcc6fb20a9c5fb14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Z=C3=BCger?= Date: Wed, 3 Feb 2021 11:11:19 +0100 Subject: [PATCH 10/14] extmod/modujson.c: Added dump/dumps separators added support for the separators keyword argument in ujson's dump and dumps. added keyword argument indent, only accepts indent=None. indent was only added because it is connected to separators. --- extmod/modujson.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/extmod/modujson.c b/extmod/modujson.c index dbe928dfa57d8..a132032547676 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -35,6 +35,24 @@ #if MICROPY_PY_UJSON +static void mod_ujson_separators(mp_obj_t separators_in, const char **item_separator, const char **key_separator) { + if (separators_in == mp_const_none) { + *item_separator = ", "; + *key_separator = ": "; + } else { + mp_obj_t *items; + size_t len; + mp_obj_tuple_get(separators_in, &len, &items); + + if (len != 2) { + mp_raise_ValueError(MP_ERROR_TEXT("too many values to unpack (expected 2)")); + } + + *item_separator = mp_obj_str_get_str(items[0]); + *key_separator = mp_obj_str_get_str(items[1]); + } +} + const char *ujson_item_separator = ", "; const char *ujson_key_separator = ": "; @@ -54,15 +72,29 @@ STATIC mp_obj_t mod_ujson_dump(size_t n_args, const mp_obj_t *pos_args, mp_map_t mp_get_stream_raise(pos_args[1], MP_STREAM_OP_WRITE); + const char *old_item_separator = ujson_item_separator; + const char *old_key_separator = ujson_key_separator; + bool raise = false; + mod_ujson_separators(args[ARG_separators].u_obj, &ujson_item_separator, &ujson_key_separator); + nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_print_t print = {MP_OBJ_TO_PTR(pos_args[1]), mp_stream_write_adaptor}; mp_obj_print_helper(&print, pos_args[0], PRINT_JSON); nlr_pop(); } else { - // Re-raise the exception + raise = true; + } + + // revert old values in case of nested dump + ujson_item_separator = old_item_separator; + ujson_key_separator = old_key_separator; + + // Re-raise the exception + if (raise) { nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); } + return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dump_obj, 2, mod_ujson_dump); @@ -85,14 +117,28 @@ STATIC mp_obj_t mod_ujson_dumps(size_t n_args, const mp_obj_t *pos_args, mp_map_ mp_print_t print; vstr_init_print(&vstr, 8, &print); + const char *old_item_separator = ujson_item_separator; + const char *old_key_separator = ujson_key_separator; + bool raise = false; + mod_ujson_separators(args[ARG_separators].u_obj, &ujson_item_separator, &ujson_key_separator); + nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_print_helper(&print, pos_args[0], PRINT_JSON); nlr_pop(); } else { - // Re-raise the exception + raise = true; + } + + // revert old values in case of nested dump + ujson_item_separator = old_item_separator; + ujson_key_separator = old_key_separator; + + // Re-raise the exception + if (raise) { nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); } + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dumps_obj, 1, mod_ujson_dumps); From db57e344b662e5021e4c21fb05c7971bce0eecc1 Mon Sep 17 00:00:00 2001 From: Oliver Joos Date: Thu, 4 Feb 2021 11:35:16 +0100 Subject: [PATCH 11/14] Revert "Merge remote-tracking branch 'peterzuger/ujson-dump-separators' into dev" This reverts commit 4a3607620eb08ecf761f2579f8b0527235b1b0a5. --- extmod/modujson.c | 108 ++++------------------------------------------ py/obj.h | 4 -- py/objdict.c | 6 +-- py/objlist.c | 3 +- py/objtuple.c | 3 +- 5 files changed, 12 insertions(+), 112 deletions(-) diff --git a/extmod/modujson.c b/extmod/modujson.c index a132032547676..8dff673580279 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -31,117 +31,25 @@ #include "py/parsenum.h" #include "py/runtime.h" #include "py/stream.h" -#include "py/nlr.h" #if MICROPY_PY_UJSON -static void mod_ujson_separators(mp_obj_t separators_in, const char **item_separator, const char **key_separator) { - if (separators_in == mp_const_none) { - *item_separator = ", "; - *key_separator = ": "; - } else { - mp_obj_t *items; - size_t len; - mp_obj_tuple_get(separators_in, &len, &items); - - if (len != 2) { - mp_raise_ValueError(MP_ERROR_TEXT("too many values to unpack (expected 2)")); - } - - *item_separator = mp_obj_str_get_str(items[0]); - *key_separator = mp_obj_str_get_str(items[1]); - } -} - -const char *ujson_item_separator = ", "; -const char *ujson_key_separator = ": "; - -STATIC mp_obj_t mod_ujson_dump(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum {ARG_indent, ARG_separators}; - const mp_arg_t allowed_args[] = { - { MP_QSTR_indent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, - { MP_QSTR_separators, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - if (args[ARG_indent].u_obj != mp_const_none) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("indent is not None")); - } - - mp_get_stream_raise(pos_args[1], MP_STREAM_OP_WRITE); - - const char *old_item_separator = ujson_item_separator; - const char *old_key_separator = ujson_key_separator; - bool raise = false; - mod_ujson_separators(args[ARG_separators].u_obj, &ujson_item_separator, &ujson_key_separator); - - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_print_t print = {MP_OBJ_TO_PTR(pos_args[1]), mp_stream_write_adaptor}; - mp_obj_print_helper(&print, pos_args[0], PRINT_JSON); - nlr_pop(); - } else { - raise = true; - } - - // revert old values in case of nested dump - ujson_item_separator = old_item_separator; - ujson_key_separator = old_key_separator; - - // Re-raise the exception - if (raise) { - nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); - } - +STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) { + mp_get_stream_raise(stream, MP_STREAM_OP_WRITE); + mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor}; + mp_obj_print_helper(&print, obj, PRINT_JSON); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dump_obj, 2, mod_ujson_dump); - -STATIC mp_obj_t mod_ujson_dumps(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum {ARG_indent, ARG_separators}; - const mp_arg_t allowed_args[] = { - { MP_QSTR_indent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, - { MP_QSTR_separators, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - if (args[ARG_indent].u_obj != mp_const_none) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("indent is not None")); - } +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump); +STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) { vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 8, &print); - - const char *old_item_separator = ujson_item_separator; - const char *old_key_separator = ujson_key_separator; - bool raise = false; - mod_ujson_separators(args[ARG_separators].u_obj, &ujson_item_separator, &ujson_key_separator); - - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_print_helper(&print, pos_args[0], PRINT_JSON); - nlr_pop(); - } else { - raise = true; - } - - // revert old values in case of nested dump - ujson_item_separator = old_item_separator; - ujson_key_separator = old_key_separator; - - // Re-raise the exception - if (raise) { - nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); - } - + mp_obj_print_helper(&print, obj, PRINT_JSON); return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dumps_obj, 1, mod_ujson_dumps); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps); // The function below implements a simple non-recursive JSON parser. // diff --git a/py/obj.h b/py/obj.h index b8acc916f7ab2..86e5d83125cb5 100644 --- a/py/obj.h +++ b/py/obj.h @@ -490,10 +490,6 @@ typedef enum { PRINT_EXC_SUBCLASS = 0x80, // Internal flag for printing exception subclasses } mp_print_kind_t; -// separators for ujson -extern const char *ujson_item_separator; -extern const char *ujson_key_separator; - typedef struct _mp_obj_iter_buf_t { mp_obj_base_t base; mp_obj_t buf[3]; diff --git a/py/objdict.c b/py/objdict.c index 5924de0f15084..aea5952d3ddad 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -72,8 +72,6 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { kind = PRINT_REPR; } - const char *item_separator = (kind == PRINT_JSON) ? ujson_item_separator : ", "; - const char *key_separator = (kind == PRINT_JSON) ? ujson_key_separator : ": "; if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) { mp_printf(print, "%q(", self->base.type->name); } @@ -82,7 +80,7 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ mp_map_elem_t *next = NULL; while ((next = dict_iter_next(self, &cur)) != NULL) { if (!first) { - mp_print_str(print, item_separator); + mp_print_str(print, ", "); } first = false; bool add_quote = MICROPY_PY_UJSON && kind == PRINT_JSON && !mp_obj_is_str_or_bytes(next->key); @@ -93,7 +91,7 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ if (add_quote) { mp_print_str(print, "\""); } - mp_print_str(print, key_separator); + mp_print_str(print, ": "); mp_obj_print_helper(print, next->value, kind); } mp_print_str(print, "}"); diff --git a/py/objlist.c b/py/objlist.c index b5711f6a5ab13..8c989facc0dfe 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -47,11 +47,10 @@ STATIC void list_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t k if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { kind = PRINT_REPR; } - const char *item_separator = (kind == PRINT_JSON) ? ujson_item_separator : ", "; mp_print_str(print, "["); for (size_t i = 0; i < o->len; i++) { if (i > 0) { - mp_print_str(print, item_separator); + mp_print_str(print, ", "); } mp_obj_print_helper(print, o->items[i], kind); } diff --git a/py/objtuple.c b/py/objtuple.c index 472e497c56b26..07a560ac08aac 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -45,10 +45,9 @@ void mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t mp_print_str(print, "("); kind = PRINT_REPR; } - const char *item_separator = (kind == PRINT_JSON) ? ujson_item_separator : ", "; for (size_t i = 0; i < o->len; i++) { if (i > 0) { - mp_print_str(print, item_separator); + mp_print_str(print, ", "); } mp_obj_print_helper(print, o->items[i], kind); } From 2aaacbd96dff0042599f8994ac750dffad8f862f Mon Sep 17 00:00:00 2001 From: Oliver Joos Date: Tue, 29 Dec 2020 09:53:07 +0100 Subject: [PATCH 12/14] Revert "Merge remote-tracking branch 'zsquareplusc/fix-override-relative-import' into dev" This reverts commit 8413c46c604b796232834047923fa74c139d39b3. --- extmod/uasyncio/__init__.py | 2 +- py/builtinimport.c | 17 +++-------------- py/runtime.c | 2 +- tests/import/import_override2.py | 17 ----------------- tests/import/import_override2.py.exp | 13 ------------- 5 files changed, 5 insertions(+), 46 deletions(-) delete mode 100644 tests/import/import_override2.py delete mode 100644 tests/import/import_override2.py.exp diff --git a/extmod/uasyncio/__init__.py b/extmod/uasyncio/__init__.py index 3361159587f24..fa64438f6b2a0 100644 --- a/extmod/uasyncio/__init__.py +++ b/extmod/uasyncio/__init__.py @@ -25,6 +25,6 @@ def __getattr__(attr): mod = _attrs.get(attr, None) if mod is None: raise AttributeError(attr) - value = getattr(__import__(mod, globals(), None, True, 1), attr) + value = getattr(__import__(mod, None, None, True, 1), attr) globals()[attr] = value return value diff --git a/py/builtinimport.c b/py/builtinimport.c index f09d474852156..08921f873b803 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -255,11 +255,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { mp_obj_t module_name = args[0]; mp_obj_t fromtuple = mp_const_none; - mp_obj_t globals = mp_const_none; mp_int_t level = 0; - if (n_args >= 2) { - globals = args[1]; - } if (n_args >= 4) { fromtuple = args[3]; if (n_args >= 5) { @@ -282,22 +278,15 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // "Relative imports use a module's __name__ attribute to determine that // module's position in the package hierarchy." level--; - if (globals == mp_const_none) { - globals = MP_OBJ_FROM_PTR(mp_globals_get()); - } else { - if (!mp_obj_is_type(globals, &mp_type_dict)) { - mp_raise_TypeError(MP_ERROR_TEXT("globals must be dict")); - } - } - mp_obj_t this_name_q = mp_obj_dict_get(globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__)); + mp_obj_t this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__)); assert(this_name_q != MP_OBJ_NULL); #if MICROPY_CPYTHON_COMPAT if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) { // This is a module run by -m command-line switch, get its real name from backup attribute - this_name_q = mp_obj_dict_get(globals, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); } #endif - mp_map_t *globals_map = mp_obj_dict_get_map(globals); + mp_map_t *globals_map = &mp_globals_get()->map; mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); bool is_pkg = (elem != NULL); diff --git a/py/runtime.c b/py/runtime.c index e23771d73bf51..0120b70d74e1b 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1399,7 +1399,7 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { // build args array mp_obj_t args[5]; args[0] = MP_OBJ_NEW_QSTR(name); - args[1] = MP_OBJ_FROM_PTR(mp_globals_get()); // globals of the current context + args[1] = mp_const_none; // TODO should be globals args[2] = mp_const_none; // TODO should be locals args[3] = fromlist; args[4] = level; diff --git a/tests/import/import_override2.py b/tests/import/import_override2.py deleted file mode 100644 index 27f02fcc298fa..0000000000000 --- a/tests/import/import_override2.py +++ /dev/null @@ -1,17 +0,0 @@ -# test overriding __import__ combined with importing from the filesystem - - -def custom_import(name, globals, locals, fromlist, level): - print("import", name, fromlist, level) - return orig_import(name, globals, locals, fromlist, level) - - -orig_import = __import__ -try: - __import__("builtins").__import__ = custom_import -except AttributeError: - print("SKIP") - raise SystemExit - -# import calls __import__ behind the scenes -import pkg7.subpkg1.subpkg2.mod3 diff --git a/tests/import/import_override2.py.exp b/tests/import/import_override2.py.exp deleted file mode 100644 index 3f590b8504279..0000000000000 --- a/tests/import/import_override2.py.exp +++ /dev/null @@ -1,13 +0,0 @@ -import pkg7.subpkg1.subpkg2.mod3 None 0 -pkg __name__: pkg7 -pkg __name__: pkg7.subpkg1 -pkg __name__: pkg7.subpkg1.subpkg2 -import ('mod1',) 3 -import pkg7.mod1 True 0 -mod1 -import mod2 ('bar',) 3 -mod2 -mod1.foo -mod2.bar -import ('mod1',) 4 -ValueError From 3a46dc08b79b2f753b17ad1f600289b2792b28e5 Mon Sep 17 00:00:00 2001 From: Oliver Joos Date: Sat, 12 Mar 2022 16:29:23 +0100 Subject: [PATCH 13/14] py/builtinimport: Support relative import in custom __import__ callback. The globals need to be forwarded from the callers context. --- py/builtinimport.c | 21 +++++++++++++++----- py/runtime.c | 2 +- tests/import/import_override2.py | 29 ++++++++++++++++++++++++++++ tests/import/import_override2.py.exp | 15 ++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 tests/import/import_override2.py create mode 100644 tests/import/import_override2.py.exp diff --git a/py/builtinimport.c b/py/builtinimport.c index 094959f97d381..19d45d4bac673 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -257,7 +257,7 @@ STATIC void do_load(mp_module_context_t *module_obj, vstr_t *file) { // Convert a relative (to the current module) import, going up "level" levels, // into an absolute import. -STATIC void evaluate_relative_import(mp_int_t level, const char **module_name, size_t *module_name_len) { +STATIC void evaluate_relative_import(mp_int_t level, const char **module_name, size_t *module_name_len, mp_obj_t globals) { // What we want to do here is to take the name of the current module, // remove trailing components, and concatenate the passed-in // module name. @@ -266,7 +266,7 @@ STATIC void evaluate_relative_import(mp_int_t level, const char **module_name, s // module's position in the package hierarchy." // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name - mp_obj_t current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__)); + mp_obj_t current_module_name_obj = mp_obj_dict_get(globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__)); assert(current_module_name_obj != MP_OBJ_NULL); #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT && MICROPY_CPYTHON_COMPAT @@ -274,12 +274,12 @@ STATIC void evaluate_relative_import(mp_int_t level, const char **module_name, s // This is a module loaded by -m command-line switch (e.g. unix port), // and so its __name__ has been set to "__main__". Get its real name // that we stored during import in the __main__ attribute. - current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + current_module_name_obj = mp_obj_dict_get(globals, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); } #endif // If we have a __path__ in the globals dict, then we're a package. - bool is_pkg = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); + bool is_pkg = mp_map_lookup(mp_obj_dict_get_map(globals), MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); #if DEBUG_PRINT DEBUG_printf("Current module/package: "); @@ -480,6 +480,17 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // "from ...foo.bar import baz" --> module_name="foo.bar" mp_obj_t module_name_obj = args[0]; + // This is the dict with all global symbols. + mp_obj_t globals = mp_const_none; + if (n_args >= 2) { + globals = args[1]; + } + if (globals == mp_const_none) { + globals = MP_OBJ_FROM_PTR(mp_globals_get()); + } else if (!mp_obj_is_type(globals, &mp_type_dict)) { + mp_raise_TypeError(MP_ERROR_TEXT("globals must be dict")); + } + // These are the imported names. // i.e. "from foo.bar import baz, zap" --> fromtuple=("baz", "zap",) // Note: There's a special case on the Unix port, where this is set to mp_const_false which means that it's __main__. @@ -505,7 +516,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { if (level != 0) { // Turn "foo.bar" into ".foo.bar". - evaluate_relative_import(level, &module_name, &module_name_len); + evaluate_relative_import(level, &module_name, &module_name_len, globals); } if (module_name_len == 0) { diff --git a/py/runtime.c b/py/runtime.c index 8c93f539e04e6..b1fed7096981c 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1408,7 +1408,7 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { // build args array mp_obj_t args[5]; args[0] = MP_OBJ_NEW_QSTR(name); - args[1] = mp_const_none; // TODO should be globals + args[1] = MP_OBJ_FROM_PTR(mp_globals_get()); // globals of the current context args[2] = mp_const_none; // TODO should be locals args[3] = fromlist; args[4] = level; diff --git a/tests/import/import_override2.py b/tests/import/import_override2.py new file mode 100644 index 0000000000000..2cd2da21ebd55 --- /dev/null +++ b/tests/import/import_override2.py @@ -0,0 +1,29 @@ +# test overriding __import__ combined with importing from the filesystem + + +def custom_import(name, globals, locals, fromlist, level): + print("import", name, fromlist, level) + return orig_import(name, globals, locals, fromlist, level) + + +orig_import = __import__ +try: + __import__("builtins").__import__ = custom_import +except AttributeError: + print("SKIP") + raise SystemExit + +# import calls __import__ behind the scenes +import pkg7.subpkg1.subpkg2.mod3 + + +try: + # globals must be a dict or None, not a string + orig_import("builtins", "globals", None, None, 0) +except TypeError: + print("TypeError") +try: + # ... same for relative imports (level > 0) + orig_import("builtins", "globals", None, None, 1) +except TypeError: + print("TypeError") diff --git a/tests/import/import_override2.py.exp b/tests/import/import_override2.py.exp new file mode 100644 index 0000000000000..99dd8d7ac2fcc --- /dev/null +++ b/tests/import/import_override2.py.exp @@ -0,0 +1,15 @@ +import pkg7.subpkg1.subpkg2.mod3 None 0 +pkg __name__: pkg7 +pkg __name__: pkg7.subpkg1 +pkg __name__: pkg7.subpkg1.subpkg2 +import ('mod1',) 3 +import pkg7.mod1 True 0 +mod1 +import mod2 ('bar',) 3 +mod2 +mod1.foo +mod2.bar +import ('mod1',) 4 +ImportError +TypeError +TypeError From 9a08ff625a3192d699304552e1c7f7afba19e63d Mon Sep 17 00:00:00 2001 From: Chris Liechti Date: Wed, 2 Dec 2020 00:38:30 +0100 Subject: [PATCH 14/14] extmod/uasyncio: Support for overriden __import__. globals() needs to be provided in case __import__ is a Python function --- extmod/uasyncio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/uasyncio/__init__.py b/extmod/uasyncio/__init__.py index fa64438f6b2a0..3361159587f24 100644 --- a/extmod/uasyncio/__init__.py +++ b/extmod/uasyncio/__init__.py @@ -25,6 +25,6 @@ def __getattr__(attr): mod = _attrs.get(attr, None) if mod is None: raise AttributeError(attr) - value = getattr(__import__(mod, None, None, True, 1), attr) + value = getattr(__import__(mod, globals(), None, True, 1), attr) globals()[attr] = value return value