LCOV - code coverage report
Current view: top level - py - builtinimport.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.22.0-344-ge60e8079a.info Lines: 201 201 100.0 %
Date: 2024-04-26 14:58:11 Functions: 11 11 100.0 %
Branches: 90 100 90.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of the MicroPython project, http://micropython.org/
       3                 :            :  *
       4                 :            :  * The MIT License (MIT)
       5                 :            :  *
       6                 :            :  * Copyright (c) 2013-2019 Damien P. George
       7                 :            :  * Copyright (c) 2014 Paul Sokolovsky
       8                 :            :  * Copyright (c) 2021 Jim Mussared
       9                 :            :  *
      10                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
      11                 :            :  * of this software and associated documentation files (the "Software"), to deal
      12                 :            :  * in the Software without restriction, including without limitation the rights
      13                 :            :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      14                 :            :  * copies of the Software, and to permit persons to whom the Software is
      15                 :            :  * furnished to do so, subject to the following conditions:
      16                 :            :  *
      17                 :            :  * The above copyright notice and this permission notice shall be included in
      18                 :            :  * all copies or substantial portions of the Software.
      19                 :            :  *
      20                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      21                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      23                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      25                 :            :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      26                 :            :  * THE SOFTWARE.
      27                 :            :  */
      28                 :            : 
      29                 :            : #include <stdio.h>
      30                 :            : #include <string.h>
      31                 :            : #include <assert.h>
      32                 :            : 
      33                 :            : #include "py/compile.h"
      34                 :            : #include "py/objmodule.h"
      35                 :            : #include "py/persistentcode.h"
      36                 :            : #include "py/runtime.h"
      37                 :            : #include "py/builtin.h"
      38                 :            : #include "py/frozenmod.h"
      39                 :            : 
      40                 :            : #if MICROPY_DEBUG_VERBOSE // print debugging info
      41                 :            : #define DEBUG_PRINT (1)
      42                 :            : #define DEBUG_printf DEBUG_printf
      43                 :            : #else // don't print debugging info
      44                 :            : #define DEBUG_PRINT (0)
      45                 :            : #define DEBUG_printf(...) (void)0
      46                 :            : #endif
      47                 :            : 
      48                 :            : #if MICROPY_ENABLE_EXTERNAL_IMPORT
      49                 :            : 
      50                 :            : // Must be a string of one byte.
      51                 :            : #define PATH_SEP_CHAR "/"
      52                 :            : 
      53                 :            : // Virtual sys.path entry that maps to the frozen modules.
      54                 :            : #define MP_FROZEN_PATH_PREFIX ".frozen/"
      55                 :            : 
      56                 :            : // Wrapper for mp_import_stat (which is provided by the port, and typically
      57                 :            : // uses mp_vfs_import_stat) to also search frozen modules. Given an exact
      58                 :            : // path to a file or directory (e.g. "foo/bar", foo/bar.py" or "foo/bar.mpy"),
      59                 :            : // will return whether the path is a file, directory, or doesn't exist.
      60                 :      12155 : static mp_import_stat_t stat_path(vstr_t *path) {
      61                 :      12155 :     const char *str = vstr_null_terminated_str(path);
      62                 :            :     #if MICROPY_MODULE_FROZEN
      63                 :            :     // Only try and load as a frozen module if it starts with .frozen/.
      64                 :      12155 :     const int frozen_path_prefix_len = strlen(MP_FROZEN_PATH_PREFIX);
      65         [ +  + ]:      12155 :     if (strncmp(str, MP_FROZEN_PATH_PREFIX, frozen_path_prefix_len) == 0) {
      66                 :            :         // Just stat (which is the return value), don't get the data.
      67                 :       2592 :         return mp_find_frozen_module(str + frozen_path_prefix_len, NULL, NULL);
      68                 :            :     }
      69                 :            :     #endif
      70                 :       9563 :     return mp_import_stat(str);
      71                 :            : }
      72                 :            : 
      73                 :            : // Stat a given filesystem path to a .py file. If the file does not exist,
      74                 :            : // then attempt to stat the corresponding .mpy file, and update the path
      75                 :            : // argument. This is the logic that makes .py files take precedent over .mpy
      76                 :            : // files. This uses stat_path above, rather than mp_import_stat directly, so
      77                 :            : // that the .frozen path prefix is handled.
      78                 :       4148 : static mp_import_stat_t stat_file_py_or_mpy(vstr_t *path) {
      79                 :       4148 :     mp_import_stat_t stat = stat_path(path);
      80         [ +  + ]:       4148 :     if (stat == MP_IMPORT_STAT_FILE) {
      81                 :            :         return stat;
      82                 :            :     }
      83                 :            : 
      84                 :            :     #if MICROPY_PERSISTENT_CODE_LOAD
      85                 :            :     // Didn't find .py -- try the .mpy instead by inserting an 'm' into the '.py'.
      86                 :            :     // Note: There's no point doing this if it's a frozen path, but adding the check
      87                 :            :     // would be extra code, and no harm letting mp_find_frozen_module fail instead.
      88                 :       3859 :     vstr_ins_byte(path, path->len - 2, 'm');
      89                 :       3859 :     stat = stat_path(path);
      90         [ +  + ]:       3859 :     if (stat == MP_IMPORT_STAT_FILE) {
      91                 :       1355 :         return stat;
      92                 :            :     }
      93                 :            :     #endif
      94                 :            : 
      95                 :            :     return MP_IMPORT_STAT_NO_EXIST;
      96                 :            : }
      97                 :            : 
      98                 :            : // Given an import path (e.g. "foo/bar"), try and find "foo/bar" (a directory)
      99                 :            : // or "foo/bar.(m)py" in either the filesystem or frozen modules. If the
     100                 :            : // result is a file, the path argument will be updated to include the file
     101                 :            : // extension.
     102                 :       4148 : static mp_import_stat_t stat_module(vstr_t *path) {
     103                 :       4148 :     mp_import_stat_t stat = stat_path(path);
     104                 :       4148 :     DEBUG_printf("stat %s: %d\n", vstr_str(path), stat);
     105         [ +  + ]:       4148 :     if (stat == MP_IMPORT_STAT_DIR) {
     106                 :            :         return stat;
     107                 :            :     }
     108                 :            : 
     109                 :            :     // Not a directory, add .py and try as a file.
     110                 :       4048 :     vstr_add_str(path, ".py");
     111                 :       4048 :     return stat_file_py_or_mpy(path);
     112                 :            : }
     113                 :            : 
     114                 :            : // Given a top-level module name, try and find it in each of the sys.path
     115                 :            : // entries. Note: On success, the dest argument will be updated to the matching
     116                 :            : // path (i.e. "<entry>/mod_name(.py)").
     117                 :       2263 : static mp_import_stat_t stat_top_level(qstr mod_name, vstr_t *dest) {
     118                 :       2263 :     DEBUG_printf("stat_top_level: '%s'\n", qstr_str(mod_name));
     119                 :            :     #if MICROPY_PY_SYS
     120                 :       2263 :     size_t path_num;
     121                 :       2263 :     mp_obj_t *path_items;
     122                 :       2263 :     mp_obj_get_array(mp_sys_path, &path_num, &path_items);
     123                 :            : 
     124                 :            :     // go through each sys.path entry, trying to import "<entry>/<mod_name>".
     125         [ +  + ]:       4757 :     for (size_t i = 0; i < path_num; i++) {
     126                 :       4013 :         vstr_reset(dest);
     127                 :       4013 :         size_t p_len;
     128                 :       4013 :         const char *p = mp_obj_str_get_data(path_items[i], &p_len);
     129         [ +  + ]:       4013 :         if (p_len > 0) {
     130                 :            :             // Add the path separator (unless the entry is "", i.e. cwd).
     131                 :       2535 :             vstr_add_strn(dest, p, p_len);
     132                 :       2535 :             vstr_add_char(dest, PATH_SEP_CHAR[0]);
     133                 :            :         }
     134                 :       4013 :         vstr_add_str(dest, qstr_str(mod_name));
     135                 :       4013 :         mp_import_stat_t stat = stat_module(dest);
     136         [ +  + ]:       4013 :         if (stat != MP_IMPORT_STAT_NO_EXIST) {
     137                 :       1519 :             return stat;
     138                 :            :         }
     139                 :            :     }
     140                 :            : 
     141                 :            :     // sys.path was empty or no matches, do not search the filesystem or
     142                 :            :     // frozen code.
     143                 :            :     return MP_IMPORT_STAT_NO_EXIST;
     144                 :            : 
     145                 :            :     #else
     146                 :            : 
     147                 :            :     // mp_sys_path is not enabled, so just stat the given path directly.
     148                 :            :     vstr_add_str(dest, qstr_str(mod_name));
     149                 :            :     return stat_module(dest);
     150                 :            : 
     151                 :            :     #endif
     152                 :            : }
     153                 :            : 
     154                 :            : #if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER
     155                 :        259 : static void do_load_from_lexer(mp_module_context_t *context, mp_lexer_t *lex) {
     156                 :            :     #if MICROPY_PY___FILE__
     157                 :        259 :     qstr source_name = lex->source_name;
     158                 :        259 :     mp_store_attr(MP_OBJ_FROM_PTR(&context->module), MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
     159                 :            :     #endif
     160                 :            : 
     161                 :            :     // parse, compile and execute the module in its context
     162                 :        259 :     mp_obj_dict_t *mod_globals = context->module.globals;
     163                 :        259 :     mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals);
     164                 :        249 : }
     165                 :            : #endif
     166                 :            : 
     167                 :            : #if (MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD) || MICROPY_MODULE_FROZEN_MPY
     168                 :       1367 : static void do_execute_proto_fun(const mp_module_context_t *context, mp_proto_fun_t proto_fun, qstr source_name) {
     169                 :            :     #if MICROPY_PY___FILE__
     170                 :       1367 :     mp_store_attr(MP_OBJ_FROM_PTR(&context->module), MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
     171                 :            :     #else
     172                 :            :     (void)source_name;
     173                 :            :     #endif
     174                 :            : 
     175                 :            :     // execute the module in its context
     176                 :       1367 :     mp_obj_dict_t *mod_globals = context->module.globals;
     177                 :            : 
     178                 :            :     // save context
     179                 :       1367 :     nlr_jump_callback_node_globals_locals_t ctx;
     180                 :       1367 :     ctx.globals = mp_globals_get();
     181                 :       1367 :     ctx.locals = mp_locals_get();
     182                 :            : 
     183                 :            :     // set new context
     184                 :       1367 :     mp_globals_set(mod_globals);
     185                 :       1367 :     mp_locals_set(mod_globals);
     186                 :            : 
     187                 :            :     // set exception handler to restore context if an exception is raised
     188                 :       1367 :     nlr_push_jump_callback(&ctx.callback, mp_globals_locals_set_from_nlr_jump_callback);
     189                 :            : 
     190                 :            :     // make and execute the function
     191                 :       1367 :     mp_obj_t module_fun = mp_make_function_from_proto_fun(proto_fun, context, NULL);
     192                 :       1367 :     mp_call_function_0(module_fun);
     193                 :            : 
     194                 :            :     // deregister exception handler and restore context
     195                 :       1361 :     nlr_pop_jump_callback(true);
     196                 :       1361 : }
     197                 :            : #endif
     198                 :            : 
     199                 :       1644 : static void do_load(mp_module_context_t *module_obj, vstr_t *file) {
     200                 :            :     #if MICROPY_MODULE_FROZEN || MICROPY_ENABLE_COMPILER || (MICROPY_PERSISTENT_CODE_LOAD && MICROPY_HAS_FILE_READER)
     201                 :       1644 :     const char *file_str = vstr_null_terminated_str(file);
     202                 :            :     #endif
     203                 :            : 
     204                 :            :     // If we support frozen modules (either as str or mpy) then try to find the
     205                 :            :     // requested filename in the list of frozen module filenames.
     206                 :            :     #if MICROPY_MODULE_FROZEN
     207                 :       1644 :     void *modref;
     208                 :       1644 :     int frozen_type;
     209                 :       1644 :     const int frozen_path_prefix_len = strlen(MP_FROZEN_PATH_PREFIX);
     210         [ +  + ]:       1644 :     if (strncmp(file_str, MP_FROZEN_PATH_PREFIX, frozen_path_prefix_len) == 0) {
     211                 :         36 :         mp_find_frozen_module(file_str + frozen_path_prefix_len, &frozen_type, &modref);
     212                 :            : 
     213                 :            :         // If we support frozen str modules and the compiler is enabled, and we
     214                 :            :         // found the filename in the list of frozen files, then load and execute it.
     215                 :            :         #if MICROPY_MODULE_FROZEN_STR
     216         [ +  + ]:         36 :         if (frozen_type == MP_FROZEN_STR) {
     217                 :          6 :             do_load_from_lexer(module_obj, modref);
     218                 :          6 :             return;
     219                 :            :         }
     220                 :            :         #endif
     221                 :            : 
     222                 :            :         // If we support frozen mpy modules and we found a corresponding file (and
     223                 :            :         // its data) in the list of frozen files, execute it.
     224                 :            :         #if MICROPY_MODULE_FROZEN_MPY
     225         [ +  - ]:         30 :         if (frozen_type == MP_FROZEN_MPY) {
     226                 :         30 :             const mp_frozen_module_t *frozen = modref;
     227                 :         30 :             module_obj->constants = frozen->constants;
     228                 :            :             #if MICROPY_PY___FILE__
     229                 :         30 :             qstr frozen_file_qstr = qstr_from_str(file_str + frozen_path_prefix_len);
     230                 :            :             #else
     231                 :            :             qstr frozen_file_qstr = MP_QSTRnull;
     232                 :            :             #endif
     233                 :         30 :             do_execute_proto_fun(module_obj, frozen->proto_fun, frozen_file_qstr);
     234                 :         30 :             return;
     235                 :            :         }
     236                 :            :         #endif
     237                 :            :     }
     238                 :            : 
     239                 :            :     #endif // MICROPY_MODULE_FROZEN
     240                 :            : 
     241                 :       1608 :     qstr file_qstr = qstr_from_str(file_str);
     242                 :            : 
     243                 :            :     // If we support loading .mpy files then check if the file extension is of
     244                 :            :     // the correct format and, if so, load and execute the file.
     245                 :            :     #if MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD
     246         [ +  + ]:       1608 :     if (file_str[file->len - 3] == 'm') {
     247                 :       1355 :         mp_compiled_module_t cm;
     248                 :       1355 :         cm.context = module_obj;
     249                 :       1355 :         mp_raw_code_load_file(file_qstr, &cm);
     250                 :       1337 :         do_execute_proto_fun(cm.context, cm.rc, file_qstr);
     251                 :       1333 :         return;
     252                 :            :     }
     253                 :            :     #endif
     254                 :            : 
     255                 :            :     // If we can compile scripts then load the file and compile and execute it.
     256                 :            :     #if MICROPY_ENABLE_COMPILER
     257                 :            :     {
     258                 :        253 :         mp_lexer_t *lex = mp_lexer_new_from_file(file_qstr);
     259                 :        253 :         do_load_from_lexer(module_obj, lex);
     260                 :        253 :         return;
     261                 :            :     }
     262                 :            :     #else
     263                 :            :     // If we get here then the file was not frozen and we can't compile scripts.
     264                 :            :     mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("script compilation not supported"));
     265                 :            :     #endif
     266                 :            : }
     267                 :            : 
     268                 :            : // Convert a relative (to the current module) import, going up "level" levels,
     269                 :            : // into an absolute import.
     270                 :        120 : static void evaluate_relative_import(mp_int_t level, const char **module_name, size_t *module_name_len) {
     271                 :            :     // What we want to do here is to take the name of the current module,
     272                 :            :     // remove <level> trailing components, and concatenate the passed-in
     273                 :            :     // module name.
     274                 :            :     // For example, level=3, module_name="foo.bar", __name__="a.b.c.d" --> "a.foo.bar"
     275                 :            :     // "Relative imports use a module's __name__ attribute to determine that
     276                 :            :     // module's position in the package hierarchy."
     277                 :            :     // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name
     278                 :            : 
     279                 :        120 :     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__));
     280         [ -  + ]:        120 :     assert(current_module_name_obj != MP_OBJ_NULL);
     281                 :            : 
     282                 :            :     #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT && MICROPY_CPYTHON_COMPAT
     283         [ +  + ]:        120 :     if (MP_OBJ_QSTR_VALUE(current_module_name_obj) == MP_QSTR___main__) {
     284                 :            :         // This is a module loaded by -m command-line switch (e.g. unix port),
     285                 :            :         // and so its __name__ has been set to "__main__". Get its real name
     286                 :            :         // that we stored during import in the __main__ attribute.
     287                 :          2 :         current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
     288                 :            :     }
     289                 :            :     #endif
     290                 :            : 
     291                 :            :     // If we have a __path__ in the globals dict, then we're a package.
     292                 :        118 :     bool is_pkg = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP);
     293                 :            : 
     294                 :            :     #if DEBUG_PRINT
     295                 :            :     DEBUG_printf("Current module/package: ");
     296                 :            :     mp_obj_print_helper(MICROPY_DEBUG_PRINTER, current_module_name_obj, PRINT_REPR);
     297                 :            :     DEBUG_printf(", is_package: %d", is_pkg);
     298                 :            :     DEBUG_printf("\n");
     299                 :            :     #endif
     300                 :            : 
     301                 :        118 :     size_t current_module_name_len;
     302                 :        118 :     const char *current_module_name = mp_obj_str_get_data(current_module_name_obj, &current_module_name_len);
     303                 :            : 
     304                 :        118 :     const char *p = current_module_name + current_module_name_len;
     305         [ +  + ]:        118 :     if (is_pkg) {
     306                 :            :         // If we're evaluating relative to a package, then take off one fewer
     307                 :            :         // level (i.e. the relative search starts inside the package, rather
     308                 :            :         // than as a sibling of the package).
     309                 :         83 :         --level;
     310                 :            :     }
     311                 :            : 
     312                 :            :     // Walk back 'level' dots (or run out of path).
     313         [ +  + ]:        435 :     while (level && p > current_module_name) {
     314         [ +  + ]:        317 :         if (*--p == '.') {
     315                 :         49 :             --level;
     316                 :            :         }
     317                 :            :     }
     318                 :            : 
     319                 :            :     // We must have some component left over to import from.
     320         [ +  + ]:        118 :     if (p == current_module_name) {
     321                 :          2 :         mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("can't perform relative import"));
     322                 :            :     }
     323                 :            : 
     324                 :            :     // New length is len("<chopped path>.<module_name>"). Note: might be one byte
     325                 :            :     // more than we need if module_name is empty (for the extra . we will
     326                 :            :     // append).
     327                 :        116 :     uint new_module_name_len = (size_t)(p - current_module_name) + 1 + *module_name_len;
     328                 :        116 :     char *new_mod = mp_local_alloc(new_module_name_len);
     329                 :        116 :     memcpy(new_mod, current_module_name, p - current_module_name);
     330                 :            : 
     331                 :            :     // Only append ".<module_name>" if there was one).
     332         [ +  + ]:        116 :     if (*module_name_len != 0) {
     333                 :         87 :         new_mod[p - current_module_name] = '.';
     334                 :         87 :         memcpy(new_mod + (p - current_module_name) + 1, *module_name, *module_name_len);
     335                 :            :     } else {
     336                 :            :         --new_module_name_len;
     337                 :            :     }
     338                 :            : 
     339                 :            :     // Copy into a QSTR.
     340                 :        116 :     qstr new_mod_q = qstr_from_strn(new_mod, new_module_name_len);
     341                 :        116 :     mp_local_free(new_mod);
     342                 :            : 
     343                 :        116 :     DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q));
     344                 :        116 :     *module_name = qstr_str(new_mod_q);
     345                 :        116 :     *module_name_len = new_module_name_len;
     346                 :        116 : }
     347                 :            : 
     348                 :            : typedef struct _nlr_jump_callback_node_unregister_module_t {
     349                 :            :     nlr_jump_callback_node_t callback;
     350                 :            :     qstr name;
     351                 :            : } nlr_jump_callback_node_unregister_module_t;
     352                 :            : 
     353                 :         34 : static void unregister_module_from_nlr_jump_callback(void *ctx_in) {
     354                 :         34 :     nlr_jump_callback_node_unregister_module_t *ctx = ctx_in;
     355                 :         34 :     mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
     356                 :         34 :     mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(ctx->name), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
     357                 :         34 : }
     358                 :            : 
     359                 :            : // Load a module at the specified absolute path, possibly as a submodule of the given outer module.
     360                 :            : // full_mod_name:    The full absolute path up to this level (e.g. "foo.bar.baz").
     361                 :            : // level_mod_name:   The final component of the path (e.g. "baz").
     362                 :            : // outer_module_obj: The parent module (we need to store this module as an
     363                 :            : //                   attribute on it) (or MP_OBJ_NULL for top-level).
     364                 :            : // override_main:    Whether to set the __name__ to "__main__" (and use __main__
     365                 :            : //                   for the actual path).
     366                 :       3423 : static mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, mp_obj_t outer_module_obj, bool override_main) {
     367                 :            :     // Immediately return if the module at this level is already loaded.
     368                 :       3423 :     mp_map_elem_t *elem;
     369                 :            : 
     370                 :            :     #if MICROPY_PY_SYS
     371                 :            :     // If sys.path is empty, the intention is to force using a built-in. This
     372                 :            :     // means we should also ignore any loaded modules with the same name
     373                 :            :     // which may have come from the filesystem.
     374                 :       3423 :     size_t path_num;
     375                 :       3423 :     mp_obj_t *path_items;
     376                 :       3423 :     mp_obj_get_array(mp_sys_path, &path_num, &path_items);
     377         [ +  + ]:       3423 :     if (path_num)
     378                 :            :     #endif
     379                 :            :     {
     380                 :       3421 :         elem = mp_map_lookup(&MP_STATE_VM(mp_loaded_modules_dict).map, MP_OBJ_NEW_QSTR(full_mod_name), MP_MAP_LOOKUP);
     381         [ +  + ]:       3421 :         if (elem) {
     382                 :        188 :             return elem->value;
     383                 :            :         }
     384                 :            :     }
     385                 :            : 
     386                 :       3235 :     VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX);
     387                 :       3235 :     mp_import_stat_t stat = MP_IMPORT_STAT_NO_EXIST;
     388                 :       3235 :     mp_obj_t module_obj;
     389                 :            : 
     390         [ +  + ]:       3235 :     if (outer_module_obj == MP_OBJ_NULL) {
     391                 :            :         // First module in the dotted-name path.
     392                 :       3096 :         DEBUG_printf("Searching for top-level module\n");
     393                 :            : 
     394                 :            :         // An import of a non-extensible built-in will always bypass the
     395                 :            :         // filesystem. e.g. `import micropython` or `import pyb`. So try and
     396                 :            :         // match a non-extensible built-ins first.
     397                 :       3096 :         module_obj = mp_module_get_builtin(level_mod_name, false);
     398         [ +  + ]:       3096 :         if (module_obj != MP_OBJ_NULL) {
     399                 :            :             return module_obj;
     400                 :            :         }
     401                 :            : 
     402                 :            :         // Next try the filesystem. Search for a directory or file relative to
     403                 :            :         // all the locations in sys.path.
     404                 :       2263 :         stat = stat_top_level(level_mod_name, &path);
     405                 :            : 
     406                 :            :         // If filesystem failed, now try and see if it matches an extensible
     407                 :            :         // built-in module.
     408         [ +  + ]:       2263 :         if (stat == MP_IMPORT_STAT_NO_EXIST) {
     409                 :        744 :             module_obj = mp_module_get_builtin(level_mod_name, true);
     410         [ +  + ]:        744 :             if (module_obj != MP_OBJ_NULL) {
     411                 :            :                 return module_obj;
     412                 :            :             }
     413                 :            :         }
     414                 :            :     } else {
     415                 :        139 :         DEBUG_printf("Searching for sub-module\n");
     416                 :            : 
     417                 :            :         #if MICROPY_MODULE_BUILTIN_SUBPACKAGES
     418                 :            :         // If the outer module is a built-in (because its map is in ROM), then
     419                 :            :         // treat it like a package if it contains this submodule in its
     420                 :            :         // globals dict.
     421                 :        139 :         mp_obj_module_t *mod = MP_OBJ_TO_PTR(outer_module_obj);
     422         [ +  + ]:        139 :         if (mod->globals->map.is_fixed) {
     423                 :          4 :             elem = mp_map_lookup(&mod->globals->map, MP_OBJ_NEW_QSTR(level_mod_name), MP_MAP_LOOKUP);
     424                 :            :             // Also verify that the entry in the globals dict is in fact a module.
     425   [ +  -  -  +  :          4 :             if (elem && mp_obj_is_type(elem->value, &mp_type_module)) {
          -  +  -  +  -  
             +  +  -  +  
                      - ]
     426                 :          4 :                 return elem->value;
     427                 :            :             }
     428                 :            :         }
     429                 :            :         #endif
     430                 :            : 
     431                 :            :         // If the outer module is a package, it will have __path__ set.
     432                 :            :         // We can use that as the path to search inside.
     433                 :        135 :         mp_obj_t dest[2];
     434                 :        135 :         mp_load_method_maybe(outer_module_obj, MP_QSTR___path__, dest);
     435         [ -  + ]:        135 :         if (dest[0] != MP_OBJ_NULL) {
     436                 :            :             // e.g. __path__ will be "<matched search path>/foo/bar"
     437                 :        135 :             vstr_add_str(&path, mp_obj_str_get_str(dest[0]));
     438                 :            : 
     439                 :            :             // Add the level module name to the path to get "<matched search path>/foo/bar/baz".
     440                 :        135 :             vstr_add_char(&path, PATH_SEP_CHAR[0]);
     441                 :        135 :             vstr_add_str(&path, qstr_str(level_mod_name));
     442                 :            : 
     443                 :        135 :             stat = stat_module(&path);
     444                 :            :         }
     445                 :            :     }
     446                 :            : 
     447                 :            :     // Not already loaded, and not a built-in, so look at the stat result from the filesystem/frozen.
     448                 :            : 
     449         [ +  + ]:        157 :     if (stat == MP_IMPORT_STAT_NO_EXIST) {
     450                 :            :         // Not found -- fail.
     451                 :            :         #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
     452                 :            :         mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found"));
     453                 :            :         #else
     454                 :         22 :         mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), full_mod_name);
     455                 :            :         #endif
     456                 :            :     }
     457                 :            : 
     458                 :            :     // Module was found on the filesystem/frozen, try and load it.
     459                 :       1654 :     DEBUG_printf("Found path to load: %.*s\n", (int)vstr_len(&path), vstr_str(&path));
     460                 :            : 
     461                 :            :     // Prepare for loading from the filesystem. Create a new shell module
     462                 :            :     // and register it in sys.modules.  Also make sure we remove it if
     463                 :            :     // there is any problem below.
     464                 :       1654 :     module_obj = mp_obj_new_module(full_mod_name);
     465                 :       1654 :     nlr_jump_callback_node_unregister_module_t ctx;
     466                 :       1654 :     ctx.name = full_mod_name;
     467                 :       1654 :     nlr_push_jump_callback(&ctx.callback, unregister_module_from_nlr_jump_callback);
     468                 :            : 
     469                 :            :     #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
     470                 :            :     // If this module is being loaded via -m on unix, then
     471                 :            :     // override __name__ to "__main__". Do this only for *modules*
     472                 :            :     // however - packages never have their names replaced, instead
     473                 :            :     // they're -m'ed using a special __main__ submodule in them. (This all
     474                 :            :     // apparently is done to not touch the package name itself, which is
     475                 :            :     // important for future imports).
     476         [ +  + ]:       1654 :     if (override_main && stat != MP_IMPORT_STAT_DIR) {
     477                 :       1325 :         mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj);
     478                 :       1325 :         mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
     479                 :            :         #if MICROPY_CPYTHON_COMPAT
     480                 :            :         // Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules).
     481                 :       1325 :         mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj);
     482                 :            :         // Store real name in "__main__" attribute. Need this for
     483                 :            :         // resolving relative imports later. "__main__ was chosen
     484                 :            :         // semi-randonly, to reuse existing qstr's.
     485                 :       1325 :         mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(full_mod_name));
     486                 :            :         #endif
     487                 :            :     }
     488                 :            :     #endif // MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
     489                 :            : 
     490         [ +  + ]:       1654 :     if (stat == MP_IMPORT_STAT_DIR) {
     491                 :            :         // Directory (i.e. a package).
     492                 :        100 :         DEBUG_printf("%.*s is dir\n", (int)vstr_len(&path), vstr_str(&path));
     493                 :            : 
     494                 :            :         // Store the __path__ attribute onto this module.
     495                 :            :         // https://docs.python.org/3/reference/import.html
     496                 :            :         // "Specifically, any module that contains a __path__ attribute is considered a package."
     497                 :            :         // This gets used later to locate any subpackages of this module.
     498                 :        100 :         mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path)));
     499                 :        100 :         size_t orig_path_len = path.len;
     500                 :        100 :         vstr_add_str(&path, PATH_SEP_CHAR "__init__.py");
     501                 :            : 
     502                 :            :         // execute "path/__init__.py" (if available).
     503         [ +  + ]:        100 :         if (stat_file_py_or_mpy(&path) == MP_IMPORT_STAT_FILE) {
     504                 :         90 :             do_load(MP_OBJ_TO_PTR(module_obj), &path);
     505                 :            :         } else {
     506                 :            :             // No-op. Nothing to load.
     507                 :            :             // mp_warning("%s is imported as namespace package", vstr_str(&path));
     508                 :        100 :         }
     509                 :            :         // Remove /__init__.py suffix from path.
     510                 :        100 :         path.len = orig_path_len;
     511                 :            :     } else { // MP_IMPORT_STAT_FILE
     512                 :            :         // File -- execute "path.(m)py".
     513                 :       1554 :         do_load(MP_OBJ_TO_PTR(module_obj), &path);
     514                 :            :         // Note: This should be the last component in the import path. If
     515                 :            :         // there are remaining components then in the next call to
     516                 :            :         // process_import_at_level will detect that it doesn't have
     517                 :            :         // a __path__ attribute, and not attempt to stat it.
     518                 :            :     }
     519                 :            : 
     520         [ +  + ]:       1620 :     if (outer_module_obj != MP_OBJ_NULL) {
     521                 :            :         // If it's a sub-module then make it available on the parent module.
     522                 :        127 :         mp_store_attr(outer_module_obj, level_mod_name, module_obj);
     523                 :            :     }
     524                 :            : 
     525                 :       1620 :     nlr_pop_jump_callback(false);
     526                 :            : 
     527                 :       1620 :     return module_obj;
     528                 :            : }
     529                 :            : 
     530                 :       3282 : mp_obj_t mp_builtin___import___default(size_t n_args, const mp_obj_t *args) {
     531                 :            :     #if DEBUG_PRINT
     532                 :            :     DEBUG_printf("__import__:\n");
     533                 :            :     for (size_t i = 0; i < n_args; i++) {
     534                 :            :         DEBUG_printf("  ");
     535                 :            :         mp_obj_print_helper(MICROPY_DEBUG_PRINTER, args[i], PRINT_REPR);
     536                 :            :         DEBUG_printf("\n");
     537                 :            :     }
     538                 :            :     #endif
     539                 :            : 
     540                 :            :     // This is the import path, with any leading dots stripped.
     541                 :            :     // "import foo.bar" --> module_name="foo.bar"
     542                 :            :     // "from foo.bar import baz" --> module_name="foo.bar"
     543                 :            :     // "from . import foo" --> module_name=""
     544                 :            :     // "from ...foo.bar import baz" --> module_name="foo.bar"
     545                 :       3282 :     mp_obj_t module_name_obj = args[0];
     546                 :            : 
     547                 :            :     // These are the imported names.
     548                 :            :     // i.e. "from foo.bar import baz, zap" --> fromtuple=("baz", "zap",)
     549                 :            :     // Note: There's a special case on the Unix port, where this is set to mp_const_false which means that it's __main__.
     550                 :       3282 :     mp_obj_t fromtuple = mp_const_none;
     551                 :            : 
     552                 :            :     // Level is the number of leading dots in a relative import.
     553                 :            :     // i.e. "from . import foo" --> level=1
     554                 :            :     // i.e. "from ...foo.bar import baz" --> level=3
     555                 :       3282 :     mp_int_t level = 0;
     556         [ +  + ]:       3282 :     if (n_args >= 4) {
     557                 :       3234 :         fromtuple = args[3];
     558         [ +  + ]:       3234 :         if (n_args >= 5) {
     559                 :       1905 :             level = MP_OBJ_SMALL_INT_VALUE(args[4]);
     560         [ +  + ]:       1905 :             if (level < 0) {
     561                 :          2 :                 mp_raise_ValueError(NULL);
     562                 :            :             }
     563                 :            :         }
     564                 :            :     }
     565                 :            : 
     566                 :       3280 :     size_t module_name_len;
     567                 :       3280 :     const char *module_name = mp_obj_str_get_data(module_name_obj, &module_name_len);
     568                 :            : 
     569         [ +  + ]:       3278 :     if (level != 0) {
     570                 :            :         // Turn "foo.bar" with level=3 into "<current module 3 components>.foo.bar".
     571                 :            :         // Current module name is extracted from globals().__name__.
     572                 :        120 :         evaluate_relative_import(level, &module_name, &module_name_len);
     573                 :            :         // module_name is now an absolute module path.
     574                 :            :     }
     575                 :            : 
     576         [ +  + ]:       3274 :     if (module_name_len == 0) {
     577                 :          2 :         mp_raise_ValueError(NULL);
     578                 :            :     }
     579                 :            : 
     580                 :            :     DEBUG_printf("Starting module search for '%s'\n", module_name);
     581                 :            : 
     582                 :            :     mp_obj_t top_module_obj = MP_OBJ_NULL;
     583                 :            :     mp_obj_t outer_module_obj = MP_OBJ_NULL;
     584                 :            : 
     585                 :            :     // Iterate the absolute path, finding the end of each component of the path.
     586                 :            :     // foo.bar.baz
     587                 :            :     //    ^   ^   ^
     588                 :            :     size_t current_component_start = 0;
     589         [ +  + ]:      31829 :     for (size_t i = 1; i <= module_name_len; i++) {
     590   [ +  +  +  + ]:      28619 :         if (i == module_name_len || module_name[i] == '.') {
     591                 :            :             // The module name up to this depth (e.g. foo.bar.baz).
     592                 :       3429 :             qstr full_mod_name = qstr_from_strn(module_name, i);
     593                 :            :             // The current level name (e.g. baz).
     594                 :       3423 :             qstr level_mod_name = qstr_from_strn(module_name + current_component_start, i - current_component_start);
     595                 :            : 
     596                 :       3423 :             DEBUG_printf("Processing module: '%s' at level '%s'\n", qstr_str(full_mod_name), qstr_str(level_mod_name));
     597                 :            : 
     598                 :            :             #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
     599                 :            :             // On unix, if this is being loaded via -m (indicated by sentinel
     600                 :            :             // fromtuple=mp_const_false), then handle that if it's the final
     601                 :            :             // component.
     602   [ +  +  +  + ]:       3423 :             bool override_main = (i == module_name_len && fromtuple == mp_const_false);
     603                 :            :             #else
     604                 :            :             bool override_main = false;
     605                 :            :             #endif
     606                 :            : 
     607                 :            :             // Import this module.
     608                 :       3423 :             mp_obj_t module_obj = process_import_at_level(full_mod_name, level_mod_name, outer_module_obj, override_main);
     609                 :            : 
     610                 :            :             // Set this as the parent module, and remember the top-level module if it's the first.
     611                 :       3367 :             outer_module_obj = module_obj;
     612         [ +  + ]:       3367 :             if (top_module_obj == MP_OBJ_NULL) {
     613                 :       3218 :                 top_module_obj = module_obj;
     614                 :            :             }
     615                 :            : 
     616                 :       3367 :             current_component_start = i + 1;
     617                 :            :         }
     618                 :            :     }
     619                 :            : 
     620         [ +  + ]:       3210 :     if (fromtuple != mp_const_none) {
     621                 :            :         // If fromtuple is not empty, return leaf module
     622                 :            :         return outer_module_obj;
     623                 :            :     } else {
     624                 :            :         // Otherwise, we need to return top-level package
     625                 :       1373 :         return top_module_obj;
     626                 :            :     }
     627                 :            : }
     628                 :            : 
     629                 :            : #else // MICROPY_ENABLE_EXTERNAL_IMPORT
     630                 :            : 
     631                 :            : mp_obj_t mp_builtin___import___default(size_t n_args, const mp_obj_t *args) {
     632                 :            :     // Check that it's not a relative import.
     633                 :            :     if (n_args >= 5 && MP_OBJ_SMALL_INT_VALUE(args[4]) != 0) {
     634                 :            :         mp_raise_NotImplementedError(MP_ERROR_TEXT("relative import"));
     635                 :            :     }
     636                 :            : 
     637                 :            :     // Check if the module is already loaded.
     638                 :            :     mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_VM(mp_loaded_modules_dict).map, args[0], MP_MAP_LOOKUP);
     639                 :            :     if (elem) {
     640                 :            :         return elem->value;
     641                 :            :     }
     642                 :            : 
     643                 :            :     // Try the name directly as a non-extensible built-in (e.g. `micropython`).
     644                 :            :     qstr module_name_qstr = mp_obj_str_get_qstr(args[0]);
     645                 :            :     mp_obj_t module_obj = mp_module_get_builtin(module_name_qstr, false);
     646                 :            :     if (module_obj != MP_OBJ_NULL) {
     647                 :            :         return module_obj;
     648                 :            :     }
     649                 :            :     // Now try as an extensible built-in (e.g. `time`).
     650                 :            :     module_obj = mp_module_get_builtin(module_name_qstr, true);
     651                 :            :     if (module_obj != MP_OBJ_NULL) {
     652                 :            :         return module_obj;
     653                 :            :     }
     654                 :            : 
     655                 :            :     // Couldn't find the module, so fail
     656                 :            :     #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
     657                 :            :     mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found"));
     658                 :            :     #else
     659                 :            :     mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), module_name_qstr);
     660                 :            :     #endif
     661                 :            : }
     662                 :            : 
     663                 :            : #endif // MICROPY_ENABLE_EXTERNAL_IMPORT
     664                 :            : 
     665                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj, 1, 5, mp_builtin___import__);

Generated by: LCOV version 1.15-5-g462f71d