Skip to content

Commit 22a9610

Browse files
committed
Improve behavior wrt errors during import
1 parent d650476 commit 22a9610

7 files changed

Lines changed: 57 additions & 37 deletions

File tree

src/main.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ extern crate rustpython_vm;
1010
use clap::{App, Arg};
1111
use rustpython_parser::parser;
1212
use rustpython_vm::compile;
13+
use rustpython_vm::obj::objstr;
1314
use rustpython_vm::print_exception;
15+
use rustpython_vm::pyobject::PyObjectRef;
1416
use rustpython_vm::VirtualMachine;
1517
use std::io;
1618
use std::io::prelude::*;
1719
use std::path::Path;
1820

19-
use rustpython_vm::pyobject::PyObjectRef;
20-
2121
fn main() {
2222
env_logger::init();
2323
let matches = App::new("RustPython")
@@ -99,17 +99,21 @@ fn shell_exec(vm: &mut VirtualMachine, source: &str, scope: PyObjectRef) -> bool
9999
Ok(_value) => {
100100
// Printed already.
101101
}
102-
Err(msg) => {
103-
print_exception(vm, &msg);
102+
Err(err) => {
103+
print_exception(vm, &err);
104104
}
105105
}
106106
}
107-
Err(msg) => {
107+
Err(err) => {
108108
// Enum rather than special string here.
109+
let msg = match vm.get_attribute(err.clone(), "msg") {
110+
Ok(value) => objstr::get_value(&value),
111+
Err(_) => panic!("Expected msg attribute on exception object!"),
112+
};
109113
if msg == "Unexpected end of input." {
110114
return false;
111115
} else {
112-
println!("Error: {:?}", msg)
116+
print_exception(vm, &err);
113117
}
114118
}
115119
};

vm/src/builtins.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,7 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
110110
let mode = compile::Mode::Eval;
111111
let source = source.borrow().str();
112112

113-
match compile::compile(vm, &source, mode, None) {
114-
Ok(value) => Ok(value),
115-
Err(msg) => Err(vm.new_type_error(msg)),
116-
}
113+
compile::compile(vm, &source, mode, None)
117114
}
118115

119116
// builtin_complex

vm/src/compile.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ extern crate rustpython_parser;
66

77
use self::rustpython_parser::{ast, parser};
88
use super::bytecode::{self, CodeObject, Instruction};
9-
use super::pyobject::{PyObject, PyObjectKind, PyObjectRef};
9+
use super::pyobject::{PyObject, PyObjectKind, PyResult};
1010
use super::vm::VirtualMachine;
1111

1212
struct Compiler {
@@ -21,27 +21,31 @@ pub fn compile(
2121
source: &str,
2222
mode: Mode,
2323
source_path: Option<String>,
24-
) -> Result<PyObjectRef, String> {
24+
) -> PyResult {
2525
let mut compiler = Compiler::new();
2626
compiler.source_path = source_path.clone();
2727
compiler.push_new_code_object(source_path, "<module>".to_string());
28+
let syntax_error = vm.context().exceptions.syntax_error.clone();
2829
match mode {
2930
Mode::Exec => match parser::parse_program(source) {
3031
Ok(ast) => {
3132
compiler.compile_program(&ast);
3233
}
33-
Err(msg) => return Err(msg),
34+
Err(msg) => return Err(vm.new_exception(syntax_error.clone(), msg)),
3435
},
3536
Mode::Eval => match parser::parse_statement(source) {
3637
Ok(statement) => {
3738
if let &ast::Statement::Expression { ref expression } = &statement.node {
3839
compiler.compile_expression(expression);
3940
compiler.emit(Instruction::ReturnValue);
4041
} else {
41-
return Err("Expecting expression, got statement".to_string());
42+
return Err(vm.new_exception(
43+
syntax_error.clone(),
44+
"Expecting expression, got statement".to_string(),
45+
));
4246
}
4347
}
44-
Err(msg) => return Err(msg),
48+
Err(msg) => return Err(vm.new_exception(syntax_error.clone(), msg)),
4549
},
4650
Mode::Single => match parser::parse_program(source) {
4751
Ok(ast) => {
@@ -58,7 +62,7 @@ pub fn compile(
5862
});
5963
compiler.emit(Instruction::ReturnValue);
6064
}
61-
Err(msg) => return Err(msg),
65+
Err(msg) => return Err(vm.new_exception(syntax_error.clone(), msg)),
6266
},
6367
};
6468

vm/src/eval.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ pub fn eval(vm: &mut VirtualMachine, source: &str, scope: PyObjectRef) -> PyResu
1010
debug!("Code object: {:?}", bytecode);
1111
vm.run_code_obj(bytecode, scope)
1212
}
13-
Err(msg) => {
14-
panic!("Parsing went horribly wrong: {}", msg);
15-
}
13+
Err(err) => Err(err),
1614
}
1715
}
1816

vm/src/exceptions.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ fn exception_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
1515
vm.new_str("No msg".to_string())
1616
};
1717
let traceback = vm.ctx.new_list(Vec::new());
18-
zelf.set_attr("__msg__", msg);
18+
zelf.set_attr("msg", msg);
1919
zelf.set_attr("__traceback__", traceback);
2020
Ok(vm.get_none())
2121
}
@@ -71,7 +71,7 @@ fn exception_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
7171
required = [(exc, Some(vm.ctx.exceptions.exception_type.clone()))]
7272
);
7373
let type_name = objtype::get_type_name(&exc.typ());
74-
let msg = if let Some(m) = exc.get_attr("__msg__") {
74+
let msg = if let Some(m) = exc.get_attr("msg") {
7575
objstr::get_value(&m)
7676
} else {
7777
panic!("Error message must be set");
@@ -84,6 +84,7 @@ fn exception_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
8484
pub struct ExceptionZoo {
8585
pub base_exception_type: PyObjectRef,
8686
pub exception_type: PyObjectRef,
87+
pub syntax_error: PyObjectRef,
8788
pub assertion_error: PyObjectRef,
8889
pub attribute_error: PyObjectRef,
8990
pub name_error: PyObjectRef,
@@ -92,6 +93,8 @@ pub struct ExceptionZoo {
9293
pub stop_iteration: PyObjectRef,
9394
pub type_error: PyObjectRef,
9495
pub value_error: PyObjectRef,
96+
pub import_error: PyObjectRef,
97+
pub module_not_found_error: PyObjectRef,
9598
}
9699

97100
impl ExceptionZoo {
@@ -109,6 +112,12 @@ impl ExceptionZoo {
109112
&base_exception_type,
110113
&dict_type,
111114
);
115+
let syntax_error = create_type(
116+
&String::from("SyntaxError"),
117+
&type_type,
118+
&exception_type,
119+
&dict_type,
120+
);
112121
let assertion_error = create_type(
113122
&String::from("AssertionError"),
114123
&type_type,
@@ -157,10 +166,23 @@ impl ExceptionZoo {
157166
&exception_type,
158167
&dict_type,
159168
);
169+
let import_error = create_type(
170+
&String::from("ImportError"),
171+
&type_type,
172+
&exception_type,
173+
&dict_type,
174+
);
175+
let module_not_found_error = create_type(
176+
&String::from("ModuleNotFoundError"),
177+
&type_type,
178+
&import_error,
179+
&dict_type,
180+
);
160181

161182
ExceptionZoo {
162183
base_exception_type: base_exception_type,
163184
exception_type: exception_type,
185+
syntax_error: syntax_error,
164186
assertion_error: assertion_error,
165187
attribute_error: attribute_error,
166188
name_error: name_error,
@@ -169,6 +191,8 @@ impl ExceptionZoo {
169191
stop_iteration: stop_iteration,
170192
type_error: type_error,
171193
value_error: value_error,
194+
import_error: import_error,
195+
module_not_found_error: module_not_found_error,
172196
}
173197
}
174198
}

vm/src/import.rs

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
extern crate rustpython_parser;
66

7-
use std::io;
8-
use std::io::ErrorKind::NotFound;
97
use std::path::PathBuf;
108

119
use self::rustpython_parser::parser;
@@ -19,14 +17,14 @@ fn import_uncached_module(vm: &mut VirtualMachine, module: &str) -> PyResult {
1917
return Ok(module(&vm.ctx).clone());
2018
}
2119

22-
// TODO: introduce import error:
23-
let import_error = vm.context().exceptions.exception_type.clone();
20+
let notfound_error = vm.context().exceptions.module_not_found_error.clone();
21+
let import_error = vm.context().exceptions.import_error.clone();
2422

2523
// Time to search for module in any place:
26-
let filepath = find_source(vm, module)
27-
.map_err(|e| vm.new_exception(import_error.clone(), format!("Error: {:?}", e)))?;
24+
let filepath =
25+
find_source(vm, module).map_err(|e| vm.new_exception(notfound_error.clone(), e))?;
2826
let source = parser::read_file(filepath.as_path())
29-
.map_err(|e| vm.new_exception(import_error.clone(), format!("Error: {:?}", e)))?;
27+
.map_err(|e| vm.new_exception(import_error.clone(), e))?;
3028

3129
let code_obj = match compile::compile(
3230
vm,
@@ -38,9 +36,7 @@ fn import_uncached_module(vm: &mut VirtualMachine, module: &str) -> PyResult {
3836
debug!("Code object: {:?}", bytecode);
3937
bytecode
4038
}
41-
Err(value) => {
42-
panic!("Error: {}", value);
43-
}
39+
Err(value) => return Err(value),
4440
};
4541

4642
let builtins = vm.get_builtin_scope();
@@ -75,7 +71,7 @@ pub fn import(vm: &mut VirtualMachine, module_name: &str, symbol: &Option<String
7571
Ok(obj)
7672
}
7773

78-
fn find_source(vm: &VirtualMachine, name: &str) -> io::Result<PathBuf> {
74+
fn find_source(vm: &VirtualMachine, name: &str) -> Result<PathBuf, String> {
7975
let sys_path = vm.sys_module.get_item("path").unwrap();
8076
let mut paths: Vec<PathBuf> = match sys_path.borrow().kind {
8177
PyObjectKind::List { ref elements } => elements
@@ -112,9 +108,6 @@ fn find_source(vm: &VirtualMachine, name: &str) -> io::Result<PathBuf> {
112108

113109
match filepaths.iter().filter(|p| p.exists()).next() {
114110
Some(path) => Ok(path.to_path_buf()),
115-
None => Err(io::Error::new(
116-
NotFound,
117-
format!("Module ({}) could not be found.", name),
118-
)),
111+
None => Err(format!("No module named '{}'", name)),
119112
}
120113
}

vm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub mod eval;
2020
mod exceptions;
2121
mod frame;
2222
mod import;
23-
mod obj;
23+
pub mod obj;
2424
pub mod pyobject;
2525
pub mod stdlib;
2626
mod sysmodule;

0 commit comments

Comments
 (0)