Commit d7da2dba authored by Paul Sokolovsky's avatar Paul Sokolovsky
Browse files

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.
parent 4c2fa83f
......@@ -43,16 +43,16 @@ extern const char mp_frozen_str_names[];
extern const uint32_t mp_frozen_str_sizes[];
extern const char mp_frozen_str_content[];
STATIC mp_lexer_t *mp_find_frozen_str(const char *str, size_t len) {
// On input, *len contains size of name, on output - size of content
const char *mp_find_frozen_str(const char *str, size_t *len) {
const char *name = mp_frozen_str_names;
size_t offset = 0;
for (int i = 0; *name != 0; i++) {
size_t l = strlen(name);
if (l == len && !memcmp(str, name, l)) {
qstr source = qstr_from_strn(name, l);
mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, mp_frozen_str_content + offset, mp_frozen_str_sizes[i], 0);
return lex;
if (l == *len && !memcmp(str, name, l)) {
*len = mp_frozen_str_sizes[i];
return mp_frozen_str_content + offset;
}
name += l + 1;
offset += mp_frozen_str_sizes[i] + 1;
......@@ -60,6 +60,19 @@ STATIC mp_lexer_t *mp_find_frozen_str(const char *str, size_t len) {
return NULL;
}
STATIC mp_lexer_t *mp_lexer_frozen_str(const char *str, size_t len) {
size_t name_len = len;
const char *content = mp_find_frozen_str(str, &len);
if (content == NULL) {
return NULL;
}
qstr source = qstr_from_strn(str, name_len);
mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, len, 0);
return lex;
}
#endif
#if MICROPY_MODULE_FROZEN_MPY
......@@ -124,7 +137,7 @@ mp_import_stat_t mp_frozen_stat(const char *str) {
int mp_find_frozen_module(const char *str, size_t len, void **data) {
#if MICROPY_MODULE_FROZEN_STR
mp_lexer_t *lex = mp_find_frozen_str(str, len);
mp_lexer_t *lex = mp_lexer_frozen_str(str, len);
if (lex != NULL) {
*data = lex;
return MP_FROZEN_STR;
......
......@@ -24,6 +24,8 @@
* THE SOFTWARE.
*/
#include "py/lexer.h"
enum {
MP_FROZEN_NONE,
MP_FROZEN_STR,
......@@ -31,4 +33,5 @@ enum {
};
int mp_find_frozen_module(const char *str, size_t len, void **data);
const char *mp_find_frozen_str(const char *str, size_t *len);
mp_import_stat_t mp_frozen_stat(const char *str);
......@@ -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
......
......@@ -886,6 +886,13 @@ typedef double mp_float_t;
#define MICROPY_PY_IO (1)
#endif
// Whether to provide "uio.resource_stream()" function with
// the semantics of CPython's pkg_resources.resource_stream()
// (allows to access resources in frozen packages).
#ifndef MICROPY_PY_IO_RESOURCE_STREAM
#define MICROPY_PY_IO_RESOURCE_STREAM (0)
#endif
// Whether to provide "io.FileIO" class
#ifndef MICROPY_PY_IO_FILEIO
#define MICROPY_PY_IO_FILEIO (0)
......
......@@ -101,6 +101,7 @@
#endif
#define MICROPY_PY_CMATH (1)
#define MICROPY_PY_IO_FILEIO (1)
#define MICROPY_PY_IO_RESOURCE_STREAM (1)
#define MICROPY_PY_GC_COLLECT_RETVAL (1)
#define MICROPY_MODULE_FROZEN_STR (1)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment