Skip to content

Commit 9e29666

Browse files
committed
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.
1 parent 52386ca commit 9e29666

6 files changed

Lines changed: 69 additions & 28 deletions

File tree

py/modio.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,20 @@
3232

3333
#if MICROPY_ENABLE_MOD_IO
3434

35+
extern const mp_obj_type_t mp_type_fileio;
36+
extern const mp_obj_type_t mp_type_textio;
37+
3538
STATIC const mp_map_elem_t mp_module_io_globals_table[] = {
3639
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_io) },
3740
// Note: mp_builtin_open_obj should be defined by port, it's not
3841
// part of the core.
3942
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
43+
#if MICROPY_MOD_IO_FILEIO
44+
{ MP_OBJ_NEW_QSTR(MP_QSTR_FileIO), (mp_obj_t)&mp_type_fileio },
45+
#endif
46+
#if MICROPY_CPYTHON_COMPAT
47+
{ MP_OBJ_NEW_QSTR(MP_QSTR_TextIOWrapper), (mp_obj_t)&mp_type_textio },
48+
#endif
4049
{ MP_OBJ_NEW_QSTR(MP_QSTR_StringIO), (mp_obj_t)&mp_type_stringio },
4150
#if MICROPY_IO_BYTESIO
4251
{ MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_bytesio },

py/mpconfig.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ typedef double mp_float_t;
225225
#define MICROPY_ENABLE_MOD_IO (1)
226226
#endif
227227

228+
#ifndef MICROPY_MOD_IO_FILEIO
229+
#define MICROPY_MOD_IO_FILEIO (0)
230+
#endif
231+
228232
#ifndef MICROPY_IO_BYTESIO
229233
#define MICROPY_IO_BYTESIO (1)
230234
#endif

py/qstrdefs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ Q(io)
354354
Q(readall)
355355
Q(readline)
356356
Q(readlines)
357+
Q(FileIO)
358+
Q(TextIOWrapper)
357359
Q(StringIO)
358360
Q(BytesIO)
359361
Q(getvalue)

stmhal/file.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ typedef struct _pyb_file_obj_t {
4141
} pyb_file_obj_t;
4242

4343
void file_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
44-
printf("<io.FileIO %p>", self_in);
44+
printf("<io.%s %p>", mp_obj_get_type_str(self_in), self_in);
4545
}
4646

4747
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 = {
9494
.write = file_write,
9595
};
9696

97-
STATIC const mp_obj_type_t file_obj_type = {
97+
const mp_obj_type_t mp_type_textio = {
9898
{ &mp_type_type },
9999
.name = MP_QSTR_FileIO,
100100
.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
113113
mode = mp_obj_str_get_str(args[1]);
114114
}
115115
pyb_file_obj_t *self = m_new_obj_with_finaliser(pyb_file_obj_t);
116-
self->base.type = &file_obj_type;
116+
self->base.type = &mp_type_textio;
117117
if (mode[0] == 'r') {
118118
// open for reading
119119
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
138138
// Factory function for I/O stream classes
139139
STATIC mp_obj_t pyb_io_open(uint n_args, const mp_obj_t *args) {
140140
// TODO: analyze mode and buffering args and instantiate appropriate type
141-
return file_obj_make_new((mp_obj_t)&file_obj_type, n_args, 0, args);
141+
return file_obj_make_new((mp_obj_t)&mp_type_textio, n_args, 0, args);
142142
}
143143

144144
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, pyb_io_open);

unix/file.c

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@ void check_fd_is_open(const mp_obj_fdfile_t *o) {
5454
#define check_fd_is_open(o)
5555
#endif
5656

57-
STATIC const mp_obj_type_t rawfile_type;
57+
extern const mp_obj_type_t mp_type_fileio;
58+
extern const mp_obj_type_t mp_type_textio;
5859

5960
STATIC void fdfile_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
6061
mp_obj_fdfile_t *self = self_in;
61-
print(env, "<io.FileIO %d>", self->fd);
62+
print(env, "<io.%s %d>", mp_obj_get_type_str(self), self->fd);
6263
}
6364

6465
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) {
103104
}
104105
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_fileno_obj, fdfile_fileno);
105106

106-
STATIC mp_obj_fdfile_t *fdfile_new(int fd) {
107-
mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t);
108-
o->base.type = &rawfile_type;
109-
o->fd = fd;
110-
return o;
111-
}
112-
113107
STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
114108
mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t);
115-
o->base.type = type_in;
116-
117-
if (MP_OBJ_IS_SMALL_INT(args[0])) {
118-
o->fd = MP_OBJ_SMALL_INT_VALUE(args[0]);
119-
return o;
120-
}
109+
mp_const_obj_t type = type_in;
121110

122-
const char *fname = mp_obj_str_get_str(args[0]);
123111
const char *mode_s;
124112
if (n_args > 1) {
125113
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
143131
case '+':
144132
mode |= O_RDWR;
145133
break;
134+
#if MICROPY_MOD_IO_FILEIO
135+
// If we don't have io.FileIO, then files are in text mode implicitly
136+
case 'b':
137+
type = &mp_type_fileio;
138+
break;
139+
case 't':
140+
type = &mp_type_textio;
141+
break;
142+
#endif
146143
}
147144
}
148145

146+
o->base.type = type;
147+
148+
if (MP_OBJ_IS_SMALL_INT(args[0])) {
149+
o->fd = MP_OBJ_SMALL_INT_VALUE(args[0]);
150+
return o;
151+
}
152+
153+
const char *fname = mp_obj_str_get_str(args[0]);
149154
int fd = open(fname, mode, 0644);
150155
if (fd == -1) {
151156
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT((machine_int_t)errno)));
152157
}
153-
return fdfile_new(fd);
158+
o->fd = fd;
159+
return o;
154160
}
155161

156162
STATIC const mp_map_elem_t rawfile_locals_dict_table[] = {
@@ -167,29 +173,48 @@ STATIC const mp_map_elem_t rawfile_locals_dict_table[] = {
167173

168174
STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
169175

170-
STATIC const mp_stream_p_t rawfile_stream_p = {
176+
#if MICROPY_MOD_IO_FILEIO
177+
STATIC const mp_stream_p_t fileio_stream_p = {
171178
.read = fdfile_read,
172179
.write = fdfile_write,
180+
.is_bytes = true,
173181
};
174182

175-
STATIC const mp_obj_type_t rawfile_type = {
183+
const mp_obj_type_t mp_type_fileio = {
176184
{ &mp_type_type },
177185
.name = MP_QSTR_FileIO,
178186
.print = fdfile_print,
179187
.make_new = fdfile_make_new,
180188
.getiter = mp_identity,
181189
.iternext = mp_stream_unbuffered_iter,
182-
.stream_p = &rawfile_stream_p,
190+
.stream_p = &fileio_stream_p,
191+
.locals_dict = (mp_obj_t)&rawfile_locals_dict,
192+
};
193+
#endif
194+
195+
STATIC const mp_stream_p_t textio_stream_p = {
196+
.read = fdfile_read,
197+
.write = fdfile_write,
198+
};
199+
200+
const mp_obj_type_t mp_type_textio = {
201+
{ &mp_type_type },
202+
.name = MP_QSTR_TextIOWrapper,
203+
.print = fdfile_print,
204+
.make_new = fdfile_make_new,
205+
.getiter = mp_identity,
206+
.iternext = mp_stream_unbuffered_iter,
207+
.stream_p = &textio_stream_p,
183208
.locals_dict = (mp_obj_t)&rawfile_locals_dict,
184209
};
185210

186211
// Factory function for I/O stream classes
187212
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args) {
188213
// TODO: analyze mode and buffering args and instantiate appropriate type
189-
return fdfile_make_new((mp_obj_t)&rawfile_type, n_args, 0, args);
214+
return fdfile_make_new((mp_obj_t)&mp_type_textio, n_args, 0, args);
190215
}
191216
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open);
192217

193-
const mp_obj_fdfile_t mp_sys_stdin_obj = { .base = {&rawfile_type}, .fd = STDIN_FILENO };
194-
const mp_obj_fdfile_t mp_sys_stdout_obj = { .base = {&rawfile_type}, .fd = STDOUT_FILENO };
195-
const mp_obj_fdfile_t mp_sys_stderr_obj = { .base = {&rawfile_type}, .fd = STDERR_FILENO };
218+
const mp_obj_fdfile_t mp_sys_stdin_obj = { .base = {&mp_type_textio}, .fd = STDIN_FILENO };
219+
const mp_obj_fdfile_t mp_sys_stdout_obj = { .base = {&mp_type_textio}, .fd = STDOUT_FILENO };
220+
const mp_obj_fdfile_t mp_sys_stderr_obj = { .base = {&mp_type_textio}, .fd = STDERR_FILENO };

unix/mpconfigport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#define MICROPY_MOD_SYS_EXIT (1)
4646
#define MICROPY_MOD_SYS_STDFILES (1)
4747
#define MICROPY_ENABLE_MOD_CMATH (1)
48+
#define MICROPY_MOD_IO_FILEIO (1)
4849
// Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc.
4950
// names in exception messages (may require more RAM).
5051
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)

0 commit comments

Comments
 (0)