diff --git a/py/builtinimport.c b/py/builtinimport.c index 6f1f7b485f04a..c267fd12b343d 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -131,12 +131,23 @@ STATIC mp_import_stat_t stat_top_level_dir_or_file(qstr mod_name, vstr_t *dest) for (size_t i = 0; i < path_num; i++) { vstr_reset(dest); size_t p_len; + const char *dot, *rest; const char *p = mp_obj_str_get_data(path_items[i], &p_len); if (p_len > 0) { vstr_add_strn(dest, p, p_len); vstr_add_char(dest, PATH_SEP_CHAR[0]); } - vstr_add_str(dest, qstr_str(mod_name)); + + // Convert the dotted module name to a path. + rest = qstr_str(mod_name); + dot = strchr(rest, '.'); + while (dot) { + vstr_add_strn(dest, rest, dot - rest); + vstr_add_char(dest, PATH_SEP_CHAR[0]); + rest = dot + 1; + dot = strchr(rest, '.'); + } + vstr_add_str(dest, rest); mp_import_stat_t stat = stat_dir_or_file(dest); if (stat != MP_IMPORT_STAT_NO_EXIST) { return stat; @@ -361,61 +372,47 @@ STATIC mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, // Exact-match of built-in (or already-loaded) takes priority. mp_obj_t module_obj = mp_module_get_loaded_or_builtin(full_mod_name); - // Even if we find the module, go through the motions of searching for it - // because we may actually be in the process of importing a sub-module. - // So we need to (re-)find the correct path to be finding the sub-module - // on the next iteration of process_import_at_level. + if (module_obj == MP_OBJ_NULL) { - if (outer_module_obj == MP_OBJ_NULL) { - DEBUG_printf("Searching for top-level module\n"); + DEBUG_printf("Searching for module %s\n", qstr_str(full_mod_name)); // First module in the dotted-name; search for a directory or file // relative to all the locations in sys.path. stat = stat_top_level_dir_or_file(full_mod_name, path); - // If the module "foo" doesn't exist on the filesystem, and it's not a - // builtin, try and find "ufoo" as a built-in. (This feature was - // formerly known as "weak links"). - #if MICROPY_MODULE_WEAK_LINKS - if (stat == MP_IMPORT_STAT_NO_EXIST && module_obj == MP_OBJ_NULL) { - qstr umodule_name = make_weak_link_name(path, level_mod_name); - module_obj = mp_module_get_builtin(umodule_name); - } - #elif MICROPY_PY_SYS - if (stat == MP_IMPORT_STAT_NO_EXIST && module_obj == MP_OBJ_NULL && level_mod_name == MP_QSTR_sys) { - module_obj = MP_OBJ_FROM_PTR(&mp_module_sys); + if (outer_module_obj == MP_OBJ_NULL) { + // If the module "foo" doesn't exist on the filesystem, and it's not a + // builtin, try and find "ufoo" as a built-in. (This feature was + // formerly known as "weak links"). + #if MICROPY_MODULE_WEAK_LINKS + if (stat == MP_IMPORT_STAT_NO_EXIST) { + qstr umodule_name = make_weak_link_name(path, level_mod_name); + module_obj = mp_module_get_builtin(umodule_name); + } + #elif MICROPY_PY_SYS + if (stat == MP_IMPORT_STAT_NO_EXIST && full_mod_name == MP_QSTR_sys) { + module_obj = MP_OBJ_FROM_PTR(&mp_module_sys); + } + #endif } - #endif - } else { - DEBUG_printf("Searching for sub-module\n"); - - // Add the current part of the module name to the path. - vstr_add_char(path, PATH_SEP_CHAR[0]); - vstr_add_str(path, qstr_str(level_mod_name)); - - // Because it's not top level, we already know which path the parent was found in. - stat = stat_dir_or_file(path); } - DEBUG_printf("Current path: %.*s\n", (int)vstr_len(path), vstr_str(path)); if (module_obj == MP_OBJ_NULL) { // Not a built-in and not already-loaded. - if (stat == MP_IMPORT_STAT_NO_EXIST) { - // And the file wasn't found -- fail. + // If the file wasn't found -- fail. #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found")); #else mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), full_mod_name); #endif } - // Not a built-in but found on the filesystem, try and load it. - DEBUG_printf("Found path: %.*s\n", (int)vstr_len(path), vstr_str(path)); // Prepare for loading from the filesystem. Create a new shell module. module_obj = mp_obj_new_module(full_mod_name); + DEBUG_printf("Prep %p\n", module_obj); #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT // If this module is being loaded via -m on unix, then diff --git a/tests/cpydiff/core_import_split_ns_pkgs.py b/tests/cpydiff/core_import_split_ns_pkgs.py index 62bf337a22bfa..392686fe24e05 100644 --- a/tests/cpydiff/core_import_split_ns_pkgs.py +++ b/tests/cpydiff/core_import_split_ns_pkgs.py @@ -1,15 +1,23 @@ """ categories: Core,import -description: MicroPython does't support namespace packages split across filesystem. -cause: MicroPython's import system is highly optimized for simplicity, minimal memory usage, and minimal filesystem search overhead. -workaround: Don't install modules belonging to the same namespace package in different directories. For MicroPython, it's recommended to have at most 3-component module search paths: for your current application, per-user (writable), system-wide (non-writable). +description: MicroPython loads non-namespace packages split across filesystems. +cause: MicroPython's import system is optimized for simplicity. +workaround: Not required. """ import sys sys.path.append(sys.path[1] + "/modules") sys.path.append(sys.path[1] + "/modules2") -import subpkg.foo +# import from the second subpackage first import subpkg.bar +import subpkg.foo + +print("Two modules of a split non-namespace package imported") + +import subpkg + +assert subpkg.one == 1 +assert not hasattr(subpkg, "two") -print("Two modules of a split namespace package imported") +print("The first module's __init__ is used") diff --git a/tests/cpydiff/modules/subpkg/__init__.py b/tests/cpydiff/modules/subpkg/__init__.py new file mode 100644 index 0000000000000..66fe6278619f8 --- /dev/null +++ b/tests/cpydiff/modules/subpkg/__init__.py @@ -0,0 +1,2 @@ +# Not a namespace package +one = 1 diff --git a/tests/cpydiff/modules2/subpkg/__init__.py b/tests/cpydiff/modules2/subpkg/__init__.py new file mode 100644 index 0000000000000..1f07b34aa673f --- /dev/null +++ b/tests/cpydiff/modules2/subpkg/__init__.py @@ -0,0 +1,2 @@ +# Not a namespace package +two = 2 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