diff options
author | Jim Mussared <jim.mussared@gmail.com> | 2023-05-10 13:02:09 +1000 |
---|---|---|
committer | Damien George <damien@micropython.org> | 2023-06-01 16:03:21 +1000 |
commit | 42f3f66431bb3131f5ee78f3e121491e9d0fb91d (patch) | |
tree | d645e0abf05402ff9123915dc0d840a8eb274da0 /py | |
parent | 69dd013919461272b3669a516ef98d60accd3165 (diff) |
py/builtinimport: Handle empty sys.path correctly.
If sys.path is enabled, but empty, this will now no longer search the
filesystem. Previously an empty sys.path was equivalent to having
`sys.path=[""]`. This is a breaking change, but this behavior now matches
CPython.
This also provides an alternative mechanism to the u-prefix to force an
import of a builtin module:
```
import sys
_path = sys.path[:]
sys.path.clear()
import foo # Forces the built-in foo.
sys.path.extend(_path)
del _path
```
Code size diff is -32 bytes on PYBV11.
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
Diffstat (limited to 'py')
-rw-r--r-- | py/builtinimport.c | 49 |
1 files changed, 26 insertions, 23 deletions
diff --git a/py/builtinimport.c b/py/builtinimport.c index e620c0377..025fff928 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -117,8 +117,9 @@ STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) { return stat_file_py_or_mpy(path); } -// Given a top-level module, try and find it in each of the sys.path entries -// via stat_dir_or_file. +// Given a top-level module name, try and find it in each of the sys.path +// entries. Note: On success, the dest argument will be updated to the matching +// path (i.e. "<entry>/mod_name(.py)"). STATIC mp_import_stat_t stat_top_level_dir_or_file(qstr mod_name, vstr_t *dest) { DEBUG_printf("stat_top_level_dir_or_file: '%s'\n", qstr_str(mod_name)); #if MICROPY_PY_SYS @@ -126,32 +127,34 @@ STATIC mp_import_stat_t stat_top_level_dir_or_file(qstr mod_name, vstr_t *dest) mp_obj_t *path_items; mp_obj_list_get(mp_sys_path, &path_num, &path_items); - if (path_num > 0) { - // go through each path looking for a directory or file - for (size_t i = 0; i < path_num; i++) { - vstr_reset(dest); - size_t p_len; - 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)); - mp_import_stat_t stat = stat_dir_or_file(dest); - if (stat != MP_IMPORT_STAT_NO_EXIST) { - return stat; - } + // go through each sys.path entry, trying to import "<entry>/<mod_name>". + for (size_t i = 0; i < path_num; i++) { + vstr_reset(dest); + size_t p_len; + const char *p = mp_obj_str_get_data(path_items[i], &p_len); + if (p_len > 0) { + // Add the path separator (unless the entry is "", i.e. cwd). + vstr_add_strn(dest, p, p_len); + vstr_add_char(dest, PATH_SEP_CHAR[0]); + } + vstr_add_str(dest, qstr_str(mod_name)); + mp_import_stat_t stat = stat_dir_or_file(dest); + if (stat != MP_IMPORT_STAT_NO_EXIST) { + return stat; } - - // could not find a directory or file - return MP_IMPORT_STAT_NO_EXIST; } - #endif - // mp_sys_path is empty (or not enabled), so just stat the given path - // directly. + // sys.path was empty or no matches, do not search the filesystem or + // frozen code. + return MP_IMPORT_STAT_NO_EXIST; + + #else + + // mp_sys_path is not enabled, so just stat the given path directly. vstr_add_str(dest, qstr_str(mod_name)); return stat_dir_or_file(dest); + + #endif } #if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER |