From e11b17c25ff23b5d6c5e74bc2a9bbd28bc8d2fde Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 5 Feb 2014 00:47:06 +0200 Subject: [PATCH] Implement support for sys.path when loading modules. sys.path is not initialized by rt_init(), that's left for platform-specific startup code. (For example, bare metal port may have some hardcoded defaults, and let user change sys.path directly; while port for OS with environment feature can take path from environment). If it's not explicitly initialized, modules will be imported only from a current directory. --- py/builtinimport.c | 41 ++++++++++++++++++++++++++++++++++++++--- py/lexerunix.c | 1 - py/misc.h | 11 +++++++++++ py/qstrdefs.h | 1 + py/runtime.c | 8 +++++++- py/runtime.h | 1 + 6 files changed, 58 insertions(+), 5 deletions(-) diff --git a/py/builtinimport.c b/py/builtinimport.c index a5deed3924..92d9ada897 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -19,6 +19,8 @@ #include "map.h" #include "builtin.h" +mp_obj_t sys_path; + mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { /* printf("import:\n"); @@ -37,10 +39,43 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) { } // find the file to import - mp_lexer_t *lex = mp_import_open_file(mod_name); + uint mod_name_len; + const byte* mod_name_p = qstr_data(mod_name, &mod_name_len); + mp_lexer_t *lex = NULL; + + uint path_num = 0; + mp_obj_t *path_items; + if (sys_path != MP_OBJ_NULL) { + mp_obj_list_get(sys_path, &path_num, &path_items); + } + + if (path_num == 0) { + CHECKBUF(fname, PATH_MAX); + CHECKBUF_APPEND(fname, mod_name_p, mod_name_len); + CHECKBUF_APPEND(fname, ".py", sizeof(".py") - 1); + CHECKBUF_APPEND_0(fname); + lex = mp_lexer_new_from_file(fname); + } else { + for (int i = 0; i < path_num; i++) { + CHECKBUF(fname, PATH_MAX); + uint p_len; + const byte *p = mp_obj_str_get_data(path_items[i], &p_len); + if (p_len > 0) { + CHECKBUF_APPEND(fname, p, p_len); + CHECKBUF_APPEND(fname, "/", 1); + } + CHECKBUF_APPEND(fname, mod_name_p, mod_name_len); + CHECKBUF_APPEND(fname, ".py", sizeof(".py") - 1); + CHECKBUF_APPEND_0(fname); + lex = mp_lexer_new_from_file(fname); + if (lex != NULL) { + break; + } + } + } + if (lex == NULL) { - // TODO handle lexer error correctly - return mp_const_none; + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ImportError, "ImportError: No module named '%s'", mod_name_p)); } qstr source_name = mp_lexer_source_name(lex); diff --git a/py/lexerunix.c b/py/lexerunix.c index 5d96c468f8..aa1cbc486d 100644 --- a/py/lexerunix.c +++ b/py/lexerunix.c @@ -14,7 +14,6 @@ mp_lexer_t *mp_lexer_new_from_file(const char *filename) { int fd = open(filename, O_RDONLY); if (fd < 0) { - printf("cannot open file %s\n", filename); return NULL; } uint size = lseek(fd, 0, SEEK_END); diff --git a/py/misc.h b/py/misc.h index f58a9f669c..0fad9459f1 100644 --- a/py/misc.h +++ b/py/misc.h @@ -90,6 +90,17 @@ void vstr_add_strn(vstr_t *vstr, const char *str, int len); void vstr_cut_tail(vstr_t *vstr, int len); void vstr_printf(vstr_t *vstr, const char *fmt, ...); +/** non-dynamic size-bounded variable buffer/string *************/ + +#define CHECKBUF(buf, max_size) char buf[max_size + 1]; uint buf##_len = max_size; char *buf##_p = buf; +#define CHECKBUF_APPEND(buf, src, src_len) \ + { int l = MIN(src_len, buf##_len); \ + memcpy(buf##_p, src, l); \ + buf##_len -= l; \ + buf##_p += l; } +#define CHECKBUF_APPEND_0(buf) { *buf##_p = 0; } +#define CHECKBUF_LEN(buf) (buf##_p - buf) + #ifdef va_start void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap); #endif diff --git a/py/qstrdefs.h b/py/qstrdefs.h index bf575e25d1..3eb306723d 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -73,6 +73,7 @@ Q(max) Q(min) Q(next) Q(ord) +Q(path) Q(pow) Q(print) Q(range) diff --git a/py/runtime.c b/py/runtime.c index c84a28e4cb..6d3cbf85ba 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -168,8 +168,14 @@ void rt_init(void) { #if MICROPY_CPYTHON_COMPAT // Precreate sys module, so "import sys" didn't throw exceptions. - mp_obj_new_module(MP_QSTR_sys); + mp_obj_t m_sys = mp_obj_new_module(MP_QSTR_sys); + // Avoid warning of unused var + (void)m_sys; #endif + // init sys.path + // for efficiency, left to platform-specific startup code + //sys_path = mp_obj_new_list(0, NULL); + //rt_store_attr(m_sys, MP_QSTR_path, sys_path); mp_module_micropython_init(); diff --git a/py/runtime.h b/py/runtime.h index aafe1a06a3..20595c6a58 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -46,3 +46,4 @@ void rt_locals_set(struct _mp_map_t *m); struct _mp_map_t *rt_globals_get(void); void rt_globals_set(struct _mp_map_t *m); struct _mp_map_t *rt_loaded_modules_get(void); +extern mp_obj_t sys_path;