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 @@ ...@@ -32,11 +32,20 @@
#if MICROPY_ENABLE_MOD_IO #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[] = { 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) }, { 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 // Note: mp_builtin_open_obj should be defined by port, it's not
// part of the core. // part of the core.
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, { 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 }, { MP_OBJ_NEW_QSTR(MP_QSTR_StringIO), (mp_obj_t)&mp_type_stringio },
#if MICROPY_IO_BYTESIO #if MICROPY_IO_BYTESIO
{ MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_bytesio }, { MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_bytesio },
......
...@@ -225,6 +225,10 @@ typedef double mp_float_t; ...@@ -225,6 +225,10 @@ typedef double mp_float_t;
#define MICROPY_ENABLE_MOD_IO (1) #define MICROPY_ENABLE_MOD_IO (1)
#endif #endif
#ifndef MICROPY_MOD_IO_FILEIO
#define MICROPY_MOD_IO_FILEIO (0)
#endif
#ifndef MICROPY_IO_BYTESIO #ifndef MICROPY_IO_BYTESIO
#define MICROPY_IO_BYTESIO (1) #define MICROPY_IO_BYTESIO (1)
#endif #endif
......
...@@ -354,6 +354,8 @@ Q(io) ...@@ -354,6 +354,8 @@ Q(io)
Q(readall) Q(readall)
Q(readline) Q(readline)
Q(readlines) Q(readlines)
Q(FileIO)
Q(TextIOWrapper)
Q(StringIO) Q(StringIO)
Q(BytesIO) Q(BytesIO)
Q(getvalue) Q(getvalue)
......
...@@ -41,7 +41,7 @@ typedef struct _pyb_file_obj_t { ...@@ -41,7 +41,7 @@ typedef struct _pyb_file_obj_t {
} 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) { 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) { 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 = { ...@@ -94,7 +94,7 @@ STATIC const mp_stream_p_t file_obj_stream_p = {
.write = file_write, .write = file_write,
}; };
STATIC const mp_obj_type_t file_obj_type = { const mp_obj_type_t mp_type_textio = {
{ &mp_type_type }, { &mp_type_type },
.name = MP_QSTR_FileIO, .name = MP_QSTR_FileIO,
.make_new = file_obj_make_new, .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 ...@@ -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]); mode = mp_obj_str_get_str(args[1]);
} }
pyb_file_obj_t *self = m_new_obj_with_finaliser(pyb_file_obj_t); 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') { if (mode[0] == 'r') {
// open for reading // open for reading
FRESULT res = f_open(&self->fp, filename, FA_READ); 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 ...@@ -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 // Factory function for I/O stream classes
STATIC mp_obj_t pyb_io_open(uint n_args, const mp_obj_t *args) { 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 // 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); 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) { ...@@ -54,11 +54,12 @@ void check_fd_is_open(const mp_obj_fdfile_t *o) {
#define check_fd_is_open(o) #define check_fd_is_open(o)
#endif #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) { 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; 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) { 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) { ...@@ -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_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) { 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); mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t);
o->base.type = type_in; mp_const_obj_t type = type_in;
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]);
const char *mode_s; const char *mode_s;
if (n_args > 1) { if (n_args > 1) {
mode_s = mp_obj_str_get_str(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 ...@@ -143,14 +131,32 @@ STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
case '+': case '+':
mode |= O_RDWR; mode |= O_RDWR;
break; 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); int fd = open(fname, mode, 0644);
if (fd == -1) { if (fd == -1) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT((machine_int_t)errno))); 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[] = { STATIC const mp_map_elem_t rawfile_locals_dict_table[] = {
...@@ -167,29 +173,48 @@ 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 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, .read = fdfile_read,
.write = fdfile_write, .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 }, { &mp_type_type },
.name = MP_QSTR_FileIO, .name = MP_QSTR_FileIO,
.print = fdfile_print, .print = fdfile_print,
.make_new = fdfile_make_new, .make_new = fdfile_make_new,
.getiter = mp_identity, .getiter = mp_identity,
.iternext = mp_stream_unbuffered_iter, .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, .locals_dict = (mp_obj_t)&rawfile_locals_dict,
}; };
// Factory function for I/O stream classes // Factory function for I/O stream classes
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args) { mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args) {
// TODO: analyze mode and buffering args and instantiate appropriate type // 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); 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_stdin_obj = { .base = {&mp_type_textio}, .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_stdout_obj = { .base = {&mp_type_textio}, .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_stderr_obj = { .base = {&mp_type_textio}, .fd = STDERR_FILENO };
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#define MICROPY_MOD_SYS_EXIT (1) #define MICROPY_MOD_SYS_EXIT (1)
#define MICROPY_MOD_SYS_STDFILES (1) #define MICROPY_MOD_SYS_STDFILES (1)
#define MICROPY_ENABLE_MOD_CMATH (1) #define MICROPY_ENABLE_MOD_CMATH (1)
#define MICROPY_MOD_IO_FILEIO (1)
// Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc. // Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc.
// names in exception messages (may require more RAM). // names in exception messages (may require more RAM).
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) #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