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 : 15400162 : static void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
63 : 15400162 : mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
64 [ + + ]: 15400162 : if (dest[0] == MP_OBJ_NULL) {
65 : : // load attribute
66 : 15398077 : mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
67 [ + + ]: 15398030 : if (elem != NULL) {
68 : 15387519 : dest[0] = elem->value;
69 : : #if MICROPY_CPYTHON_COMPAT
70 [ + + ]: 10511 : } else if (attr == MP_QSTR___dict__) {
71 : 26 : dest[0] = MP_OBJ_FROM_PTR(self->globals);
72 : : #endif
73 : : #if MICROPY_MODULE_GETATTR
74 [ + + ]: 10485 : } else if (attr != MP_QSTR___getattr__) {
75 : 10479 : elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___getattr__), MP_MAP_LOOKUP);
76 [ + + ]: 10479 : if (elem != NULL) {
77 : 40 : dest[0] = mp_call_function_1(elem->value, MP_OBJ_NEW_QSTR(attr));
78 : : } else {
79 : 10439 : 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 : 2085 : mp_obj_dict_t *dict = self->globals;
88 [ + + ]: 2085 : 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 [ + + ]: 2057 : 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 : 2053 : mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr), dest[1]);
109 : : }
110 : 2057 : 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 : 1725 : mp_obj_t mp_obj_new_module(qstr module_name) {
123 : 1725 : mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
124 : 1725 : 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 [ + - ]: 1725 : if (el->value != MP_OBJ_NULL) {
128 : : return el->value;
129 : : }
130 : :
131 : : // create new module object
132 : 1725 : mp_module_context_t *o = m_new_obj(mp_module_context_t);
133 : 1725 : o->module.base.type = &mp_type_module;
134 : 1725 : o->module.globals = MP_OBJ_TO_PTR(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE));
135 : :
136 : : // store __name__ entry in the module
137 : 1725 : 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 : 1725 : el->value = MP_OBJ_FROM_PTR(o);
141 : :
142 : : // return the new module
143 : 1725 : 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 : 4072 : mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible) {
176 [ + + ]: 7356 : 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 [ + + ]: 4072 : 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 [ + + ]: 2391 : if (module_name == MP_QSTR_usys) {
182 : 2385 : return MP_OBJ_FROM_PTR(&mp_module_sys);
183 : : }
184 : : #endif
185 : :
186 [ + + ]: 2389 : 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 : 2367 : size_t module_name_len;
202 : 2367 : const char *module_name_str = (const char *)qstr_data(module_name, &module_name_len);
203 [ + + ]: 2367 : 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 : 1687 : mp_obj_t dest[2];
217 : 1687 : mp_load_method_maybe(elem->value, MP_QSTR___init__, dest);
218 [ + + ]: 1687 : if (dest[0] != MP_OBJ_NULL) {
219 : 14 : mp_call_method_n_kw(0, 0, dest);
220 : : }
221 : : #endif
222 : :
223 : 1687 : return elem->value;
224 : : }
225 : :
226 : 10473 : 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 : 10473 : size_t n = MP_ARRAY_SIZE(mp_builtin_module_delegation_table);
230 [ + + ]: 15111 : for (size_t i = 0; i < n; ++i) {
231 [ + + ]: 10473 : if (*(mp_obj_t *)(&mp_builtin_module_delegation_table[i].mod) == self_in) {
232 : 5835 : mp_builtin_module_delegation_table[i].fun(self_in, attr, dest);
233 : 5835 : break;
234 : : }
235 : : }
236 : : #else
237 : : (void)self_in;
238 : : (void)attr;
239 : : (void)dest;
240 : : #endif
241 : 10473 : }
242 : :
243 : 5835 : void mp_module_generic_attr(qstr attr, mp_obj_t *dest, const uint16_t *keys, mp_obj_t *values) {
244 [ + + ]: 28833 : for (size_t i = 0; keys[i] != MP_QSTRnull; ++i) {
245 [ + + ]: 23112 : 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 : : }
|