rustpython_vm/stdlib/
_warnings.rs1pub(crate) use _warnings::module_def;
2
3use crate::{Py, PyResult, VirtualMachine, builtins::PyType};
4
5pub fn warn(
6 category: &Py<PyType>,
7 message: String,
8 stack_level: usize,
9 vm: &VirtualMachine,
10) -> PyResult<()> {
11 crate::warn::warn(
12 vm.new_pyobj(message),
13 Some(category.to_owned()),
14 isize::try_from(stack_level).unwrap_or(isize::MAX),
15 None,
16 vm,
17 )
18}
19
20#[pymodule]
21mod _warnings {
22 use crate::{
23 AsObject, PyObjectRef, PyResult, VirtualMachine,
24 builtins::{PyDictRef, PyListRef, PyStrRef, PyTupleRef, PyTypeRef},
25 convert::TryFromObject,
26 function::OptionalArg,
27 };
28
29 #[pyattr]
30 fn filters(vm: &VirtualMachine) -> PyListRef {
31 vm.state.warnings.filters.clone()
32 }
33
34 #[pyattr]
35 fn _defaultaction(vm: &VirtualMachine) -> PyStrRef {
36 vm.state.warnings.default_action.clone()
37 }
38
39 #[pyattr]
40 fn _onceregistry(vm: &VirtualMachine) -> PyDictRef {
41 vm.state.warnings.once_registry.clone()
42 }
43
44 #[pyattr]
45 fn _warnings_context(vm: &VirtualMachine) -> PyObjectRef {
46 vm.state
47 .warnings
48 .context_var
49 .get_or_init(|| {
50 if let Ok(contextvars) = vm.import("_contextvars", 0)
55 && let Ok(cv_cls) = contextvars.get_attr("ContextVar", vm)
56 && let Ok(cv) = cv_cls.call(("_warnings_context",), vm)
57 {
58 cv
59 } else {
60 vm.ctx.none()
61 }
62 })
63 .clone()
64 }
65
66 #[pyfunction]
67 fn _acquire_lock(vm: &VirtualMachine) {
68 vm.state.warnings.acquire_lock();
69 }
70
71 #[pyfunction]
72 fn _release_lock(vm: &VirtualMachine) -> PyResult<()> {
73 if !vm.state.warnings.release_lock() {
74 return Err(vm.new_runtime_error("cannot release un-acquired lock"));
75 }
76 Ok(())
77 }
78
79 #[pyfunction]
80 fn _filters_mutated_lock_held(vm: &VirtualMachine) {
81 vm.state.warnings.filters_mutated();
82 }
83
84 #[derive(FromArgs)]
85 struct WarnArgs {
86 #[pyarg(positional)]
87 message: PyObjectRef,
88 #[pyarg(any, optional)]
89 category: OptionalArg<PyObjectRef>,
90 #[pyarg(any, optional)]
91 stacklevel: OptionalArg<i32>,
92 #[pyarg(named, optional)]
93 source: OptionalArg<PyObjectRef>,
94 #[pyarg(named, optional)]
95 skip_file_prefixes: OptionalArg<PyTupleRef>,
96 }
97
98 fn get_category(
100 message: &PyObjectRef,
101 category: Option<PyObjectRef>,
102 vm: &VirtualMachine,
103 ) -> PyResult<Option<PyTypeRef>> {
104 let cat_obj = match category {
105 Some(c) if !vm.is_none(&c) => c,
106 _ => {
107 if message.fast_isinstance(vm.ctx.exceptions.warning) {
108 return Ok(Some(message.class().to_owned()));
109 } else {
110 return Ok(None); }
112 }
113 };
114
115 let cat = PyTypeRef::try_from_object(vm, cat_obj.clone()).map_err(|_| {
116 vm.new_type_error(format!(
117 "category must be a Warning subclass, not '{}'",
118 cat_obj.class().name()
119 ))
120 })?;
121
122 if !cat.fast_issubclass(vm.ctx.exceptions.warning) {
123 return Err(vm.new_type_error(format!(
124 "category must be a Warning subclass, not '{}'",
125 cat.class().name()
126 )));
127 }
128
129 Ok(Some(cat))
130 }
131
132 #[pyfunction]
133 fn warn(args: WarnArgs, vm: &VirtualMachine) -> PyResult<()> {
134 let level = args.stacklevel.unwrap_or(1) as isize;
135
136 let category = get_category(&args.message, args.category.into_option(), vm)?;
137
138 let skip_prefixes = args.skip_file_prefixes.into_option();
140 if let Some(ref prefixes) = skip_prefixes {
141 for item in prefixes.iter() {
142 if !item.class().is(vm.ctx.types.str_type) {
143 return Err(vm.new_type_error("skip_file_prefixes must be a tuple of strs"));
144 }
145 }
146 }
147
148 crate::warn::warn_with_skip(
149 args.message,
150 category,
151 level,
152 args.source.into_option(),
153 skip_prefixes,
154 vm,
155 )
156 }
157
158 #[derive(FromArgs)]
159 struct WarnExplicitArgs {
160 #[pyarg(positional)]
161 message: PyObjectRef,
162 #[pyarg(positional)]
163 category: PyObjectRef,
164 #[pyarg(positional)]
165 filename: PyStrRef,
166 #[pyarg(positional)]
167 lineno: usize,
168 #[pyarg(any, optional)]
169 module: OptionalArg<PyObjectRef>,
170 #[pyarg(any, optional)]
171 registry: OptionalArg<PyObjectRef>,
172 #[pyarg(any, optional)]
173 module_globals: OptionalArg<PyObjectRef>,
174 #[pyarg(named, optional)]
175 source: OptionalArg<PyObjectRef>,
176 }
177
178 #[pyfunction]
179 fn warn_explicit(args: WarnExplicitArgs, vm: &VirtualMachine) -> PyResult<()> {
180 let registry = args.registry.into_option().unwrap_or_else(|| vm.ctx.none());
181
182 let module = args.module.into_option();
183
184 if let Some(ref mg) = args.module_globals.into_option()
186 && !vm.is_none(mg)
187 && !mg.class().is(vm.ctx.types.dict_type)
188 {
189 return Err(vm.new_type_error("module_globals must be a dict"));
190 }
191
192 let category = if vm.is_none(&args.category) {
193 None
194 } else {
195 Some(
196 PyTypeRef::try_from_object(vm, args.category)
197 .map_err(|_| vm.new_type_error("category must be a Warning subclass"))?,
198 )
199 };
200
201 crate::warn::warn_explicit(
202 category,
203 args.message,
204 args.filename,
205 args.lineno,
206 module,
207 registry,
208 None, args.source.into_option(),
210 vm,
211 )
212 }
213}