LCOV - code coverage report
Current view: top level - py - objmodule.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.19.1-992-g38e7b842c.info Lines: 83 83 100.0 %
Date: 2023-03-23 12:38:05 Functions: 9 9 100.0 %
Branches: 36 38 94.7 %

           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-2015 Paul Sokolovsky
       8                 :            :  *
       9                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
      10                 :            :  * of this software and associated documentation files (the "Software"), to deal
      11                 :            :  * in the Software without restriction, including without limitation the rights
      12                 :            :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      13                 :            :  * copies of the Software, and to permit persons to whom the Software is
      14                 :            :  * furnished to do so, subject to the following conditions:
      15                 :            :  *
      16                 :            :  * The above copyright notice and this permission notice shall be included in
      17                 :            :  * all copies or substantial portions of the Software.
      18                 :            :  *
      19                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      20                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      22                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      24                 :            :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      25                 :            :  * THE SOFTWARE.
      26                 :            :  */
      27                 :            : 
      28                 :            : #include <stdlib.h>
      29                 :            : #include <string.h>
      30                 :            : #include <assert.h>
      31                 :            : 
      32                 :            : #include "py/bc.h"
      33                 :            : #include "py/objmodule.h"
      34                 :            : #include "py/runtime.h"
      35                 :            : #include "py/builtin.h"
      36                 :            : 
      37                 :            : #ifndef NO_QSTR
      38                 :            : // Only include module definitions when not doing qstr extraction, because the
      39                 :            : // qstr extraction stage also generates this module definition header file.
      40                 :            : #include "genhdr/moduledefs.h"
      41                 :            : #endif
      42                 :            : 
      43                 :            : #if MICROPY_MODULE_BUILTIN_INIT
      44                 :            : STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj);
      45                 :            : #endif
      46                 :            : 
      47                 :         14 : STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
      48                 :         14 :     (void)kind;
      49                 :         14 :     mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
      50                 :            : 
      51                 :         14 :     const char *module_name = "";
      52                 :         14 :     mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_MAP_LOOKUP);
      53         [ +  - ]:         14 :     if (elem != NULL) {
      54                 :         14 :         module_name = mp_obj_str_get_str(elem->value);
      55                 :            :     }
      56                 :            : 
      57                 :            :     #if MICROPY_PY___FILE__
      58                 :            :     // If we store __file__ to imported modules then try to lookup this
      59                 :            :     // symbol to give more information about the module.
      60                 :         14 :     elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP);
      61         [ +  + ]:         14 :     if (elem != NULL) {
      62                 :          4 :         mp_printf(print, "<module '%s' from '%s'>", module_name, mp_obj_str_get_str(elem->value));
      63                 :          4 :         return;
      64                 :            :     }
      65                 :            :     #endif
      66                 :            : 
      67                 :         10 :     mp_printf(print, "<module '%s'>", module_name);
      68                 :            : }
      69                 :            : 
      70                 :       9728 : STATIC void module_attr_try_delegation(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
      71                 :            :     #if MICROPY_MODULE_ATTR_DELEGATION
      72                 :            :     // Delegate lookup to a module's custom attr method (found in last lot of globals dict).
      73                 :       9728 :     mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
      74                 :       9728 :     mp_map_t *map = &self->globals->map;
      75         [ +  + ]:       9728 :     if (map->table[map->alloc - 1].key == MP_OBJ_NEW_QSTR(MP_QSTRnull)) {
      76                 :       5446 :         ((mp_attr_fun_t)MP_OBJ_TO_PTR(map->table[map->alloc - 1].value))(self_in, attr, dest);
      77                 :            :     }
      78                 :            :     #else
      79                 :            :     (void)self_in;
      80                 :            :     (void)attr;
      81                 :            :     (void)dest;
      82                 :            :     #endif
      83                 :       9728 : }
      84                 :            : 
      85                 :     404042 : STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
      86                 :     404042 :     mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
      87         [ +  + ]:     404042 :     if (dest[0] == MP_OBJ_NULL) {
      88                 :            :         // load attribute
      89                 :     402157 :         mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
      90         [ +  + ]:     402111 :         if (elem != NULL) {
      91                 :     392358 :             dest[0] = elem->value;
      92                 :            :         #if MICROPY_CPYTHON_COMPAT
      93         [ +  + ]:       9753 :         } else if (attr == MP_QSTR___dict__) {
      94                 :         26 :             dest[0] = MP_OBJ_FROM_PTR(self->globals);
      95                 :            :         #endif
      96                 :            :         #if MICROPY_MODULE_GETATTR
      97         [ +  + ]:       9727 :         } else if (attr != MP_QSTR___getattr__) {
      98                 :       9721 :             elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___getattr__), MP_MAP_LOOKUP);
      99         [ +  + ]:       9721 :             if (elem != NULL) {
     100                 :         23 :                 dest[0] = mp_call_function_1(elem->value, MP_OBJ_NEW_QSTR(attr));
     101                 :            :             } else {
     102                 :       9698 :                 module_attr_try_delegation(self_in, attr, dest);
     103                 :            :             }
     104                 :            :         #endif
     105                 :            :         } else {
     106                 :          6 :             module_attr_try_delegation(self_in, attr, dest);
     107                 :            :         }
     108                 :            :     } else {
     109                 :            :         // delete/store attribute
     110                 :       1885 :         mp_obj_dict_t *dict = self->globals;
     111         [ +  + ]:       1885 :         if (dict->map.is_fixed) {
     112                 :            :             #if MICROPY_CAN_OVERRIDE_BUILTINS
     113         [ +  + ]:        124 :             if (dict == &mp_module_builtins_globals) {
     114         [ +  + ]:        100 :                 if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) {
     115                 :         32 :                     MP_STATE_VM(mp_module_builtins_override_dict) = MP_OBJ_TO_PTR(mp_obj_new_dict(1));
     116                 :            :                 }
     117                 :        100 :                 dict = MP_STATE_VM(mp_module_builtins_override_dict);
     118                 :            :             } else
     119                 :            :             #endif
     120                 :            :             {
     121                 :            :                 // can't delete or store to fixed map
     122                 :         24 :                 module_attr_try_delegation(self_in, attr, dest);
     123                 :         24 :                 return;
     124                 :            :             }
     125                 :            :         }
     126         [ +  + ]:       1861 :         if (dest[1] == MP_OBJ_NULL) {
     127                 :            :             // delete attribute
     128                 :          4 :             mp_obj_dict_delete(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr));
     129                 :            :         } else {
     130                 :            :             // store attribute
     131                 :       1857 :             mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr), dest[1]);
     132                 :            :         }
     133                 :       1861 :         dest[0] = MP_OBJ_NULL; // indicate success
     134                 :            :     }
     135                 :            : }
     136                 :            : 
     137                 :            : MP_DEFINE_CONST_OBJ_TYPE(
     138                 :            :     mp_type_module,
     139                 :            :     MP_QSTR_module,
     140                 :            :     MP_TYPE_FLAG_NONE,
     141                 :            :     print, module_print,
     142                 :            :     attr, module_attr
     143                 :            :     );
     144                 :            : 
     145                 :       1564 : mp_obj_t mp_obj_new_module(qstr module_name) {
     146                 :       1564 :     mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
     147                 :       1564 :     mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
     148                 :            :     // We could error out if module already exists, but let C extensions
     149                 :            :     // add new members to existing modules.
     150         [ +  - ]:       1564 :     if (el->value != MP_OBJ_NULL) {
     151                 :            :         return el->value;
     152                 :            :     }
     153                 :            : 
     154                 :            :     // create new module object
     155                 :       1564 :     mp_module_context_t *o = m_new_obj(mp_module_context_t);
     156                 :       1564 :     o->module.base.type = &mp_type_module;
     157                 :       1564 :     o->module.globals = MP_OBJ_TO_PTR(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE));
     158                 :            : 
     159                 :            :     // store __name__ entry in the module
     160                 :       1564 :     mp_obj_dict_store(MP_OBJ_FROM_PTR(o->module.globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(module_name));
     161                 :            : 
     162                 :            :     // store the new module into the slot in the global dict holding all modules
     163                 :       1564 :     el->value = MP_OBJ_FROM_PTR(o);
     164                 :            : 
     165                 :            :     // return the new module
     166                 :       1564 :     return MP_OBJ_FROM_PTR(o);
     167                 :            : }
     168                 :            : 
     169                 :            : /******************************************************************************/
     170                 :            : // Global module table and related functions
     171                 :            : 
     172                 :            : STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
     173                 :            :     // builtin modules declared with MP_REGISTER_MODULE()
     174                 :            :     MICROPY_REGISTERED_MODULES
     175                 :            : };
     176                 :            : 
     177                 :            : MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table);
     178                 :            : 
     179                 :            : // Tries to find a loaded module, otherwise attempts to load a builtin, otherwise MP_OBJ_NULL.
     180                 :       3099 : mp_obj_t mp_module_get_loaded_or_builtin(qstr module_name) {
     181                 :            :     // First try loaded modules.
     182                 :       3099 :     mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_VM(mp_loaded_modules_dict).map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
     183                 :            : 
     184         [ +  + ]:       3099 :     if (!elem) {
     185                 :            :         #if MICROPY_MODULE_WEAK_LINKS
     186                 :       2951 :         return mp_module_get_builtin(module_name);
     187                 :            :         #else
     188                 :            :         // Otherwise try builtin.
     189                 :            :         elem = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
     190                 :            :         if (!elem) {
     191                 :            :             return MP_OBJ_NULL;
     192                 :            :         }
     193                 :            : 
     194                 :            :         #if MICROPY_MODULE_BUILTIN_INIT
     195                 :            :         // If found, it's a newly loaded built-in, so init it.
     196                 :            :         mp_module_call_init(MP_OBJ_NEW_QSTR(module_name), elem->value);
     197                 :            :         #endif
     198                 :            :         #endif
     199                 :            :     }
     200                 :            : 
     201                 :        148 :     return elem->value;
     202                 :            : }
     203                 :            : 
     204                 :            : #if MICROPY_MODULE_WEAK_LINKS
     205                 :            : // Tries to find a loaded module, otherwise attempts to load a builtin, otherwise MP_OBJ_NULL.
     206                 :       3195 : mp_obj_t mp_module_get_builtin(qstr module_name) {
     207                 :            :     // Try builtin.
     208                 :       3195 :     mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
     209         [ +  + ]:       3195 :     if (!elem) {
     210                 :            :         return MP_OBJ_NULL;
     211                 :            :     }
     212                 :            : 
     213                 :            :     #if MICROPY_MODULE_BUILTIN_INIT
     214                 :            :     // If found, it's a newly loaded built-in, so init it.
     215                 :       1367 :     mp_module_call_init(MP_OBJ_NEW_QSTR(module_name), elem->value);
     216                 :            :     #endif
     217                 :            : 
     218                 :       1367 :     return elem->value;
     219                 :            : }
     220                 :            : #endif
     221                 :            : 
     222                 :            : #if MICROPY_MODULE_BUILTIN_INIT
     223                 :          8 : STATIC void mp_module_register(mp_obj_t module_name, mp_obj_t module) {
     224                 :          8 :     mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
     225                 :          8 :     mp_map_lookup(mp_loaded_modules_map, module_name, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module;
     226                 :          8 : }
     227                 :            : 
     228                 :       1367 : STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj) {
     229                 :            :     // Look for __init__ and call it if it exists
     230                 :       1367 :     mp_obj_t dest[2];
     231                 :       1367 :     mp_load_method_maybe(module_obj, MP_QSTR___init__, dest);
     232         [ +  + ]:       1367 :     if (dest[0] != MP_OBJ_NULL) {
     233                 :          8 :         mp_call_method_n_kw(0, 0, dest);
     234                 :            :         // Register module so __init__ is not called again.
     235                 :            :         // If a module can be referenced by more than one name (eg due to weak links)
     236                 :            :         // then __init__ will still be called for each distinct import, and it's then
     237                 :            :         // up to the particular module to make sure it's __init__ code only runs once.
     238                 :          8 :         mp_module_register(module_name, module_obj);
     239                 :            :     }
     240                 :       1367 : }
     241                 :            : #endif
     242                 :            : 
     243                 :       5446 : void mp_module_generic_attr(qstr attr, mp_obj_t *dest, const uint16_t *keys, mp_obj_t *values) {
     244         [ +  + ]:      21706 :     for (size_t i = 0; keys[i] != MP_QSTRnull; ++i) {
     245         [ +  + ]:      16308 :         if (attr == keys[i]) {
     246         [ +  + ]:         48 :             if (dest[0] == MP_OBJ_NULL) {
     247                 :            :                 // load attribute (MP_OBJ_NULL returned for deleted items)
     248                 :         28 :                 dest[0] = values[i];
     249                 :            :             } else {
     250                 :            :                 // delete or store (delete stores MP_OBJ_NULL)
     251                 :         20 :                 values[i] = dest[1];
     252                 :         20 :                 dest[0] = MP_OBJ_NULL; // indicate success
     253                 :            :             }
     254                 :         48 :             return;
     255                 :            :         }
     256                 :            :     }
     257                 :            : }

Generated by: LCOV version 1.15-5-g462f71d