From 91ba7a54c51958a584f3dd404be7d62b5ec0bbd9 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 16 Feb 2014 02:53:44 +0200 Subject: [PATCH] builtinimport: Get the basic (and only basic) package imports work. --- py/builtinimport.c | 35 ++++++++++++++++++++++++++++------- tests/basics/import-pkg1.py | 11 +++++++++++ tests/basics/pkg/__init__.py | 0 tests/basics/pkg/mod.py | 2 ++ 4 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 tests/basics/import-pkg1.py create mode 100644 tests/basics/pkg/__init__.py create mode 100644 tests/basics/pkg/mod.py diff --git a/py/builtinimport.c b/py/builtinimport.c index ae03f8c52..0a730b031 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -139,18 +139,28 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { } */ + uint mod_len; + const char *mod_str = (const char*)mp_obj_str_get_data(args[0], &mod_len); + // check if module already exists mp_obj_t module_obj = mp_obj_module_get(mp_obj_str_get_qstr(args[0])); if (module_obj != MP_OBJ_NULL) { - return module_obj; + // If it's not a package, return module right away + char *p = strchr(mod_str, '.'); + if (p == NULL) { + return module_obj; + } + // Otherwise, we need to return top-level package + // TODO: subject to fromlist arg + qstr pkg_name = qstr_from_strn(mod_str, p - mod_str); + return mp_obj_module_get(pkg_name); } - uint mod_len; - const char *mod_str = (const char*)mp_obj_str_get_data(args[0], &mod_len); - uint last = 0; VSTR_FIXED(path, MICROPY_PATH_MAX) module_obj = MP_OBJ_NULL; + mp_obj_t top_module_obj = MP_OBJ_NULL; + mp_obj_t outer_module_obj = MP_OBJ_NULL; uint i; for (i = 1; i <= mod_len; i++) { if (i == mod_len || mod_str[i] == '.') { @@ -168,7 +178,6 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { vstr_add_strn(&path, mod_str + last, i - last); stat = stat_dir_or_file(&path); } - last = i + 1; // fail if we couldn't find the file if (stat == MP_IMPORT_STAT_NO_EXIST) { @@ -194,9 +203,21 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { vstr_cut_tail(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py } else { // MP_IMPORT_STAT_FILE do_load(module_obj, &path); - break; + // TODO: We cannot just break here, at the very least, we must execute + // trailer code below. But otherwise if there're remaining components, + // that would be (??) object path within module, not modules path within FS. + // break; } } + if (outer_module_obj != MP_OBJ_NULL) { + qstr s = qstr_from_strn(mod_str + last, i - last); + rt_store_attr(outer_module_obj, s, module_obj); + } + outer_module_obj = module_obj; + if (top_module_obj == MP_OBJ_NULL) { + top_module_obj = module_obj; + } + last = i + 1; } } @@ -206,7 +227,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { assert(0); } - return module_obj; + return top_module_obj; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj, 1, 5, mp_builtin___import__); diff --git a/tests/basics/import-pkg1.py b/tests/basics/import-pkg1.py new file mode 100644 index 000000000..8cd77af79 --- /dev/null +++ b/tests/basics/import-pkg1.py @@ -0,0 +1,11 @@ +import pkg.mod + +print(pkg.__name__) +print(pkg.mod.__name__) +print(pkg.mod.foo()) + +# Import 2nd time, must be same module objects +pkg_ = __import__("pkg.mod") +print(pkg_ is not pkg.mod) +print(pkg_ is pkg) +print(pkg_.mod is pkg.mod) diff --git a/tests/basics/pkg/__init__.py b/tests/basics/pkg/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/basics/pkg/mod.py b/tests/basics/pkg/mod.py new file mode 100644 index 000000000..9e67bdd29 --- /dev/null +++ b/tests/basics/pkg/mod.py @@ -0,0 +1,2 @@ +def foo(): + return 42