LCOV - code coverage report
Current view: top level - py - objmodule.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.22.0-344-ge60e8079a.info Lines: 79 79 100.0 %
Date: 2024-04-26 14:58:11 Functions: 6 6 100.0 %
Branches: 46 48 95.8 %

           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                 :         40 : static void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
      38                 :         40 :     (void)kind;
      39                 :         40 :     mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
      40                 :            : 
      41                 :         40 :     const char *module_name = "";
      42                 :         40 :     mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_MAP_LOOKUP);
      43         [ +  - ]:         40 :     if (elem != NULL) {
      44                 :         40 :         module_name = mp_obj_str_get_str(elem->value);
      45                 :            :     }
      46                 :            : 
      47                 :            :     #if MICROPY_PY___FILE__
      48                 :            :     // If we store __file__ to imported modules then try to lookup this
      49                 :            :     // symbol to give more information about the module.
      50                 :         40 :     elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP);
      51         [ +  + ]:         40 :     if (elem != NULL) {
      52                 :         10 :         mp_printf(print, "<module '%s' from '%s'>", module_name, mp_obj_str_get_str(elem->value));
      53                 :         10 :         return;
      54                 :            :     }
      55                 :            :     #endif
      56                 :            : 
      57                 :         30 :     mp_printf(print, "<module '%s'>", module_name);
      58                 :            : }
      59                 :            : 
      60                 :            : static void module_attr_try_delegation(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
      61                 :            : 
      62                 :     321369 : static void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
      63                 :     321369 :     mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
      64         [ +  + ]:     321369 :     if (dest[0] == MP_OBJ_NULL) {
      65                 :            :         // load attribute
      66                 :     319380 :         mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
      67         [ +  + ]:     319380 :         if (elem != NULL) {
      68                 :     309151 :             dest[0] = elem->value;
      69                 :            :         #if MICROPY_CPYTHON_COMPAT
      70         [ +  + ]:      10229 :         } else if (attr == MP_QSTR___dict__) {
      71                 :         26 :             dest[0] = MP_OBJ_FROM_PTR(self->globals);
      72                 :            :         #endif
      73                 :            :         #if MICROPY_MODULE_GETATTR
      74         [ +  + ]:      10203 :         } else if (attr != MP_QSTR___getattr__) {
      75                 :      10197 :             elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___getattr__), MP_MAP_LOOKUP);
      76         [ +  + ]:      10197 :             if (elem != NULL) {
      77                 :         27 :                 dest[0] = mp_call_function_1(elem->value, MP_OBJ_NEW_QSTR(attr));
      78                 :            :             } else {
      79                 :      10170 :                 module_attr_try_delegation(self_in, attr, dest);
      80                 :            :             }
      81                 :            :         #endif
      82                 :            :         } else {
      83                 :          6 :             module_attr_try_delegation(self_in, attr, dest);
      84                 :            :         }
      85                 :            :     } else {
      86                 :            :         // delete/store attribute
      87                 :       1989 :         mp_obj_dict_t *dict = self->globals;
      88         [ +  + ]:       1989 :         if (dict->map.is_fixed) {
      89                 :            :             #if MICROPY_CAN_OVERRIDE_BUILTINS
      90         [ +  + ]:        128 :             if (dict == &mp_module_builtins_globals) {
      91         [ +  + ]:        100 :                 if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) {
      92                 :         32 :                     MP_STATE_VM(mp_module_builtins_override_dict) = MP_OBJ_TO_PTR(mp_obj_new_dict(1));
      93                 :            :                 }
      94                 :        100 :                 dict = MP_STATE_VM(mp_module_builtins_override_dict);
      95                 :            :             } else
      96                 :            :             #endif
      97                 :            :             {
      98                 :            :                 // can't delete or store to fixed map
      99                 :         28 :                 module_attr_try_delegation(self_in, attr, dest);
     100                 :         28 :                 return;
     101                 :            :             }
     102                 :            :         }
     103         [ +  + ]:       1961 :         if (dest[1] == MP_OBJ_NULL) {
     104                 :            :             // delete attribute
     105                 :          4 :             mp_obj_dict_delete(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr));
     106                 :            :         } else {
     107                 :            :             // store attribute
     108                 :       1957 :             mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr), dest[1]);
     109                 :            :         }
     110                 :       1961 :         dest[0] = MP_OBJ_NULL; // indicate success
     111                 :            :     }
     112                 :            : }
     113                 :            : 
     114                 :            : MP_DEFINE_CONST_OBJ_TYPE(
     115                 :            :     mp_type_module,
     116                 :            :     MP_QSTR_module,
     117                 :            :     MP_TYPE_FLAG_NONE,
     118                 :            :     print, module_print,
     119                 :            :     attr, module_attr
     120                 :            :     );
     121                 :            : 
     122                 :       1654 : mp_obj_t mp_obj_new_module(qstr module_name) {
     123                 :       1654 :     mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
     124                 :       1654 :     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);
     125                 :            :     // We could error out if module already exists, but let C extensions
     126                 :            :     // add new members to existing modules.
     127         [ +  - ]:       1654 :     if (el->value != MP_OBJ_NULL) {
     128                 :            :         return el->value;
     129                 :            :     }
     130                 :            : 
     131                 :            :     // create new module object
     132                 :       1654 :     mp_module_context_t *o = m_new_obj(mp_module_context_t);
     133                 :       1654 :     o->module.base.type = &mp_type_module;
     134                 :       1654 :     o->module.globals = MP_OBJ_TO_PTR(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE));
     135                 :            : 
     136                 :            :     // store __name__ entry in the module
     137                 :       1654 :     mp_obj_dict_store(MP_OBJ_FROM_PTR(o->module.globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(module_name));
     138                 :            : 
     139                 :            :     // store the new module into the slot in the global dict holding all modules
     140                 :       1654 :     el->value = MP_OBJ_FROM_PTR(o);
     141                 :            : 
     142                 :            :     // return the new module
     143                 :       1654 :     return MP_OBJ_FROM_PTR(o);
     144                 :            : }
     145                 :            : 
     146                 :            : /******************************************************************************/
     147                 :            : // Global module table and related functions
     148                 :            : 
     149                 :            : static const mp_rom_map_elem_t mp_builtin_module_table[] = {
     150                 :            :     // built-in modules declared with MP_REGISTER_MODULE()
     151                 :            :     MICROPY_REGISTERED_MODULES
     152                 :            : };
     153                 :            : MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table);
     154                 :            : 
     155                 :            : static const mp_rom_map_elem_t mp_builtin_extensible_module_table[] = {
     156                 :            :     // built-in modules declared with MP_REGISTER_EXTENSIBLE_MODULE()
     157                 :            :     MICROPY_REGISTERED_EXTENSIBLE_MODULES
     158                 :            : };
     159                 :            : MP_DEFINE_CONST_MAP(mp_builtin_extensible_module_map, mp_builtin_extensible_module_table);
     160                 :            : 
     161                 :            : #if MICROPY_MODULE_ATTR_DELEGATION && defined(MICROPY_MODULE_DELEGATIONS)
     162                 :            : typedef struct _mp_module_delegation_entry_t {
     163                 :            :     mp_rom_obj_t mod;
     164                 :            :     mp_attr_fun_t fun;
     165                 :            : } mp_module_delegation_entry_t;
     166                 :            : 
     167                 :            : static const mp_module_delegation_entry_t mp_builtin_module_delegation_table[] = {
     168                 :            :     // delegation entries declared with MP_REGISTER_MODULE_DELEGATION()
     169                 :            :     MICROPY_MODULE_DELEGATIONS
     170                 :            : };
     171                 :            : #endif
     172                 :            : 
     173                 :            : // Attempts to find (and initialise) a built-in, otherwise returns
     174                 :            : // MP_OBJ_NULL.
     175                 :       3840 : mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible) {
     176         [ +  + ]:       6936 :     mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)(extensible ? &mp_builtin_extensible_module_map : &mp_builtin_module_map), MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
     177         [ +  + ]:       3840 :     if (!elem) {
     178                 :            :         #if MICROPY_PY_SYS
     179                 :            :         // Special case for sys, which isn't extensible but can always be
     180                 :            :         // imported with the alias `usys`.
     181         [ +  + ]:       2293 :         if (module_name == MP_QSTR_usys) {
     182                 :       2287 :             return MP_OBJ_FROM_PTR(&mp_module_sys);
     183                 :            :         }
     184                 :            :         #endif
     185                 :            : 
     186         [ +  + ]:       2291 :         if (extensible) {
     187                 :            :             // At this point we've already tried non-extensible built-ins, the
     188                 :            :             // filesystem, and now extensible built-ins. No match, so fail
     189                 :            :             // the import.
     190                 :            :             return MP_OBJ_NULL;
     191                 :            :         }
     192                 :            : 
     193                 :            :         // We're trying to match a non-extensible built-in (i.e. before trying
     194                 :            :         // the filesystem), but if the user is importing `ufoo`, _and_ `foo`
     195                 :            :         // is an extensible module, then allow it as a way of forcing the
     196                 :            :         // built-in. Essentially, this makes it as if all the extensible
     197                 :            :         // built-ins also had non-extensible aliases named `ufoo`. Newer code
     198                 :            :         // should be using sys.path to force the built-in, but this retains
     199                 :            :         // the old behaviour of the u-prefix being used to force a built-in
     200                 :            :         // import.
     201                 :       2269 :         size_t module_name_len;
     202                 :       2269 :         const char *module_name_str = (const char *)qstr_data(module_name, &module_name_len);
     203         [ +  + ]:       2269 :         if (module_name_str[0] != 'u') {
     204                 :            :             return MP_OBJ_NULL;
     205                 :            :         }
     206                 :         20 :         elem = mp_map_lookup((mp_map_t *)&mp_builtin_extensible_module_map, MP_OBJ_NEW_QSTR(qstr_from_strn(module_name_str + 1, module_name_len - 1)), MP_MAP_LOOKUP);
     207         [ +  + ]:         20 :         if (!elem) {
     208                 :            :             return MP_OBJ_NULL;
     209                 :            :         }
     210                 :            :     }
     211                 :            : 
     212                 :            :     #if MICROPY_MODULE_BUILTIN_INIT
     213                 :            :     // If found, it's a newly loaded built-in, so init it. This can run
     214                 :            :     // multiple times, so the module must ensure that it handles being
     215                 :            :     // initialised multiple times.
     216                 :       1553 :     mp_obj_t dest[2];
     217                 :       1553 :     mp_load_method_maybe(elem->value, MP_QSTR___init__, dest);
     218         [ +  + ]:       1553 :     if (dest[0] != MP_OBJ_NULL) {
     219                 :         14 :         mp_call_method_n_kw(0, 0, dest);
     220                 :            :     }
     221                 :            :     #endif
     222                 :            : 
     223                 :       1553 :     return elem->value;
     224                 :            : }
     225                 :            : 
     226                 :      10204 : static void module_attr_try_delegation(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
     227                 :            :     #if MICROPY_MODULE_ATTR_DELEGATION && defined(MICROPY_MODULE_DELEGATIONS)
     228                 :            :     // Delegate lookup to a module's custom attr method.
     229                 :      10204 :     size_t n = MP_ARRAY_SIZE(mp_builtin_module_delegation_table);
     230         [ +  + ]:      14682 :     for (size_t i = 0; i < n; ++i) {
     231         [ +  + ]:      10204 :         if (*(mp_obj_t *)(&mp_builtin_module_delegation_table[i].mod) == self_in) {
     232                 :       5726 :             mp_builtin_module_delegation_table[i].fun(self_in, attr, dest);
     233                 :       5726 :             break;
     234                 :            :         }
     235                 :            :     }
     236                 :            :     #else
     237                 :            :     (void)self_in;
     238                 :            :     (void)attr;
     239                 :            :     (void)dest;
     240                 :            :     #endif
     241                 :      10204 : }
     242                 :            : 
     243                 :       5726 : void mp_module_generic_attr(qstr attr, mp_obj_t *dest, const uint16_t *keys, mp_obj_t *values) {
     244         [ +  + ]:      28288 :     for (size_t i = 0; keys[i] != MP_QSTRnull; ++i) {
     245         [ +  + ]:      22676 :         if (attr == keys[i]) {
     246         [ +  + ]:        114 :             if (dest[0] == MP_OBJ_NULL) {
     247                 :            :                 // load attribute (MP_OBJ_NULL returned for deleted items)
     248                 :         90 :                 dest[0] = values[i];
     249                 :            :             } else {
     250                 :            :                 // delete or store (delete stores MP_OBJ_NULL)
     251                 :         24 :                 values[i] = dest[1];
     252                 :         24 :                 dest[0] = MP_OBJ_NULL; // indicate success
     253                 :            :             }
     254                 :        114 :             return;
     255                 :            :         }
     256                 :            :     }
     257                 :            : }

Generated by: LCOV version 1.15-5-g462f71d