mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-09 22:49:57 +09:00
Better error handling for file io
Add FileNotFoundError Add PermissionError Minor idomatic clean ups
This commit is contained in:
@@ -96,6 +96,8 @@ pub struct ExceptionZoo {
|
||||
pub value_error: PyObjectRef,
|
||||
pub import_error: PyObjectRef,
|
||||
pub module_not_found_error: PyObjectRef,
|
||||
pub file_not_found_error: PyObjectRef,
|
||||
pub permission_error: PyObjectRef,
|
||||
}
|
||||
|
||||
impl ExceptionZoo {
|
||||
@@ -138,6 +140,10 @@ impl ExceptionZoo {
|
||||
let import_error = create_type("ImportError", &type_type, &exception_type, &dict_type);
|
||||
let module_not_found_error =
|
||||
create_type("ModuleNotFoundError", &type_type, &import_error, &dict_type);
|
||||
let file_not_found_error =
|
||||
create_type("FileNotFoundError", &type_type, &import_error, &dict_type);
|
||||
let permission_error =
|
||||
create_type("PermissionError", &type_type, &import_error, &dict_type);
|
||||
|
||||
ExceptionZoo {
|
||||
base_exception_type: base_exception_type,
|
||||
@@ -155,6 +161,8 @@ impl ExceptionZoo {
|
||||
value_error: value_error,
|
||||
import_error: import_error,
|
||||
module_not_found_error: module_not_found_error,
|
||||
file_not_found_error: file_not_found_error,
|
||||
permission_error: permission_error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,10 +81,8 @@ fn buffered_reader_read(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
//bytes are returned (when the end of the file is reached).
|
||||
while length == buff_size {
|
||||
let raw_read = vm.get_method(raw.clone(), &"readinto".to_string()).unwrap();
|
||||
match vm.invoke(raw_read, PyFuncArgs::new(vec![buffer.clone()], vec![])) {
|
||||
Ok(_) => {}
|
||||
Err(_) => return Err(vm.new_value_error("IO Error".to_string())),
|
||||
}
|
||||
vm.invoke(raw_read, PyFuncArgs::new(vec![buffer.clone()], vec![]))
|
||||
.map_err(|_| vm.new_value_error("IO Error".to_string()))?;
|
||||
|
||||
//Copy bytes from the buffer vector into the results vector
|
||||
match buffer.borrow_mut().payload {
|
||||
@@ -110,18 +108,15 @@ fn file_io_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
optional = [(mode, Some(vm.ctx.str_type()))]
|
||||
);
|
||||
|
||||
let rust_mode = match mode {
|
||||
Some(m) => objstr::get_value(m),
|
||||
None => "r".to_string(),
|
||||
};
|
||||
let rust_mode = mode.map_or("r".to_string(), |m| objstr::get_value(m));
|
||||
|
||||
match compute_c_flag(&rust_mode).to_bigint() {
|
||||
Some(os_mode) => {
|
||||
let args = vec![name.clone(), vm.ctx.new_int(os_mode)];
|
||||
let fileno = os::os_open(vm, PyFuncArgs::new(args, vec![]));
|
||||
let file_no = os::os_open(vm, PyFuncArgs::new(args, vec![]))?;
|
||||
|
||||
vm.ctx.set_attr(&file_io, "name", name.clone());
|
||||
vm.ctx.set_attr(&file_io, "fileno", fileno.unwrap());
|
||||
vm.ctx.set_attr(&file_io, "file_no", file_no);
|
||||
Ok(vm.get_none())
|
||||
}
|
||||
None => Err(vm.new_type_error(format!("invalid mode {}", rust_mode))),
|
||||
@@ -166,8 +161,8 @@ fn file_io_readinto(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
let py_length = vm.invoke(len_method.unwrap(), PyFuncArgs::default());
|
||||
let length = objint::get_value(&py_length.unwrap()).to_u64().unwrap();
|
||||
|
||||
let fileno = file_io.get_attr("fileno").unwrap();
|
||||
let raw_fd = objint::get_value(&fileno).to_i32().unwrap();
|
||||
let file_no = file_io.get_attr("file_no").unwrap();
|
||||
let raw_fd = objint::get_value(&file_no).to_i32().unwrap();
|
||||
|
||||
//unsafe block - creates file handle from the UNIX file descriptor
|
||||
//raw_fd is supported on UNIX only. This will need to be extended
|
||||
@@ -189,7 +184,7 @@ fn file_io_readinto(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
|
||||
let new_handle = f.into_inner().into_raw_fd().to_bigint();
|
||||
vm.ctx
|
||||
.set_attr(&file_io, "fileno", vm.ctx.new_int(new_handle.unwrap()));
|
||||
.set_attr(&file_io, "file_no", vm.ctx.new_int(new_handle.unwrap()));
|
||||
Ok(vm.get_none())
|
||||
}
|
||||
|
||||
@@ -200,8 +195,8 @@ fn file_io_write(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
required = [(file_io, None), (obj, Some(vm.ctx.bytes_type()))]
|
||||
);
|
||||
|
||||
let fileno = file_io.get_attr("fileno").unwrap();
|
||||
let raw_fd = objint::get_value(&fileno).to_i32().unwrap();
|
||||
let file_no = file_io.get_attr("file_no").unwrap();
|
||||
let raw_fd = objint::get_value(&file_no).to_i32().unwrap();
|
||||
|
||||
//unsafe block - creates file handle from the UNIX file descriptor
|
||||
//raw_fd is supported on UNIX only. This will need to be extended
|
||||
@@ -215,7 +210,7 @@ fn file_io_write(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
//reset raw fd on the FileIO object
|
||||
let new_handle = handle.into_raw_fd().to_bigint();
|
||||
vm.ctx
|
||||
.set_attr(&file_io, "fileno", vm.ctx.new_int(new_handle.unwrap()));
|
||||
.set_attr(&file_io, "file_no", vm.ctx.new_int(new_handle.unwrap()));
|
||||
|
||||
//return number of bytes written
|
||||
Ok(vm.ctx.new_int(len.to_bigint().unwrap()))
|
||||
@@ -280,11 +275,7 @@ pub fn io_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
let module = mk_module(&vm.ctx);
|
||||
|
||||
//mode is optional: 'rt' is the default mode (open from reading text)
|
||||
let rust_mode = if let Some(m) = mode {
|
||||
objstr::get_value(m)
|
||||
} else {
|
||||
"rt".to_string()
|
||||
};
|
||||
let rust_mode = mode.map_or("rt".to_string(), |m| objstr::get_value(m));
|
||||
|
||||
let mut raw_modes = HashSet::new();
|
||||
|
||||
@@ -322,7 +313,7 @@ pub fn io_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
vec![file.clone(), vm.ctx.new_str(modes[0].to_string())],
|
||||
vec![],
|
||||
);
|
||||
let file_io = vm.invoke(file_io_class, file_args).unwrap();
|
||||
let file_io = vm.invoke(file_io_class, file_args)?;
|
||||
|
||||
//Create Buffered class to consume FileIO. The type of buffered class depends on
|
||||
//the operation in the mode.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::ErrorKind;
|
||||
use std::os::unix::io::IntoRawFd;
|
||||
|
||||
use num_bigint::ToBigInt;
|
||||
@@ -22,25 +23,34 @@ pub fn os_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
]
|
||||
);
|
||||
|
||||
let fname = objstr::get_value(&name);
|
||||
|
||||
let handle = match objint::get_value(mode).to_u16().unwrap() {
|
||||
0 => OpenOptions::new().read(true).open(objstr::get_value(&name)),
|
||||
1 => OpenOptions::new()
|
||||
.write(true)
|
||||
.open(objstr::get_value(&name)),
|
||||
512 => OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(objstr::get_value(&name)),
|
||||
_ => OpenOptions::new().read(true).open(objstr::get_value(&name)),
|
||||
};
|
||||
0 => OpenOptions::new().read(true).open(&fname),
|
||||
1 => OpenOptions::new().write(true).open(&fname),
|
||||
512 => OpenOptions::new().write(true).create(true).open(&fname),
|
||||
_ => OpenOptions::new().read(true).open(&fname),
|
||||
}
|
||||
.map_err(|err| match err.kind() {
|
||||
ErrorKind::NotFound => {
|
||||
let exc_type = vm.ctx.exceptions.file_not_found_error.clone();
|
||||
vm.new_exception(exc_type, format!("No such file or directory: {}", &fname))
|
||||
}
|
||||
ErrorKind::PermissionDenied => {
|
||||
let exc_type = vm.ctx.exceptions.permission_error.clone();
|
||||
vm.new_exception(exc_type, format!("Permission denied: {}", &fname))
|
||||
}
|
||||
_ => vm.new_value_error("Unhandled file IO error".to_string()),
|
||||
})?;
|
||||
|
||||
//raw_fd is supported on UNIX only. This will need to be extended
|
||||
//to support windows - i.e. raw file_handles
|
||||
if let Ok(f) = handle {
|
||||
Ok(vm.ctx.new_int(f.into_raw_fd().to_bigint().unwrap()))
|
||||
} else {
|
||||
Err(vm.new_value_error("Bad file descriptor".to_string()))
|
||||
}
|
||||
Ok(vm.ctx.new_int(
|
||||
handle
|
||||
.into_raw_fd()
|
||||
.to_bigint()
|
||||
.expect("Invalid file descriptor"),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
|
||||
|
||||
Reference in New Issue
Block a user