Commit 9e29666b authored by Paul Sokolovsky's avatar Paul Sokolovsky
Browse files

py: Implement proper separation between io.FileIO and io.TextIOWrapper.

io.FileIO is binary I/O, ans actually optional. Default file type is
io.TextIOWrapper, which provides str results. CPython3 explicitly describes
io.TextIOWrapper as buffered I/O, but we don't have buffering support yet
anyway.
parent 52386caf
......@@ -32,11 +32,20 @@
#if MICROPY_ENABLE_MOD_IO
extern const mp_obj_type_t mp_type_fileio;
extern const mp_obj_type_t mp_type_textio;
STATIC const mp_map_elem_t mp_module_io_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_io) },
// Note: mp_builtin_open_obj should be defined by port, it's not
// part of the core.
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
#if MICROPY_MOD_IO_FILEIO
{ MP_OBJ_NEW_QSTR(MP_QSTR_FileIO), (mp_obj_t)&mp_type_fileio },
#endif
#if MICROPY_CPYTHON_COMPAT
{ MP_OBJ_NEW_QSTR(MP_QSTR_TextIOWrapper), (mp_obj_t)&mp_type_textio },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_StringIO), (mp_obj_t)&mp_type_stringio },
#if MICROPY_IO_BYTESIO
{ MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_bytesio },
......
......@@ -225,6 +225,10 @@ typedef double mp_float_t;
#define MICROPY_ENABLE_MOD_IO (1)
#endif
#ifndef MICROPY_MOD_IO_FILEIO
#define MICROPY_MOD_IO_FILEIO (0)
#endif
#ifndef MICROPY_IO_BYTESIO
#define MICROPY_IO_BYTESIO (1)
#endif
......
......@@ -354,6 +354,8 @@ Q(io)
Q(readall)
Q(readline)
Q(readlines)
Q(FileIO)
Q(TextIOWrapper)
Q(StringIO)
Q(BytesIO)
Q(getvalue)
......
......@@ -41,7 +41,7 @@ typedef struct _pyb_file_obj_t {
} pyb_file_obj_t;
void file_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
printf("<io.FileIO %p>", self_in);
printf("<io.%s %p>", mp_obj_get_type_str(self_in), self_in);
}
STATIC machine_int_t file_read(mp_obj_t self_in, void *buf, machine_uint_t size, int *errcode) {
......@@ -94,7 +94,7 @@ STATIC const mp_stream_p_t file_obj_stream_p = {
.write = file_write,
};
STATIC const mp_obj_type_t file_obj_type = {
const mp_obj_type_t mp_type_textio = {
{ &mp_type_type },
.name = MP_QSTR_FileIO,
.make_new = file_obj_make_new,
......@@ -113,7 +113,7 @@ STATIC mp_obj_t file_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, cons
mode = mp_obj_str_get_str(args[1]);
}
pyb_file_obj_t *self = m_new_obj_with_finaliser(pyb_file_obj_t);
self->base.type = &file_obj_type;
self->base.type = &mp_type_textio;
if (mode[0] == 'r') {
// open for reading
FRESULT res = f_open(&self->fp, filename, FA_READ);
......@@ -138,7 +138,7 @@ STATIC mp_obj_t file_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, cons
// Factory function for I/O stream classes
STATIC mp_obj_t pyb_io_open(uint n_args, const mp_obj_t *args) {
// TODO: analyze mode and buffering args and instantiate appropriate type
return file_obj_make_new((mp_obj_t)&file_obj_type, n_args, 0, args);
return file_obj_make_new((mp_obj_t)&mp_type_textio, n_args, 0, args);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, pyb_io_open);
......@@ -54,11 +54,12 @@ void check_fd_is_open(const mp_obj_fdfile_t *o) {
#define check_fd_is_open(o)
#endif
STATIC const mp_obj_type_t rawfile_type;
extern const mp_obj_type_t mp_type_fileio;
extern const mp_obj_type_t mp_type_textio;
STATIC void fdfile_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_fdfile_t *self = self_in;
print(env, "<io.FileIO %d>", self->fd);
print(env, "<io.%s %d>", mp_obj_get_type_str(self), self->fd);
}
STATIC machine_int_t fdfile_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) {
......@@ -103,23 +104,10 @@ STATIC mp_obj_t fdfile_fileno(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_fileno_obj, fdfile_fileno);
STATIC mp_obj_fdfile_t *fdfile_new(int fd) {
mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t);
o->base.type = &rawfile_type;
o->fd = fd;
return o;
}
STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t);
o->base.type = type_in;
if (MP_OBJ_IS_SMALL_INT(args[0])) {
o->fd = MP_OBJ_SMALL_INT_VALUE(args[0]);
return o;
}
mp_const_obj_t type = type_in;
const char *fname = mp_obj_str_get_str(args[0]);
const char *mode_s;
if (n_args > 1) {
mode_s = mp_obj_str_get_str(args[1]);
......@@ -143,14 +131,32 @@ STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
case '+':
mode |= O_RDWR;
break;
#if MICROPY_MOD_IO_FILEIO
// If we don't have io.FileIO, then files are in text mode implicitly
case 'b':
type = &mp_type_fileio;
break;
case 't':
type = &mp_type_textio;
break;
#endif
}
}
o->base.type = type;
if (MP_OBJ_IS_SMALL_INT(args[0])) {
o->fd = MP_OBJ_SMALL_INT_VALUE(args[0]);
return o;
}
const char *fname = mp_obj_str_get_str(args[0]);
int fd = open(fname, mode, 0644);
if (fd == -1) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT((machine_int_t)errno)));
}
return fdfile_new(fd);
o->fd = fd;
return o;
}
STATIC const mp_map_elem_t rawfile_locals_dict_table[] = {
......@@ -167,29 +173,48 @@ STATIC const mp_map_elem_t rawfile_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
STATIC const mp_stream_p_t rawfile_stream_p = {
#if MICROPY_MOD_IO_FILEIO
STATIC const mp_stream_p_t fileio_stream_p = {
.read = fdfile_read,
.write = fdfile_write,
.is_bytes = true,
};
STATIC const mp_obj_type_t rawfile_type = {
const mp_obj_type_t mp_type_fileio = {
{ &mp_type_type },
.name = MP_QSTR_FileIO,
.print = fdfile_print,
.make_new = fdfile_make_new,
.getiter = mp_identity,
.iternext = mp_stream_unbuffered_iter,
.stream_p = &rawfile_stream_p,
.stream_p = &fileio_stream_p,
.locals_dict = (mp_obj_t)&rawfile_locals_dict,
};
#endif
STATIC const mp_stream_p_t textio_stream_p = {
.read = fdfile_read,
.write = fdfile_write,
};
const mp_obj_type_t mp_type_textio = {
{ &mp_type_type },
.name = MP_QSTR_TextIOWrapper,
.print = fdfile_print,
.make_new = fdfile_make_new,
.getiter = mp_identity,
.iternext = mp_stream_unbuffered_iter,
.stream_p = &textio_stream_p,
.locals_dict = (mp_obj_t)&rawfile_locals_dict,
};
// Factory function for I/O stream classes
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args) {
// TODO: analyze mode and buffering args and instantiate appropriate type
return fdfile_make_new((mp_obj_t)&rawfile_type, n_args, 0, args);
return fdfile_make_new((mp_obj_t)&mp_type_textio, n_args, 0, args);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open);
const mp_obj_fdfile_t mp_sys_stdin_obj = { .base = {&rawfile_type}, .fd = STDIN_FILENO };
const mp_obj_fdfile_t mp_sys_stdout_obj = { .base = {&rawfile_type}, .fd = STDOUT_FILENO };
const mp_obj_fdfile_t mp_sys_stderr_obj = { .base = {&rawfile_type}, .fd = STDERR_FILENO };
const mp_obj_fdfile_t mp_sys_stdin_obj = { .base = {&mp_type_textio}, .fd = STDIN_FILENO };
const mp_obj_fdfile_t mp_sys_stdout_obj = { .base = {&mp_type_textio}, .fd = STDOUT_FILENO };
const mp_obj_fdfile_t mp_sys_stderr_obj = { .base = {&mp_type_textio}, .fd = STDERR_FILENO };
......@@ -45,6 +45,7 @@
#define MICROPY_MOD_SYS_EXIT (1)
#define MICROPY_MOD_SYS_STDFILES (1)
#define MICROPY_ENABLE_MOD_CMATH (1)
#define MICROPY_MOD_IO_FILEIO (1)
// Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc.
// names in exception messages (may require more RAM).
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
......
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