Skip to content

Commit 9c2847a

Browse files
authored
Merge pull request #3736 from youknowone/warning
warning module start
2 parents ade5549 + 5a80fc3 commit 9c2847a

File tree

3 files changed

+127
-23
lines changed

3 files changed

+127
-23
lines changed

vm/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub mod types;
7676
pub mod utils;
7777
pub mod version;
7878
pub mod vm;
79+
pub mod warn;
7980

8081
pub use self::convert::{TryFromBorrowedObject, TryFromObject};
8182
pub use self::object::{

vm/src/stdlib/warnings.rs

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ mod _warnings {
2222
use crate::{
2323
builtins::{PyStrRef, PyTypeRef},
2424
function::OptionalArg,
25-
stdlib::sys::PyStderr,
26-
AsObject, PyResult, VirtualMachine,
25+
PyResult, VirtualMachine,
2726
};
2827

2928
#[derive(FromArgs)]
@@ -38,27 +37,13 @@ mod _warnings {
3837

3938
#[pyfunction]
4039
fn warn(args: WarnArgs, vm: &VirtualMachine) -> PyResult<()> {
41-
// TODO: Implement correctly
4240
let level = args.stacklevel.unwrap_or(1);
43-
let category = if let OptionalArg::Present(category) = args.category {
44-
if !category.fast_issubclass(vm.ctx.exceptions.warning) {
45-
return Err(vm.new_type_error(format!(
46-
"category must be a Warning subclass, not '{}'",
47-
category.class().name()
48-
)));
49-
}
50-
category
51-
} else {
52-
vm.ctx.exceptions.user_warning.to_owned()
53-
};
54-
let stderr = PyStderr(vm);
55-
writeln!(
56-
stderr,
57-
"level:{}: {}: {}",
58-
level,
59-
category.name(),
60-
args.message
61-
);
62-
Ok(())
41+
crate::warn::warn(
42+
args.message,
43+
args.category.into_option(),
44+
level as isize,
45+
None,
46+
vm,
47+
)
6348
}
6449
}

vm/src/warn.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use crate::{
2+
builtins::{PyDict, PyStrRef, PyType, PyTypeRef},
3+
AsObject, Py, PyObjectRef, PyResult, VirtualMachine,
4+
};
5+
6+
pub fn py_warn(
7+
category: &Py<PyType>,
8+
message: String,
9+
stack_level: usize,
10+
vm: &VirtualMachine,
11+
) -> PyResult<()> {
12+
// TODO: use rust warnings module
13+
if let Ok(module) = vm.import("warnings", None, 0) {
14+
if let Ok(func) = module.get_attr("warn", vm) {
15+
let _ = vm.invoke(&func, (message, category.to_owned(), stack_level));
16+
}
17+
}
18+
Ok(())
19+
}
20+
21+
pub fn warn(
22+
message: PyStrRef,
23+
category: Option<PyTypeRef>,
24+
stack_level: isize,
25+
source: Option<PyObjectRef>,
26+
vm: &VirtualMachine,
27+
) -> PyResult<()> {
28+
let (filename, lineno, module, registry) = setup_context(stack_level, vm)?;
29+
warn_explicit(
30+
category, message, filename, lineno, module, registry, None, source, vm,
31+
)
32+
}
33+
34+
#[allow(clippy::too_many_arguments)]
35+
fn warn_explicit(
36+
category: Option<PyTypeRef>,
37+
message: PyStrRef,
38+
_filename: PyStrRef,
39+
_lineno: usize,
40+
_module: PyObjectRef,
41+
_registry: PyObjectRef,
42+
_source_line: Option<PyObjectRef>,
43+
_source: Option<PyObjectRef>,
44+
vm: &VirtualMachine,
45+
) -> PyResult<()> {
46+
// TODO: Implement correctly
47+
let category = if let Some(category) = category {
48+
if !category.fast_issubclass(vm.ctx.exceptions.warning) {
49+
return Err(vm.new_type_error(format!(
50+
"category must be a Warning subclass, not '{}'",
51+
category.class().name()
52+
)));
53+
}
54+
category
55+
} else {
56+
vm.ctx.exceptions.user_warning.to_owned()
57+
};
58+
let stderr = crate::stdlib::sys::PyStderr(vm);
59+
writeln!(stderr, "{}: {}", category.name(), message.as_str(),);
60+
Ok(())
61+
}
62+
63+
// filename, module, and registry are new refs, globals is borrowed
64+
// Returns 0 on error (no new refs), 1 on success
65+
fn setup_context(
66+
_stack_level: isize,
67+
vm: &VirtualMachine,
68+
) -> PyResult<
69+
// filename, lineno, module, registry
70+
(PyStrRef, usize, PyObjectRef, PyObjectRef),
71+
> {
72+
let __warningregistry__ = "__warningregistry__";
73+
let __name__ = "__name__";
74+
75+
// Setup globals, filename and lineno.
76+
let frame = vm.current_frame();
77+
78+
// PyThreadState *tstate = _PyThreadState_GET();
79+
// PyFrameObject *f = PyThreadState_GetFrame(tstate);
80+
// // Stack level comparisons to Python code is off by one as there is no
81+
// // warnings-related stack level to avoid.
82+
// if (stack_level <= 0 || is_internal_frame(f)) {
83+
// while (--stack_level > 0 && f != NULL) {
84+
// PyFrameObject *back = PyFrame_GetBack(f);
85+
// Py_DECREF(f);
86+
// f = back;
87+
// }
88+
// }
89+
// else {
90+
// while (--stack_level > 0 && f != NULL) {
91+
// f = next_external_frame(f);
92+
// }
93+
// }
94+
95+
let (globals, filename, lineno) = if let Some(f) = frame {
96+
// TODO:
97+
let lineno = 1;
98+
// *lineno = PyFrame_GetLineNumber(f);
99+
// *filename = code->co_filename;
100+
(f.globals.clone(), f.code.source_path, lineno)
101+
} else {
102+
(vm.current_globals().clone(), vm.ctx.intern_str("sys"), 1)
103+
};
104+
105+
let registry = if let Ok(registry) = globals.get_item(__warningregistry__, vm) {
106+
registry
107+
} else {
108+
let registry = PyDict::new_ref(&vm.ctx);
109+
globals.set_item(__warningregistry__, registry.clone().into(), vm)?;
110+
registry.into()
111+
};
112+
113+
// Setup module.
114+
let module = globals
115+
.get_item(__name__, vm)
116+
.unwrap_or_else(|_| vm.new_pyobj("<string>"));
117+
Ok((filename.to_owned(), lineno, module, registry))
118+
}

0 commit comments

Comments
 (0)