From d7da2dba07778fa3c0c7873b7c253bde48066e9c Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 3 May 2017 01:47:08 +0300 Subject: py/modio: Implement uio.resource_stream(package, resource_path). The with semantics of this function is close to pkg_resources.resource_stream() function from setuptools, which is the canonical way to access non-source files belonging to a package (resources), regardless of what medium the package uses (e.g. individual source files vs zip archive). In the case of MicroPython, this function allows to access resources which are frozen into the executable, besides accessing resources in the file system. This is initial stage of the implementation, which actually doesn't implement "package" part of the semantics, just accesses frozen resources from "root", or filesystem resource - from current dir. --- py/modio.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'py/modio.c') diff --git a/py/modio.c b/py/modio.c index d5da0b1db..6bf5129e6 100644 --- a/py/modio.c +++ b/py/modio.c @@ -30,6 +30,8 @@ #include "py/runtime.h" #include "py/builtin.h" #include "py/stream.h" +#include "py/objstringio.h" +#include "py/frozenmod.h" #if MICROPY_PY_IO @@ -129,11 +131,38 @@ STATIC const mp_obj_type_t bufwriter_type = { }; #endif // MICROPY_PY_IO_BUFFEREDWRITER +#if MICROPY_MODULE_FROZEN_STR +STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { + if (package_in != mp_const_none) { + mp_not_implemented(""); + } + + size_t len; + const char *path = mp_obj_str_get_data(path_in, &len); + const char *data = mp_find_frozen_str(path, &len); + if (data != NULL) { + mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t); + o->base.type = &mp_type_bytesio; + o->vstr = m_new_obj(vstr_t); + vstr_init_fixed_buf(o->vstr, len + 1, (char*)data); + o->vstr->len = len; + o->pos = 0; + return MP_OBJ_FROM_PTR(o); + } + + return mp_builtin_open(1, &path_in, (mp_map_t*)&mp_const_empty_map); +} +MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream); +#endif + STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uio) }, // Note: mp_builtin_open_obj should be defined by port, it's not // part of the core. { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + #if MICROPY_PY_IO_RESOURCE_STREAM + { MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) }, + #endif #if MICROPY_PY_IO_FILEIO { MP_ROM_QSTR(MP_QSTR_FileIO), MP_ROM_PTR(&mp_type_fileio) }, #if MICROPY_CPYTHON_COMPAT -- cgit v1.2.3 From 4a4490ffcc906fe88e157dc926be54030c6fbf72 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 6 May 2017 18:42:35 +0300 Subject: py/modio: resource_stream: Implement "package" param handling. --- py/modio.c | 35 +++++++++++++++++++++++++++++++---- tests/io/resource_stream.py | 6 ++---- tests/io/resource_stream.py.exp | 1 + 3 files changed, 34 insertions(+), 8 deletions(-) (limited to 'py/modio.c') diff --git a/py/modio.c b/py/modio.c index 6bf5129e6..2d317d022 100644 --- a/py/modio.c +++ b/py/modio.c @@ -133,13 +133,39 @@ STATIC const mp_obj_type_t bufwriter_type = { #if MICROPY_MODULE_FROZEN_STR STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { + VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX); + size_t len; + + // As an extension to pkg_resources.resource_stream(), we support + // package parameter being None, the path_in is interpreted as a + // raw path. if (package_in != mp_const_none) { - mp_not_implemented(""); + mp_obj_t args[5]; + args[0] = package_in; + args[1] = mp_const_none; // TODO should be globals + args[2] = mp_const_none; // TODO should be locals + args[3] = mp_const_true; // Pass sentinel "non empty" value to force returning of leaf module + args[4] = MP_OBJ_NEW_SMALL_INT(0); + + // TODO lookup __import__ and call that instead of going straight to builtin implementation + mp_obj_t pkg = mp_builtin___import__(5, args); + + mp_obj_t dest[2]; + mp_load_method_maybe(pkg, MP_QSTR___path__, dest); + if (dest[0] == MP_OBJ_NULL) { + mp_raise_TypeError(NULL); + } + + const char *path = mp_obj_str_get_data(dest[0], &len); + vstr_add_strn(&path_buf, path, len); + vstr_add_byte(&path_buf, '/'); } - size_t len; const char *path = mp_obj_str_get_data(path_in, &len); - const char *data = mp_find_frozen_str(path, &len); + vstr_add_strn(&path_buf, path, len); + + len = path_buf.len; + const char *data = mp_find_frozen_str(path_buf.buf, &len); if (data != NULL) { mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t); o->base.type = &mp_type_bytesio; @@ -150,7 +176,8 @@ STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { return MP_OBJ_FROM_PTR(o); } - return mp_builtin_open(1, &path_in, (mp_map_t*)&mp_const_empty_map); + mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len, false); + return mp_builtin_open(1, &path_out, (mp_map_t*)&mp_const_empty_map); } MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream); #endif diff --git a/tests/io/resource_stream.py b/tests/io/resource_stream.py index 940ffaf2f..86975f118 100644 --- a/tests/io/resource_stream.py +++ b/tests/io/resource_stream.py @@ -7,10 +7,8 @@ except AttributeError: print('SKIP') sys.exit() -try: - buf = uio.resource_stream("data", "file2") -except NotImplementedError: - pass +buf = uio.resource_stream("data", "file2") +print(buf.read()) # resource_stream(None, ...) look ups from current dir, hence sys.path[0] hack buf = uio.resource_stream(None, sys.path[0] + "/data/file2") diff --git a/tests/io/resource_stream.py.exp b/tests/io/resource_stream.py.exp index 81c545efe..75404a347 100644 --- a/tests/io/resource_stream.py.exp +++ b/tests/io/resource_stream.py.exp @@ -1 +1,2 @@ 1234 +1234 -- cgit v1.2.3