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 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