Update io module with a bunch of methods

This commit is contained in:
coolreader18 committed 2019-12-01 02:01:15 -06:00
1 parent 300ac26852
commit e63073bfb8
2 files changed
+461 -144

No files matched your search

Vendored
+95
View File
@@ -1 +1,96 @@
"""The io module provides the Python interfaces to stream handling. The
builtin open function is defined in this module.
At the top of the I/O hierarchy is the abstract base class IOBase. It
defines the basic interface to a stream. Note, however, that there is no
separation between reading and writing to streams; implementations are
allowed to raise an OSError if they do not support a given operation.
Extending IOBase is RawIOBase which deals simply with the reading and
writing of raw bytes to a stream. FileIO subclasses RawIOBase to provide
an interface to OS files.
BufferedIOBase deals with buffering on a raw byte stream (RawIOBase). Its
subclasses, BufferedWriter, BufferedReader, and BufferedRWPair buffer
streams that are readable, writable, and both respectively.
BufferedRandom provides a buffered interface to random access
streams. BytesIO is a simple stream of in-memory bytes.
Another IOBase subclass, TextIOBase, deals with the encoding and decoding
of streams into text. TextIOWrapper, which extends it, is a buffered text
interface to a buffered raw stream (`BufferedIOBase`). Finally, StringIO
is an in-memory stream for text.
Argument names are not part of the specification, and only the arguments
of open() are intended to be used as keyword arguments.
data:
DEFAULT_BUFFER_SIZE
An int containing the default buffer size used by the module's buffered
I/O classes. open() uses the file's blksize (as obtained by os.stat) if
possible.
"""
# New I/O library conforming to PEP 3116.
__author__ = ("Guido van Rossum <guido@python.org>, "
"Mike Verdone <mike.verdone@gmail.com>, "
"Mark Russell <mark.russell@zen.co.uk>, "
"Antoine Pitrou <solipsis@pitrou.net>, "
"Amaury Forgeot d'Arc <amauryfa@gmail.com>, "
"Benjamin Peterson <benjamin@python.org>")
__all__ = ["BlockingIOError", "open", "IOBase", "RawIOBase", "FileIO",
"BytesIO", "StringIO", "BufferedIOBase",
"BufferedReader", "BufferedWriter", "BufferedRWPair",
"BufferedRandom", "TextIOBase", "TextIOWrapper",
"UnsupportedOperation", "SEEK_SET", "SEEK_CUR", "SEEK_END"]
import _io
import abc
from _io import *
OpenWrapper = _io.open # for compatibility with _pyio
# Pretend this exception was created here.
#UnsupportedOperation.__module__ = "io"
# for seek()
SEEK_SET = 0
SEEK_CUR = 1
SEEK_END = 2
# Declaring ABCs in C is tricky so we do it here.
# Method descriptions and default implementations are inherited from the C
# version however.
class IOBase(_io._IOBase, metaclass=abc.ABCMeta):
__doc__ = _io._IOBase.__doc__
class RawIOBase(_io._RawIOBase, IOBase):
__doc__ = _io._RawIOBase.__doc__
class BufferedIOBase(_io._BufferedIOBase, IOBase):
__doc__ = _io._BufferedIOBase.__doc__
class TextIOBase(_io._TextIOBase, IOBase):
__doc__ = _io._TextIOBase.__doc__
RawIOBase.register(FileIO)
for klass in (BytesIO, BufferedReader, BufferedWriter):#, BufferedRandom,
#BufferedRWPair):
BufferedIOBase.register(klass)
for klass in (StringIO, TextIOWrapper):
TextIOBase.register(klass)
del klass
try:
from _io import _WindowsConsoleIO
except ImportError:
pass
else:
RawIOBase.register(_WindowsConsoleIO)
+366 -144
View File
@@ -1,7 +1,8 @@
/*
* I/O core tools.
*/
use std::cell::RefCell;
use std::cell::{Cell, RefCell};
use std::fs;
use std::io::prelude::*;
use std::io::Cursor;
use std::io::SeekFrom;
@@ -10,22 +11,25 @@ use num_traits::ToPrimitive;
use super::os;
use crate::function::{OptionalArg, OptionalOption, PyFuncArgs};
use crate::obj::objbool;
use crate::obj::objbytearray::PyByteArray;
use crate::obj::objbyteinner::PyBytesLike;
use crate::obj::objbytes;
use crate::obj::objbytes::PyBytes;
use crate::obj::objint::{self, PyIntRef};
use crate::obj::objint;
use crate::obj::objiter;
use crate::obj::objstr::{self, PyStringRef};
use crate::obj::objtype;
use crate::obj::objtype::PyClassRef;
use crate::pyobject::TypeProtocol;
use crate::pyobject::{BufferProtocol, Either, PyObjectRef, PyRef, PyResult, PyValue};
use crate::obj::objtype::{self, PyClassRef};
use crate::pyobject::{
BufferProtocol, Either, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
};
use crate::vm::VirtualMachine;
fn byte_count(bytes: OptionalOption<i64>) -> i64 {
bytes.flat_option().unwrap_or(-1 as i64)
}
const DEFAULT_BUFFER_SIZE: usize = 8 * 1024;
#[derive(Debug)]
struct BufferedIO {
cursor: Cursor<Vec<u8>>,
@@ -100,6 +104,7 @@ impl BufferedIO {
#[derive(Debug)]
struct PyStringIO {
buffer: RefCell<BufferedIO>,
closed: Cell<bool>,
}
type PyStringIORef = PyRef<PyStringIO>;
@@ -167,14 +172,34 @@ impl PyStringIORef {
}
}
fn close(self, _vm: &VirtualMachine) {
// TODO: discard the text buffer on close
fn truncate(self, size: OptionalOption<usize>, _vm: &VirtualMachine) {
let mut buffer = self.buffer.borrow_mut();
let size = size.flat_option().unwrap_or_else(|| buffer.tell() as usize);
buffer.cursor.get_mut().truncate(size);
}
fn closed(self, _vm: &VirtualMachine) -> bool {
self.closed.get()
}
fn close(self, _vm: &VirtualMachine) {
self.buffer.borrow_mut().cursor.get_mut().clear();
self.closed.set(true);
}
}
#[derive(FromArgs)]
struct StringIOArgs {
#[pyarg(positional_or_keyword, default = "None")]
#[allow(dead_code)]
// TODO: use this
newline: Option<PyStringRef>,
}
fn string_io_new(
cls: PyClassRef,
object: OptionalArg<Option<PyObjectRef>>,
_args: StringIOArgs,
vm: &VirtualMachine,
) -> PyResult<PyStringIORef> {
let raw_string = match object {
@@ -184,6 +209,7 @@ fn string_io_new(
PyStringIO {
buffer: RefCell::new(BufferedIO::new(Cursor::new(raw_string.into_bytes()))),
closed: Cell::new(false),
}
.into_ref_with_type(vm, cls)
}
@@ -191,6 +217,7 @@ fn string_io_new(
#[derive(Debug)]
struct PyBytesIO {
buffer: RefCell<BufferedIO>,
closed: Cell<bool>,
}
type PyBytesIORef = PyRef<PyBytesIO>;
@@ -247,6 +274,15 @@ impl PyBytesIORef {
None => Err(vm.new_value_error("Error Performing Operation".to_string())),
}
}
fn closed(self, _vm: &VirtualMachine) -> bool {
self.closed.get()
}
fn close(self, _vm: &VirtualMachine) {
self.buffer.borrow_mut().cursor.get_mut().clear();
self.closed.set(true);
}
}
fn bytes_io_new(
@@ -261,6 +297,7 @@ fn bytes_io_new(
PyBytesIO {
buffer: RefCell::new(BufferedIO::new(Cursor::new(raw_bytes))),
closed: Cell::new(false),
}
.into_ref_with_type(vm, cls)
}
@@ -269,7 +306,10 @@ fn io_base_cm_enter(instance: PyObjectRef, _vm: &VirtualMachine) -> PyObjectRef
instance.clone()
}
fn io_base_cm_exit(_args: PyFuncArgs, _vm: &VirtualMachine) {}
fn io_base_cm_exit(instance: PyObjectRef, _args: PyFuncArgs, vm: &VirtualMachine) -> PyResult<()> {
vm.call_method(&instance, "close", vec![])?;
Ok(())
}
// TODO Check if closed, then if so raise ValueError
fn io_base_flush(_self: PyObjectRef, _vm: &VirtualMachine) {}
@@ -277,49 +317,189 @@ fn io_base_flush(_self: PyObjectRef, _vm: &VirtualMachine) {}
fn io_base_seekable(_self: PyObjectRef, _vm: &VirtualMachine) -> bool {
false
}
fn io_base_readable(_self: PyObjectRef, _vm: &VirtualMachine) -> bool {
false
}
fn io_base_writable(_self: PyObjectRef, _vm: &VirtualMachine) -> bool {
false
}
fn io_base_closed(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
vm.get_attribute(instance, "__closed")
}
fn io_base_close(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let closed = objbool::boolval(vm, io_base_closed(instance.clone(), vm)?)?;
if !closed {
let res = vm.call_method(&instance, "flush", vec![]);
vm.set_attr(&instance, "__closed", vm.ctx.new_bool(true))?;
res?;
}
Ok(())
}
fn io_base_readline(
instance: PyObjectRef,
size: OptionalOption<i64>,
vm: &VirtualMachine,
) -> PyResult<Vec<u8>> {
let size = byte_count(size);
let mut res = Vec::<u8>::new();
let read = vm.get_attribute(instance, "read")?;
while size < 0 || res.len() < size as usize {
let read_res = PyBytesLike::try_from_object(vm, vm.invoke(&read, vec![vm.new_int(1)])?)?;
let b = read_res.to_cow();
if b.is_empty() {
break;
}
res.extend_from_slice(b.as_ref());
if res.ends_with(b"\n") {
break;
}
}
Ok(res)
}
fn io_base_checkclosed(
instance: PyObjectRef,
msg: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
if objbool::boolval(vm, vm.get_attribute(instance, "closed")?)? {
let msg = msg
.flat_option()
.unwrap_or_else(|| vm.new_str("I/O operation on closed file.".to_string()));
Err(vm.new_exception_obj(vm.ctx.exceptions.value_error.clone(), vec![msg])?)
} else {
Ok(())
}
}
fn io_base_checkreadable(
instance: PyObjectRef,
msg: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
if !objbool::boolval(vm, vm.call_method(&instance, "readable", vec![])?)? {
let msg = msg
.flat_option()
.unwrap_or_else(|| vm.new_str("File or stream is not readable.".to_string()));
Err(vm.new_exception_obj(vm.ctx.exceptions.value_error.clone(), vec![msg])?)
} else {
Ok(())
}
}
fn io_base_checkwritable(
instance: PyObjectRef,
msg: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
if !objbool::boolval(vm, vm.call_method(&instance, "writable", vec![])?)? {
let msg = msg
.flat_option()
.unwrap_or_else(|| vm.new_str("File or stream is not writable.".to_string()));
Err(vm.new_exception_obj(vm.ctx.exceptions.value_error.clone(), vec![msg])?)
} else {
Ok(())
}
}
fn io_base_checkseekable(
instance: PyObjectRef,
msg: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
if !objbool::boolval(vm, vm.call_method(&instance, "seekable", vec![])?)? {
let msg = msg
.flat_option()
.unwrap_or_else(|| vm.new_str("File or stream is not seekable.".to_string()));
Err(vm.new_exception_obj(vm.ctx.exceptions.value_error.clone(), vec![msg])?)
} else {
Ok(())
}
}
fn io_base_iter(instance: PyObjectRef, _vm: &VirtualMachine) -> PyObjectRef {
instance
}
fn io_base_next(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let line = vm.call_method(&instance, "readline", vec![])?;
if !objbool::boolval(vm, line.clone())? {
Err(objiter::new_stop_iteration(vm))
} else {
Ok(line)
}
}
fn io_base_readlines(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
Ok(vm.ctx.new_list(vm.extract_elements(&instance)?))
}
fn raw_io_base_read(
instance: PyObjectRef,
size: OptionalOption<i64>,
vm: &VirtualMachine,
) -> PyResult {
let size = byte_count(size);
if size < 0 {
return vm.call_method(&instance, "readall", vec![]);
}
let b = PyByteArray::new(vec![0; size as usize]).into_ref(vm);
let n = <Option<usize>>::try_from_object(
vm,
vm.call_method(&instance, "readinto", vec![b.as_object().clone()])?,
)?;
if let Some(n) = n {
let bytes = &mut b.inner.borrow_mut().elements;
bytes.truncate(n);
Ok(vm.ctx.new_bytes(bytes.clone()))
} else {
Ok(vm.get_none())
}
}
fn buffered_io_base_init(
instance: PyObjectRef,
raw: PyObjectRef,
buffer_size: OptionalArg<usize>,
vm: &VirtualMachine,
) -> PyResult<()> {
vm.set_attr(&instance, "raw", raw.clone())?;
vm.set_attr(
&instance,
"buffer_size",
vm.new_int(buffer_size.unwrap_or(DEFAULT_BUFFER_SIZE)),
)?;
Ok(())
}
fn buffered_reader_read(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
let buff_size = 8 * 1024;
let buffer = vm.ctx.new_bytearray(vec![0; buff_size]);
fn buffered_io_base_fileno(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let raw = vm.get_attribute(instance, "raw")?;
vm.call_method(&raw, "fileno", vec![])
}
//buffer method
let mut result = vec![];
let mut length = buff_size;
let raw = vm.get_attribute(instance.clone(), "raw").unwrap();
//Iterates through the raw class, invoking the readinto method
//to obtain buff_size many bytes. Exit when less than buff_size many
//bytes are returned (when the end of the file is reached).
while length == buff_size {
vm.call_method(&raw, "readinto", vec![buffer.clone()])
.map_err(|_| vm.new_value_error("IO Error".to_string()))?;
//Copy bytes from the buffer vector into the results vector
if let Some(bytes) = buffer.payload::<PyByteArray>() {
result.extend_from_slice(&bytes.inner.borrow().elements);
};
let py_len = vm.call_method(&buffer, "__len__", PyFuncArgs::default())?;
length = objint::get_value(&py_len).to_usize().unwrap();
}
Ok(result)
fn buffered_reader_read(
instance: PyObjectRef,
size: OptionalOption<i64>,
vm: &VirtualMachine,
) -> PyResult {
vm.call_method(
&vm.get_attribute(instance.clone(), "raw")?,
"read",
vec![vm.new_int(byte_count(size))],
)
}
fn buffered_reader_seekable(_self: PyObjectRef, _vm: &VirtualMachine) -> bool {
true
}
fn buffered_reader_close(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let raw = vm.get_attribute(instance, "raw")?;
vm.invoke(&vm.get_attribute(raw, "close")?, vec![])?;
Ok(())
}
fn compute_c_flag(mode: &str) -> u32 {
let flag = match mode.chars().next() {
Some(mode) => match mode {
@@ -336,63 +516,72 @@ fn compute_c_flag(mode: &str) -> u32 {
fn file_io_init(
file_io: PyObjectRef,
name: Either<PyStringRef, PyIntRef>,
name: Either<PyStringRef, i64>,
mode: OptionalArg<PyStringRef>,
vm: &VirtualMachine,
) -> PyResult {
let file_no = match &name {
let (name, file_no) = match name {
Either::A(name) => {
let mode = match mode {
OptionalArg::Present(mode) => compute_c_flag(mode.as_str()),
OptionalArg::Missing => libc::O_RDONLY as _,
};
let fno = os::os_open(
name.clone(),
mode as _,
OptionalArg::Missing,
OptionalArg::Missing,
vm,
)?;
vm.new_int(fno)
(
name.clone().into_object(),
os::os_open(
name,
mode as _,
OptionalArg::Missing,
OptionalArg::Missing,
vm,
)?,
)
}
Either::B(fno) => fno.clone().into_object(),
Either::B(fno) => (vm.new_int(fno), fno),
};
vm.set_attr(&file_io, "name", name.into_object())?;
vm.set_attr(&file_io, "fileno", file_no)?;
vm.set_attr(&file_io, "name", name)?;
vm.set_attr(&file_io, "__fileno", vm.new_int(file_no))?;
vm.set_attr(&file_io, "closefd", vm.new_bool(false))?;
vm.set_attr(&file_io, "closed", vm.new_bool(false))?;
Ok(vm.get_none())
}
fn fio_get_fileno(instance: &PyObjectRef, vm: &VirtualMachine) -> PyResult<fs::File> {
io_base_checkclosed(instance.clone(), OptionalArg::Missing, vm)?;
let fileno = i64::try_from_object(vm, vm.get_attribute(instance.clone(), "__fileno")?)?;
Ok(os::rust_file(fileno))
}
fn fio_set_fileno(instance: &PyObjectRef, f: fs::File, vm: &VirtualMachine) -> PyResult<()> {
let updated = os::raw_file_number(f);
vm.set_attr(&instance, "__fileno", vm.ctx.new_int(updated))?;
Ok(())
}
fn file_io_read(
instance: PyObjectRef,
read_byte: OptionalArg<usize>,
read_byte: OptionalOption<i64>,
vm: &VirtualMachine,
) -> PyResult<Vec<u8>> {
let file_no = vm.get_attribute(instance.clone(), "fileno")?;
let raw_fd = objint::get_value(&file_no).to_i64().unwrap();
let read_byte = byte_count(read_byte);
let mut handle = os::rust_file(raw_fd);
let mut handle = fio_get_fileno(&instance, vm)?;
let bytes = match read_byte {
OptionalArg::Missing => {
let mut bytes = vec![];
handle
.read_to_end(&mut bytes)
.map_err(|_| vm.new_value_error("Error reading from Buffer".to_string()))?;
bytes
}
OptionalArg::Present(read_byte) => {
let mut bytes = vec![0; read_byte];
handle
.read_exact(&mut bytes)
.map_err(|_| vm.new_value_error("Error reading from Buffer".to_string()))?;
let updated = os::raw_file_number(handle);
vm.set_attr(&instance, "fileno", vm.ctx.new_int(updated))?;
bytes
}
let bytes = if read_byte < 0 {
let mut bytes = vec![];
handle
.read_to_end(&mut bytes)
.map_err(|e| os::convert_io_error(vm, e))?;
bytes
} else {
let mut bytes = vec![0; read_byte as usize];
let n = handle
.read(&mut bytes)
.map_err(|e| os::convert_io_error(vm, e))?;
bytes.truncate(n);
bytes
};
fio_set_fileno(&instance, handle, vm)?;
Ok(bytes)
}
@@ -408,11 +597,7 @@ fn file_io_readinto(instance: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine
let py_length = vm.call_method(&obj, "__len__", PyFuncArgs::default())?;
let length = objint::get_value(&py_length).to_u64().unwrap();
let file_no = vm.get_attribute(instance.clone(), "fileno")?;
let raw_fd = objint::get_value(&file_no).to_i64().unwrap();
//extract unix file descriptor.
let handle = os::rust_file(raw_fd);
let handle = fio_get_fileno(&instance, vm)?;
let mut f = handle.take(length);
if let Some(bytes) = obj.payload::<PyByteArray>() {
@@ -426,51 +611,29 @@ fn file_io_readinto(instance: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine
}
};
let updated = os::raw_file_number(f.into_inner());
vm.set_attr(&instance, "fileno", vm.ctx.new_int(updated))?;
fio_set_fileno(&instance, f.into_inner(), vm)?;
Ok(())
}
fn file_io_write(instance: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
let file_no = vm.get_attribute(instance.clone(), "fileno")?;
let raw_fd = objint::get_value(&file_no).to_i64().unwrap();
fn file_io_write(instance: PyObjectRef, obj: PyBytesLike, vm: &VirtualMachine) -> PyResult<usize> {
let mut handle = fio_get_fileno(&instance, vm)?;
//unsafe block - creates file handle from the UNIX file descriptor
//raw_fd is supported on UNIX only. This will need to be extended
//to support windows - i.e. raw file_handles
let mut handle = os::rust_file(raw_fd);
let len = handle
.write(obj.to_cow().as_ref())
.map_err(|e| os::convert_io_error(vm, e))?;
let bytes = match_class!(match obj.clone() {
i @ PyBytes => Ok(i.get_value().to_vec()),
j @ PyByteArray => Ok(j.inner.borrow().elements.to_vec()),
obj => Err(vm.new_type_error(format!(
"a bytes-like object is required, not {}",
obj.class()
))),
});
fio_set_fileno(&instance, handle, vm)?;
match handle.write(&bytes?) {
Ok(len) => {
//reset raw fd on the FileIO object
let updated = os::raw_file_number(handle);
vm.set_attr(&instance, "fileno", vm.ctx.new_int(updated))?;
//return number of bytes written
Ok(len)
}
Err(_) => Err(vm.new_value_error("Error Writing Bytes to Handle".to_string())),
}
//return number of bytes written
Ok(len)
}
#[cfg(windows)]
fn file_io_close(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
use std::os::windows::io::IntoRawHandle;
let file_no = vm.get_attribute(instance.clone(), "fileno")?;
let raw_fd = objint::get_value(&file_no).to_i64().unwrap();
let handle = os::rust_file(raw_fd);
let raw_handle = handle.into_raw_handle();
let raw_handle = i64::try_from_object(vm, vm.get_attribute(instance.clone(), "__fileno")?)?;
unsafe {
winapi::um::handleapi::CloseHandle(raw_handle);
winapi::um::handleapi::CloseHandle(raw_handle as _);
}
vm.set_attr(&instance, "closefd", vm.new_bool(true))?;
vm.set_attr(&instance, "closed", vm.new_bool(true))?;
@@ -479,10 +642,9 @@ fn file_io_close(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
#[cfg(unix)]
fn file_io_close(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let file_no = vm.get_attribute(instance.clone(), "fileno")?;
let raw_fd = objint::get_value(&file_no).to_i32().unwrap();
let raw_fd = i64::try_from_object(vm, vm.get_attribute(instance.clone(), "__fileno")?)?;
unsafe {
libc::close(raw_fd);
libc::close(raw_fd as _);
}
vm.set_attr(&instance, "closefd", vm.new_bool(true))?;
vm.set_attr(&instance, "closed", vm.new_bool(true))?;
@@ -493,6 +655,10 @@ fn file_io_seekable(_self: PyObjectRef, _vm: &VirtualMachine) -> bool {
true
}
fn file_io_fileno(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
vm.get_attribute(instance, "__fileno")
}
fn buffered_writer_write(instance: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let raw = vm.get_attribute(instance, "raw").unwrap();
@@ -517,7 +683,11 @@ fn text_io_wrapper_seekable(_self: PyObjectRef, _vm: &VirtualMachine) -> bool {
true
}
fn text_io_base_read(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<String> {
fn text_io_wrapper_read(
instance: PyObjectRef,
size: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<String> {
let buffered_reader_class = vm.try_class("_io", "BufferedReader")?;
let raw = vm.get_attribute(instance.clone(), "buffer").unwrap();
@@ -526,23 +696,23 @@ fn text_io_base_read(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<Str
return Err(vm.new_value_error("not readable".to_string()));
}
if let Ok(bytes) = vm.call_method(&raw, "read", PyFuncArgs::default()) {
let value = objbytes::get_value(&bytes).to_vec();
//format bytes into string
let rust_string = String::from_utf8(value).map_err(|e| {
vm.new_unicode_decode_error(format!(
"cannot decode byte at index: {}",
e.utf8_error().valid_up_to()
))
})?;
Ok(rust_string)
} else {
Err(vm.new_value_error("Error unpacking Bytes".to_string()))
}
let bytes = vm.call_method(
&raw,
"read",
vec![size.flat_option().unwrap_or_else(|| vm.get_none())],
)?;
let bytes = PyBytesLike::try_from_object(vm, bytes)?;
//format bytes into string
let rust_string = String::from_utf8(bytes.to_cow().into_owned()).map_err(|e| {
vm.new_unicode_decode_error(format!(
"cannot decode byte at index: {}",
e.utf8_error().valid_up_to()
))
})?;
Ok(rust_string)
}
fn text_io_base_write(
fn text_io_wrapper_write(
instance: PyObjectRef,
obj: PyStringRef,
vm: &VirtualMachine,
@@ -572,6 +742,35 @@ fn text_io_base_write(
Ok(len)
}
fn text_io_wrapper_readline(
instance: PyObjectRef,
size: OptionalOption<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<String> {
let buffered_reader_class = vm.try_class("_io", "BufferedReader")?;
let raw = vm.get_attribute(instance.clone(), "buffer").unwrap();
if !objtype::isinstance(&raw, &buffered_reader_class) {
// TODO: this should be io.UnsupportedOperation error which derives both from ValueError *and* OSError
return Err(vm.new_value_error("not readable".to_string()));
}
let bytes = vm.call_method(
&raw,
"readline",
vec![size.flat_option().unwrap_or_else(|| vm.get_none())],
)?;
let bytes = PyBytesLike::try_from_object(vm, bytes)?;
//format bytes into string
let rust_string = String::from_utf8(bytes.to_cow().into_owned()).map_err(|e| {
vm.new_unicode_decode_error(format!(
"cannot decode byte at index: {}",
e.utf8_error().valid_up_to()
))
})?;
Ok(rust_string)
}
fn split_mode_string(mode_string: String) -> Result<(String, String), String> {
let mut mode: char = '\0';
let mut typ: char = '\0';
@@ -698,23 +897,35 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
let ctx = &vm.ctx;
//IOBase the abstract base class of the IO Module
let io_base = py_class!(ctx, "IOBase", ctx.object(), {
let io_base = py_class!(ctx, "_IOBase", ctx.object(), {
"__enter__" => ctx.new_rustfunc(io_base_cm_enter),
"__exit__" => ctx.new_rustfunc(io_base_cm_exit),
"seekable" => ctx.new_rustfunc(io_base_seekable),
"flush" => ctx.new_rustfunc(io_base_flush)
"readable" => ctx.new_rustfunc(io_base_readable),
"writable" => ctx.new_rustfunc(io_base_writable),
"flush" => ctx.new_rustfunc(io_base_flush),
"closed" => ctx.new_property(io_base_closed),
"__closed" => ctx.new_bool(false),
"close" => ctx.new_rustfunc(io_base_close),
"readline" => ctx.new_rustfunc(io_base_readline),
"_checkClosed" => ctx.new_rustfunc(io_base_checkclosed),
"_checkReadable" => ctx.new_rustfunc(io_base_checkreadable),
"_checkWritable" => ctx.new_rustfunc(io_base_checkwritable),
"_checkSeekable" => ctx.new_rustfunc(io_base_checkseekable),
"__iter__" => ctx.new_rustfunc(io_base_iter),
"__next__" => ctx.new_rustfunc(io_base_next),
"readlines" => ctx.new_rustfunc(io_base_readlines),
});
// IOBase Subclasses
let raw_io_base = py_class!(ctx, "RawIOBase", io_base.clone(), {});
let raw_io_base = py_class!(ctx, "_RawIOBase", io_base.clone(), {
"read" => ctx.new_rustfunc(raw_io_base_read),
});
let buffered_io_base = py_class!(ctx, "BufferedIOBase", io_base.clone(), {});
let buffered_io_base = py_class!(ctx, "_BufferedIOBase", io_base.clone(), {});
//TextIO Base has no public constructor
let text_io_base = py_class!(ctx, "TextIOBase", io_base.clone(), {
"read" => ctx.new_rustfunc(text_io_base_read),
"write" => ctx.new_rustfunc(text_io_base_write)
});
let text_io_base = py_class!(ctx, "_TextIOBase", io_base.clone(), {});
// RawBaseIO Subclasses
// TODO Fix name?
@@ -725,7 +936,8 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
"readinto" => ctx.new_rustfunc(file_io_readinto),
"write" => ctx.new_rustfunc(file_io_write),
"close" => ctx.new_rustfunc(file_io_close),
"seekable" => ctx.new_rustfunc(file_io_seekable)
"seekable" => ctx.new_rustfunc(file_io_seekable),
"fileno" => ctx.new_rustfunc(file_io_fileno),
});
// BufferedIOBase Subclasses
@@ -735,7 +947,9 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
//For more info see: https://github.com/RustPython/RustPython/issues/547
"__init__" => ctx.new_rustfunc(buffered_io_base_init),
"read" => ctx.new_rustfunc(buffered_reader_read),
"seekable" => ctx.new_rustfunc(buffered_reader_seekable)
"seekable" => ctx.new_rustfunc(buffered_reader_seekable),
"close" => ctx.new_rustfunc(buffered_reader_close),
"fileno" => ctx.new_rustfunc(buffered_io_base_fileno),
});
let buffered_writer = py_class!(ctx, "BufferedWriter", buffered_io_base.clone(), {
@@ -744,13 +958,17 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
//For more info see: https://github.com/RustPython/RustPython/issues/547
"__init__" => ctx.new_rustfunc(buffered_io_base_init),
"write" => ctx.new_rustfunc(buffered_writer_write),
"seekable" => ctx.new_rustfunc(buffered_writer_seekable)
"seekable" => ctx.new_rustfunc(buffered_writer_seekable),
"fileno" => ctx.new_rustfunc(buffered_io_base_fileno),
});
//TextIOBase Subclass
let text_io_wrapper = py_class!(ctx, "TextIOWrapper", text_io_base.clone(), {
"__init__" => ctx.new_rustfunc(text_io_wrapper_init),
"seekable" => ctx.new_rustfunc(text_io_wrapper_seekable)
"seekable" => ctx.new_rustfunc(text_io_wrapper_seekable),
"read" => ctx.new_rustfunc(text_io_wrapper_read),
"write" => ctx.new_rustfunc(text_io_wrapper_write),
"readline" => ctx.new_rustfunc(text_io_wrapper_readline),
});
//StringIO: in-memory text
@@ -763,6 +981,8 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
"getvalue" => ctx.new_rustfunc(PyStringIORef::getvalue),
"tell" => ctx.new_rustfunc(PyStringIORef::tell),
"readline" => ctx.new_rustfunc(PyStringIORef::readline),
"truncate" => ctx.new_rustfunc(PyStringIORef::truncate),
"closed" => ctx.new_property(PyStringIORef::closed),
"close" => ctx.new_rustfunc(PyStringIORef::close),
});
@@ -777,14 +997,16 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
"getvalue" => ctx.new_rustfunc(PyBytesIORef::getvalue),
"tell" => ctx.new_rustfunc(PyBytesIORef::tell),
"readline" => ctx.new_rustfunc(PyBytesIORef::readline),
"closed" => ctx.new_property(PyBytesIORef::closed),
"close" => ctx.new_rustfunc(PyBytesIORef::close),
});
py_module!(vm, "_io", {
"open" => ctx.new_rustfunc(io_open),
"IOBase" => io_base,
"RawIOBase" => raw_io_base,
"BufferedIOBase" => buffered_io_base,
"TextIOBase" => text_io_base,
"_IOBase" => io_base,
"_RawIOBase" => raw_io_base,
"_BufferedIOBase" => buffered_io_base,
"_TextIOBase" => text_io_base,
"FileIO" => file_io,
"BufferedReader" => buffered_reader,
"BufferedWriter" => buffered_writer,