Skip to content

Commit 2fe4cf7

Browse files
stinospfalcon
authored andcommitted
Implement kwargs for builtin open() and _io.FileIO
This makes open() and _io.FileIO() more CPython compliant. The mode kwarg is fully iplemented. The encoding kwarg is allowed but not implemented; mainly to allow the tests to specify encoding for CPython, see adafruit#874
1 parent 072bd07 commit 2fe4cf7

8 files changed

Lines changed: 90 additions & 63 deletions

File tree

bare-arm/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ mp_import_stat_t mp_import_stat(const char *path) {
7070
return MP_IMPORT_STAT_NO_EXIST;
7171
}
7272

73-
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args) {
73+
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
7474
return mp_const_none;
7575
}
76-
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open);
76+
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
7777

7878
void nlr_jump_fail(void *val) {
7979
}

py/builtin.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
*/
2626

2727
mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args);
28-
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args);
28+
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
2929

3030
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
3131
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj);

py/qstrdefs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,9 @@ Q(StringIO)
446446
Q(BytesIO)
447447
Q(getvalue)
448448
Q(file)
449+
Q(mode)
450+
Q(r)
451+
Q(encoding)
449452
#endif
450453

451454
#if MICROPY_PY_GC

qemu-arm/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ mp_import_stat_t mp_import_stat(const char *path) {
7070
return MP_IMPORT_STAT_NO_EXIST;
7171
}
7272

73-
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args) {
73+
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
7474
return mp_const_none;
7575
}
76-
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open);
76+
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
7777

7878
void nlr_jump_fail(void *val) {
7979
}

qemu-arm/test_main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ mp_import_stat_t mp_import_stat(const char *path) {
7878
return MP_IMPORT_STAT_NO_EXIST;
7979
}
8080

81-
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args) {
81+
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
8282
return mp_const_none;
8383
}
84-
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open);
84+
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
8585

8686
void nlr_jump_fail(void *val) {
8787
}

stmhal/file.c

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -160,49 +160,51 @@ mp_obj_t file_obj_tell(mp_obj_t self_in) {
160160
}
161161
STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_tell_obj, file_obj_tell);
162162

163-
STATIC mp_obj_t file_obj_make_new(mp_obj_t type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
164-
mp_arg_check_num(n_args, n_kw, 1, 2, false);
165-
166-
const char *fname = mp_obj_str_get_str(args[0]);
163+
// Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO,
164+
// but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor
165+
STATIC const mp_arg_t file_open_args[] = {
166+
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = mp_const_none} },
167+
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} },
168+
{ MP_QSTR_encoding, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
169+
};
170+
#define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args)
167171

172+
STATIC mp_obj_t file_open(mp_obj_t type, mp_arg_val_t *args) {
168173
int mode = 0;
169-
if (n_args == 1) {
170-
mode = FA_READ;
171-
} else {
172-
const char *mode_s = mp_obj_str_get_str(args[1]);
173-
// TODO make sure only one of r, w, x, a, and b, t are specified
174-
while (*mode_s) {
175-
switch (*mode_s++) {
176-
case 'r':
177-
mode |= FA_READ;
178-
break;
179-
case 'w':
180-
mode |= FA_WRITE | FA_CREATE_ALWAYS;
181-
break;
182-
case 'x':
183-
mode |= FA_WRITE | FA_CREATE_NEW;
184-
break;
185-
case 'a':
186-
mode |= FA_WRITE | FA_OPEN_ALWAYS;
187-
break;
188-
case '+':
189-
mode |= FA_READ | FA_WRITE;
190-
break;
191-
#if MICROPY_PY_IO_FILEIO
192-
case 'b':
193-
type = (mp_obj_t)&mp_type_fileio;
194-
break;
195-
#endif
196-
case 't':
197-
type = (mp_obj_t)&mp_type_textio;
198-
break;
199-
}
174+
const char *mode_s = mp_obj_str_get_str(args[1].u_obj);
175+
// TODO make sure only one of r, w, x, a, and b, t are specified
176+
while (*mode_s) {
177+
switch (*mode_s++) {
178+
case 'r':
179+
mode |= FA_READ;
180+
break;
181+
case 'w':
182+
mode |= FA_WRITE | FA_CREATE_ALWAYS;
183+
break;
184+
case 'x':
185+
mode |= FA_WRITE | FA_CREATE_NEW;
186+
break;
187+
case 'a':
188+
mode |= FA_WRITE | FA_OPEN_ALWAYS;
189+
break;
190+
case '+':
191+
mode |= FA_READ | FA_WRITE;
192+
break;
193+
#if MICROPY_PY_IO_FILEIO
194+
case 'b':
195+
type = (mp_obj_t)&mp_type_fileio;
196+
break;
197+
#endif
198+
case 't':
199+
type = (mp_obj_t)&mp_type_textio;
200+
break;
200201
}
201202
}
202203

203204
pyb_file_obj_t *o = m_new_obj_with_finaliser(pyb_file_obj_t);
204205
o->base.type = type;
205206

207+
const char *fname = mp_obj_str_get_str(args[0].u_obj);
206208
FRESULT res = f_open(&o->fp, fname, mode);
207209
if (res != FR_OK) {
208210
m_del_obj(pyb_file_obj_t, o);
@@ -217,6 +219,12 @@ STATIC mp_obj_t file_obj_make_new(mp_obj_t type, mp_uint_t n_args, mp_uint_t n_k
217219
return o;
218220
}
219221

222+
STATIC mp_obj_t file_obj_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
223+
mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS];
224+
mp_arg_parse_all_kw_array(n_args, n_kw, args, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals);
225+
return file_open(type_in, arg_vals);
226+
}
227+
220228
// TODO gc hook to close the file if not already closed
221229

222230
STATIC const mp_map_elem_t rawfile_locals_dict_table[] = {
@@ -273,9 +281,10 @@ const mp_obj_type_t mp_type_textio = {
273281
};
274282

275283
// Factory function for I/O stream classes
276-
STATIC mp_obj_t pyb_io_open(mp_uint_t n_args, const mp_obj_t *args) {
277-
// TODO: analyze mode and buffering args and instantiate appropriate type
278-
return file_obj_make_new((mp_obj_t)&mp_type_textio, n_args, 0, args);
284+
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
285+
// TODO: analyze buffering args and instantiate appropriate type
286+
mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS];
287+
mp_arg_parse_all(n_args, args, kwargs, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals);
288+
return file_open((mp_obj_t)&mp_type_textio, arg_vals);
279289
}
280-
281-
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, pyb_io_open);
290+
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);

unix/file.c

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -118,16 +118,19 @@ STATIC mp_obj_t fdfile_fileno(mp_obj_t self_in) {
118118
}
119119
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_fileno_obj, fdfile_fileno);
120120

121-
STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
121+
// Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO,
122+
// but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor
123+
STATIC const mp_arg_t file_open_args[] = {
124+
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = mp_const_none} },
125+
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} },
126+
{ MP_QSTR_encoding, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
127+
};
128+
#define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args)
129+
130+
STATIC mp_obj_t fdfile_open(mp_obj_t type_in, mp_arg_val_t *args) {
122131
mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t);
123132
mp_const_obj_t type = type_in;
124-
125-
const char *mode_s;
126-
if (n_args > 1) {
127-
mode_s = mp_obj_str_get_str(args[1]);
128-
} else {
129-
mode_s = "r";
130-
}
133+
const char *mode_s = mp_obj_str_get_str(args[1].u_obj);
131134

132135
int mode = 0;
133136
while (*mode_s) {
@@ -159,12 +162,14 @@ STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_
159162

160163
o->base.type = type;
161164

162-
if (MP_OBJ_IS_SMALL_INT(args[0])) {
163-
o->fd = MP_OBJ_SMALL_INT_VALUE(args[0]);
165+
mp_obj_t fid = args[0].u_obj;
166+
167+
if (MP_OBJ_IS_SMALL_INT(fid)) {
168+
o->fd = MP_OBJ_SMALL_INT_VALUE(fid);
164169
return o;
165170
}
166171

167-
const char *fname = mp_obj_str_get_str(args[0]);
172+
const char *fname = mp_obj_str_get_str(fid);
168173
int fd = open(fname, mode, 0644);
169174
if (fd == -1) {
170175
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno)));
@@ -173,6 +178,12 @@ STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_
173178
return o;
174179
}
175180

181+
STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
182+
mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS];
183+
mp_arg_parse_all_kw_array(n_args, n_kw, args, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals);
184+
return fdfile_open(type_in, arg_vals);
185+
}
186+
176187
STATIC const mp_map_elem_t rawfile_locals_dict_table[] = {
177188
{ MP_OBJ_NEW_QSTR(MP_QSTR_fileno), (mp_obj_t)&fdfile_fileno_obj },
178189
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
@@ -225,11 +236,13 @@ const mp_obj_type_t mp_type_textio = {
225236
};
226237

227238
// Factory function for I/O stream classes
228-
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args) {
229-
// TODO: analyze mode and buffering args and instantiate appropriate type
230-
return fdfile_make_new((mp_obj_t)&mp_type_textio, n_args, 0, args);
239+
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
240+
// TODO: analyze buffering args and instantiate appropriate type
241+
mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS];
242+
mp_arg_parse_all(n_args, args, kwargs, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals);
243+
return fdfile_open((mp_obj_t)&mp_type_textio, arg_vals);
231244
}
232-
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open);
245+
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
233246

234247
const mp_obj_fdfile_t mp_sys_stdin_obj = { .base = {&mp_type_textio}, .fd = STDIN_FILENO };
235248
const mp_obj_fdfile_t mp_sys_stdout_obj = { .base = {&mp_type_textio}, .fd = STDOUT_FILENO };

unix/modsocket.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,9 @@ STATIC mp_obj_t socket_makefile(mp_uint_t n_args, const mp_obj_t *args) {
257257
mp_obj_t *new_args = alloca(n_args * sizeof(mp_obj_t));
258258
memcpy(new_args + 1, args + 1, (n_args - 1) * sizeof(mp_obj_t));
259259
new_args[0] = MP_OBJ_NEW_SMALL_INT(self->fd);
260-
return mp_builtin_open(n_args, new_args);
260+
mp_map_t kwargs;
261+
mp_map_init(&kwargs, 0);
262+
return mp_builtin_open(n_args, new_args, &kwargs);
261263
}
262264
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile);
263265

0 commit comments

Comments
 (0)