Skip to content

Commit f325ef1

Browse files
Merge pull request RustPython#240 from coolreader18/json-error
Have the json ser/de functions throw an exception instead of panicking
2 parents 978e7ea + 8fee5a8 commit f325ef1

File tree

2 files changed

+57
-83
lines changed

2 files changed

+57
-83
lines changed

vm/src/exceptions.rs

Lines changed: 16 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -107,90 +107,37 @@ impl ExceptionZoo {
107107
let base_exception_type =
108108
create_type("BaseException", &type_type, &object_type, &dict_type);
109109

110-
let exception_type = create_type(
111-
&String::from("Exception"),
112-
&type_type,
113-
&base_exception_type,
114-
&dict_type,
115-
);
116-
let syntax_error = create_type(
117-
&String::from("SyntaxError"),
118-
&type_type,
119-
&exception_type,
120-
&dict_type,
121-
);
122-
let assertion_error = create_type(
123-
&String::from("AssertionError"),
124-
&type_type,
125-
&exception_type,
126-
&dict_type,
127-
);
110+
let exception_type = create_type("Exception", &type_type, &base_exception_type, &dict_type);
111+
let syntax_error = create_type("SyntaxError", &type_type, &exception_type, &dict_type);
112+
let assertion_error =
113+
create_type("AssertionError", &type_type, &exception_type, &dict_type);
128114
let attribute_error = create_type(
129-
&String::from("AttributeError"),
115+
"AttributeError",
130116
&type_type,
131117
&exception_type.clone(),
132118
&dict_type,
133119
);
134120
let index_error = create_type(
135-
&String::from("IndexError"),
121+
"IndexError",
136122
&type_type,
137123
&exception_type.clone(),
138124
&dict_type,
139125
);
140-
let key_error = create_type(
141-
&String::from("KeyError"),
142-
&type_type,
143-
&exception_type.clone(),
144-
&dict_type,
145-
);
146-
let name_error = create_type(
147-
&String::from("NameError"),
148-
&type_type,
149-
&exception_type.clone(),
150-
&dict_type,
151-
);
152-
let runtime_error = create_type(
153-
&String::from("RuntimeError"),
154-
&type_type,
155-
&exception_type,
156-
&dict_type,
157-
);
126+
let key_error = create_type("KeyError", &type_type, &exception_type.clone(), &dict_type);
127+
let name_error = create_type("NameError", &type_type, &exception_type.clone(), &dict_type);
128+
let runtime_error = create_type("RuntimeError", &type_type, &exception_type, &dict_type);
158129
let not_implemented_error = create_type(
159-
&String::from("NotImplementedError"),
130+
"NotImplementedError",
160131
&type_type,
161132
&runtime_error,
162133
&dict_type,
163134
);
164-
let stop_iteration = create_type(
165-
&String::from("StopIteration"),
166-
&type_type,
167-
&exception_type,
168-
&dict_type,
169-
);
170-
let type_error = create_type(
171-
&String::from("TypeError"),
172-
&type_type,
173-
&exception_type,
174-
&dict_type,
175-
);
176-
let value_error = create_type(
177-
&String::from("ValueError"),
178-
&type_type,
179-
&exception_type,
180-
&dict_type,
181-
);
182-
let import_error = create_type(
183-
&String::from("ImportError"),
184-
&type_type,
185-
&exception_type,
186-
&dict_type,
187-
);
188-
let module_not_found_error = create_type(
189-
&String::from("ModuleNotFoundError"),
190-
&type_type,
191-
&import_error,
192-
&dict_type,
193-
);
135+
let stop_iteration = create_type("StopIteration", &type_type, &exception_type, &dict_type);
136+
let type_error = create_type("TypeError", &type_type, &exception_type, &dict_type);
137+
let value_error = create_type("ValueError", &type_type, &exception_type, &dict_type);
138+
let import_error = create_type("ImportError", &type_type, &exception_type, &dict_type);
139+
let module_not_found_error =
140+
create_type("ModuleNotFoundError", &type_type, &import_error, &dict_type);
194141

195142
ExceptionZoo {
196143
base_exception_type: base_exception_type,

vm/src/stdlib/json.rs

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use serde_json;
77

88
use super::super::obj::{objbool, objdict, objfloat, objint, objsequence, objstr, objtype};
99
use super::super::pyobject::{
10-
PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
10+
create_type, DictProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult,
11+
TypeProtocol,
1112
};
1213
use super::super::VirtualMachine;
1314
use num_bigint::ToBigInt;
@@ -69,10 +70,10 @@ impl<'s> serde::Serialize for PyObjectSerializer<'s> {
6970
} else if let PyObjectKind::None = self.pyobject.borrow().kind {
7071
serializer.serialize_none()
7172
} else {
72-
unimplemented!(
73+
Err(serde::ser::Error::custom(format!(
7374
"Object of type '{:?}' is not serializable",
7475
self.pyobject.typ()
75-
);
76+
)))
7677
}
7778
}
7879
}
@@ -190,31 +191,57 @@ impl<'de> serde::de::DeserializeSeed<'de> for PyObjectDeserializer<'de> {
190191
fn dumps(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
191192
// TODO: Implement non-trivial serialisation case
192193
arg_check!(vm, args, required = [(obj, None)]);
193-
// TODO: Raise an exception for serialisation errors
194-
let serializer = PyObjectSerializer {
195-
pyobject: obj,
196-
ctx: &vm.ctx,
194+
let res = {
195+
let serializer = PyObjectSerializer {
196+
pyobject: obj,
197+
ctx: &vm.ctx,
198+
};
199+
serde_json::to_string(&serializer)
197200
};
198-
let string = serde_json::to_string(&serializer).unwrap();
201+
let string = res.map_err(|err| vm.new_type_error(format!("{}", err)))?;
199202
Ok(vm.context().new_str(string))
200203
}
201204

202205
fn loads(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
203206
// TODO: Implement non-trivial deserialisation case
204207
arg_check!(vm, args, required = [(string, Some(vm.ctx.str_type()))]);
205-
// TODO: Raise an exception for deserialisation errors
206-
let de = PyObjectDeserializer { ctx: &vm.ctx };
207-
// TODO: Support deserializing string sub-classes
208-
Ok(de
209-
.deserialize(&mut serde_json::Deserializer::from_str(&objstr::get_value(
208+
let res = {
209+
let de = PyObjectDeserializer { ctx: &vm.ctx };
210+
// TODO: Support deserializing string sub-classes
211+
de.deserialize(&mut serde_json::Deserializer::from_str(&objstr::get_value(
210212
&string,
211213
)))
212-
.unwrap())
214+
};
215+
216+
res.map_err(|err| {
217+
let json_decode_error = vm
218+
.sys_module
219+
.get_item("modules")
220+
.unwrap()
221+
.get_item("json")
222+
.unwrap()
223+
.get_item("JSONDecodeError")
224+
.unwrap();
225+
let exc = vm.new_exception(json_decode_error, format!("{}", err));
226+
vm.ctx
227+
.set_item(&exc, "lineno", vm.ctx.new_int(err.line().into()));
228+
vm.ctx
229+
.set_item(&exc, "colno", vm.ctx.new_int(err.column().into()));
230+
exc
231+
})
213232
}
214233

215234
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
216235
let json_mod = ctx.new_module(&"json".to_string(), ctx.new_scope(None));
217236
ctx.set_attr(&json_mod, "dumps", ctx.new_rustfunc(dumps));
218237
ctx.set_attr(&json_mod, "loads", ctx.new_rustfunc(loads));
238+
// TODO: Make this a proper type with a constructor
239+
let json_decode_error = create_type(
240+
"JSONDecodeError",
241+
&ctx.type_type,
242+
&ctx.exceptions.exception_type,
243+
&ctx.dict_type,
244+
);
245+
ctx.set_attr(&json_mod, "JSONDecodeError", json_decode_error);
219246
json_mod
220247
}

0 commit comments

Comments
 (0)