Skip to content

Commit d975c51

Browse files
authored
implement more warnings (RustPython#5077)
1 parent 23bf5c4 commit d975c51

File tree

3 files changed

+91
-17
lines changed

3 files changed

+91
-17
lines changed

.cspell.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@
171171
"scproxy",
172172
"setattro",
173173
"setcomp",
174+
"showwarnmsg",
175+
"warnmsg",
174176
"stacklevel",
175177
"subclasscheck",
176178
"subclasshook",

vm/src/vm/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ declare_const_name! {
222222
// common names
223223
_attributes,
224224
_fields,
225+
_showwarnmsg,
225226
decode,
226227
encode,
227228
keys,
@@ -232,6 +233,7 @@ declare_const_name! {
232233
copy,
233234
flush,
234235
close,
236+
WarningMessage,
235237
}
236238

237239
// Basic objects:

vm/src/warn.rs

Lines changed: 87 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use crate::{
2-
builtins::{PyDict, PyDictRef, PyListRef, PyStrRef, PyTuple, PyTupleRef, PyType, PyTypeRef},
2+
builtins::{
3+
PyDict, PyDictRef, PyListRef, PyStr, PyStrInterned, PyStrRef, PyTuple, PyTupleRef,
4+
PyTypeRef,
5+
},
36
convert::{IntoObject, TryFromObject},
47
types::PyComparisonOp,
58
AsObject, Context, Py, PyObjectRef, PyResult, VirtualMachine,
@@ -48,19 +51,26 @@ fn check_matched(obj: &PyObjectRef, arg: &PyObjectRef, vm: &VirtualMachine) -> P
4851
Ok(result.is_ok())
4952
}
5053

51-
pub fn py_warn(
52-
category: &Py<PyType>,
53-
message: String,
54-
stack_level: usize,
54+
fn get_warnings_attr(
5555
vm: &VirtualMachine,
56-
) -> PyResult<()> {
57-
// TODO: use rust warnings module
58-
if let Ok(module) = vm.import("warnings", None, 0) {
59-
if let Ok(func) = module.get_attr("warn", vm) {
60-
let _ = func.call((message, category.to_owned(), stack_level), vm);
56+
attr_name: &'static PyStrInterned,
57+
try_import: bool,
58+
) -> PyResult<Option<PyObjectRef>> {
59+
let module = if try_import
60+
&& !vm
61+
.state
62+
.finalizing
63+
.load(std::sync::atomic::Ordering::SeqCst)
64+
{
65+
match vm.import("warnings", None, 0) {
66+
Ok(module) => module,
67+
Err(_) => return Ok(None),
6168
}
62-
}
63-
Ok(())
69+
} else {
70+
// TODO: finalizing support
71+
return Ok(None);
72+
};
73+
Ok(Some(module.get_attr(attr_name, vm)?))
6474
}
6575

6676
pub fn warn(
@@ -192,7 +202,7 @@ fn already_warned(
192202
Ok(true)
193203
}
194204

195-
fn normalize_module(filename: PyStrRef, vm: &VirtualMachine) -> Option<PyObjectRef> {
205+
fn normalize_module(filename: &Py<PyStr>, vm: &VirtualMachine) -> Option<PyObjectRef> {
196206
let obj = match filename.char_len() {
197207
0 => vm.new_pyobj("<unknown>"),
198208
len if len >= 3 && filename.as_str().ends_with(".py") => {
@@ -211,16 +221,16 @@ fn warn_explicit(
211221
lineno: usize,
212222
module: Option<PyObjectRef>,
213223
registry: PyObjectRef,
214-
_source_line: Option<PyObjectRef>,
215-
_source: Option<PyObjectRef>,
224+
source_line: Option<PyObjectRef>,
225+
source: Option<PyObjectRef>,
216226
vm: &VirtualMachine,
217227
) -> PyResult<()> {
218228
let registry: PyObjectRef = registry
219229
.try_into_value(vm)
220230
.map_err(|_| vm.new_type_error("'registry' must be a dict or None".to_owned()))?;
221231

222232
// Normalize module.
223-
let module = match module.or_else(|| normalize_module(filename, vm)) {
233+
let module = match module.or_else(|| normalize_module(&filename, vm)) {
224234
Some(module) => module,
225235
None => return Ok(()),
226236
};
@@ -280,8 +290,68 @@ fn warn_explicit(
280290
return Ok(());
281291
}
282292

293+
call_show_warning(
294+
// t_state,
295+
category,
296+
message,
297+
filename,
298+
lineno, // lineno_obj,
299+
source_line,
300+
source,
301+
vm,
302+
)
303+
}
304+
305+
fn call_show_warning(
306+
category: PyTypeRef,
307+
message: PyStrRef,
308+
filename: PyStrRef,
309+
lineno: usize,
310+
source_line: Option<PyObjectRef>,
311+
source: Option<PyObjectRef>,
312+
vm: &VirtualMachine,
313+
) -> PyResult<()> {
314+
let Some(show_fn) =
315+
get_warnings_attr(vm, identifier!(&vm.ctx, _showwarnmsg), source.is_some())?
316+
else {
317+
return show_warning(filename, lineno, message, category, source_line, vm);
318+
};
319+
if !show_fn.is_callable() {
320+
return Err(
321+
vm.new_type_error("warnings._showwarnmsg() must be set to a callable".to_owned())
322+
);
323+
}
324+
let Some(warnmsg_cls) = get_warnings_attr(vm, identifier!(&vm.ctx, WarningMessage), false)?
325+
else {
326+
return Err(vm.new_type_error("unable to get warnings.WarningMessage".to_owned()));
327+
};
328+
329+
let msg = warnmsg_cls.call(
330+
vec![
331+
message.into(),
332+
category.into(),
333+
filename.into(),
334+
vm.new_pyobj(lineno),
335+
vm.ctx.none(),
336+
vm.ctx.none(),
337+
vm.unwrap_or_none(source),
338+
],
339+
vm,
340+
)?;
341+
show_fn.call((msg,), vm)?;
342+
Ok(())
343+
}
344+
345+
fn show_warning(
346+
_filename: PyStrRef,
347+
_lineno: usize,
348+
text: PyStrRef,
349+
category: PyTypeRef,
350+
_source_line: Option<PyObjectRef>,
351+
vm: &VirtualMachine,
352+
) -> PyResult<()> {
283353
let stderr = crate::stdlib::sys::PyStderr(vm);
284-
writeln!(stderr, "{}: {}", category.name(), text,);
354+
writeln!(stderr, "{}: {}", category.name(), text.as_str(),);
285355
Ok(())
286356
}
287357

0 commit comments

Comments
 (0)