py/builtinimport: Allow builtin modules to be packages.
To use this: - Create a built-in module, and add the module object as a member of the parent module's globals dict. - The submodule can set its `__name__` to either `QSTR_foo_dot_bar` or `QSTR_bar`. The former requires using qstrdefs(port).h to make the qstr. Because `bar` is a member of `foo`'s globals, it is possible to write `import foo` and then immediately use `foo.bar` without importing it explicitly. This means that if `bar` has an `__init__`, it will not be called in this situation, and for that reason, sub-modules should not have `__init__` methods. If this is required, then all initalisation for sub-modules should be done by the top-level module's (i.e. `foo`'s) `__init__` method. This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This commit is contained in:
parent
525557738c
commit
ed90f30dd5
|
@ -428,6 +428,20 @@ STATIC mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name,
|
|||
} else {
|
||||
DEBUG_printf("Searching for sub-module\n");
|
||||
|
||||
#if MICROPY_MODULE_BUILTIN_SUBPACKAGES
|
||||
// If the outer module is a built-in (because its map is in ROM), then
|
||||
// treat it like a package if it contains this submodule in its
|
||||
// globals dict.
|
||||
mp_obj_module_t *mod = MP_OBJ_TO_PTR(outer_module_obj);
|
||||
if (mod->globals->map.is_fixed) {
|
||||
elem = mp_map_lookup(&mod->globals->map, MP_OBJ_NEW_QSTR(level_mod_name), MP_MAP_LOOKUP);
|
||||
// Also verify that the entry in the globals dict is in fact a module.
|
||||
if (elem && mp_obj_is_type(elem->value, &mp_type_module)) {
|
||||
return elem->value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// If the outer module is a package, it will have __path__ set.
|
||||
// We can use that as the path to search inside.
|
||||
mp_obj_t dest[2];
|
||||
|
|
|
@ -850,6 +850,20 @@ typedef double mp_float_t;
|
|||
#define MICROPY_MODULE_BUILTIN_INIT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
|
||||
#endif
|
||||
|
||||
// Whether to allow built-in modules to have sub-packages (by making the
|
||||
// sub-package a member of their locals dict). Sub-packages should not be
|
||||
// registered with MP_REGISTER_MODULE, instead they should be added as
|
||||
// members of the parent's globals dict. To match CPython behavior,
|
||||
// their __name__ should be "foo.bar"(i.e. QSTR_foo_dot_bar) which will
|
||||
// require an entry in qstrdefs, although it does also work to just call
|
||||
// it "bar". Also, because subpackages can be accessed without being
|
||||
// imported (e.g. as foo.bar after `import foo`), they should not
|
||||
// have __init__ methods. Instead, the top-level package's __init__ should
|
||||
// initialise all sub-packages.
|
||||
#ifndef MICROPY_MODULE_BUILTIN_SUBPACKAGES
|
||||
#define MICROPY_MODULE_BUILTIN_SUBPACKAGES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING)
|
||||
#endif
|
||||
|
||||
// Whether to support module-level __getattr__ (see PEP 562)
|
||||
#ifndef MICROPY_MODULE_GETATTR
|
||||
#define MICROPY_MODULE_GETATTR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
|
||||
|
|
Loading…
Reference in New Issue