diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index cce7a79af7..488593230c 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -274,12 +274,58 @@ STATIC const mp_stream_p_t vfs_posix_textio_stream_p = { .is_text = true, }; +#if MICROPY_PY_SYS_STDIO_BUFFER + +const mp_obj_vfs_posix_file_t mp_sys_stdin_buffer_obj = {{&mp_type_vfs_posix_fileio}, STDIN_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stdout_buffer_obj = {{&mp_type_vfs_posix_fileio}, STDOUT_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stderr_buffer_obj = {{&mp_type_vfs_posix_fileio}, STDERR_FILENO}; + +// Forward declarations. +const mp_obj_vfs_posix_file_t mp_sys_stdin_obj; +const mp_obj_vfs_posix_file_t mp_sys_stdout_obj; +const mp_obj_vfs_posix_file_t mp_sys_stderr_obj; + +STATIC void vfs_posix_textio_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // These objects are read-only. + return; + } + + if (attr == MP_QSTR_buffer) { + // Implement the `buffer` attribute only on std{in,out,err} instances. + if (MP_OBJ_TO_PTR(self_in) == &mp_sys_stdin_obj) { + dest[0] = MP_OBJ_FROM_PTR(&mp_sys_stdin_buffer_obj); + return; + } + if (MP_OBJ_TO_PTR(self_in) == &mp_sys_stdout_obj) { + dest[0] = MP_OBJ_FROM_PTR(&mp_sys_stdout_buffer_obj); + return; + } + if (MP_OBJ_TO_PTR(self_in) == &mp_sys_stderr_obj) { + dest[0] = MP_OBJ_FROM_PTR(&mp_sys_stderr_buffer_obj); + return; + } + } + + // Any other attribute - forward to locals dict. + dest[1] = MP_OBJ_SENTINEL; +}; + +#define VFS_POSIX_TEXTIO_TYPE_ATTR attr, vfs_posix_textio_attr, + +#else + +#define VFS_POSIX_TEXTIO_TYPE_ATTR + +#endif // MICROPY_PY_SYS_STDIO_BUFFER + MP_DEFINE_CONST_OBJ_TYPE( mp_type_vfs_posix_textio, MP_QSTR_TextIOWrapper, MP_TYPE_FLAG_ITER_IS_STREAM, print, vfs_posix_file_print, protocol, &vfs_posix_textio_stream_p, + VFS_POSIX_TEXTIO_TYPE_ATTR locals_dict, &vfs_posix_rawfile_locals_dict ); diff --git a/tests/io/file_stdio.py b/tests/io/file_stdio.py index cbdb070163..d714bffd4d 100644 --- a/tests/io/file_stdio.py +++ b/tests/io/file_stdio.py @@ -2,3 +2,4 @@ import sys print(sys.stdin.fileno()) print(sys.stdout.fileno()) +print(sys.stderr.fileno()) diff --git a/tests/io/file_stdio2.py b/tests/io/file_stdio2.py new file mode 100644 index 0000000000..5b8a5a7692 --- /dev/null +++ b/tests/io/file_stdio2.py @@ -0,0 +1,65 @@ +# Test sys.std*.buffer objects. + +import sys + +try: + sys.stdout.buffer + sys.stdin.buffer + sys.stderr.buffer +except AttributeError: + print("SKIP") + raise SystemExit + + +# force cpython to flush after every print +# this is to sequence stdout and stderr +def print_flush(*args, **kwargs): + try: + print(*args, **kwargs, flush=True) + except TypeError: + print(*args, **kwargs) + + +print_flush("==stdin==") +print_flush(sys.stdin.buffer.fileno()) + + +print_flush("==stdout==") +print_flush(sys.stdout.buffer.fileno()) +n_text = sys.stdout.write("The quick brown fox jumps over the lazy dog\n") +sys.stdout.flush() +n_binary = sys.stdout.buffer.write("The quick brown fox jumps over the lazy dog\n".encode("utf-8")) +sys.stdout.buffer.flush() +print_flush("n_text:{} n_binary:{}".format(n_text, n_binary)) + +# temporarily disabling unicode tests until future PR which fixes unicode write character count +# n_text = sys.stdout.write("🚀") +# sys.stdout.flush() +# n_binary = sys.stdout.buffer.write("🚀".encode("utf-8")) +# sys.stdout.buffer.flush() +# print_flush("") +# print_flush("n_text:{} n_binary:{}".format(n_text, n_binary)) +# n_text = sys.stdout.write("1🚀2a3α4b5β6c7γ8d9δ0ぁ1🙐") +# sys.stdout.flush() +# n_binary = sys.stdout.buffer.write("1🚀2a3α4b5β6c7γ8d9δ0ぁ1🙐".encode("utf-8")) +# sys.stdout.buffer.flush() +# print_flush("") +# print_flush("n_text:{} n_binary:{}".format(n_text, n_binary)) + + +print_flush("==stderr==") +print_flush(sys.stderr.buffer.fileno()) +n_text = sys.stderr.write("The quick brown fox jumps over the lazy dog\n") +sys.stderr.flush() +n_binary = sys.stderr.buffer.write("The quick brown fox jumps over the lazy dog\n".encode("utf-8")) +sys.stderr.buffer.flush() +print_flush("n_text:{} n_binary:{}".format(n_text, n_binary)) + +# temporarily disabling unicode tests until future PR which fixes unicode write character count +# n_text = sys.stderr.write("🚀") +# sys.stderr.flush() +# n_binary = sys.stderr.buffer.write("🚀".encode("utf-8")) +# sys.stderr.buffer.flush() +# print_flush("") +# print_flush("n_text:{} n_binary:{}".format(n_text, n_binary)) +# print_flush("")