Skip to content

Commit 6a64af1

Browse files
authored
Merge pull request RustPython#5213 from youknowone/vm-finalize
Add vm.finalize and enter/run docs
2 parents 6eed8f4 + 3514126 commit 6a64af1

File tree

1 file changed

+54
-5
lines changed

1 file changed

+54
-5
lines changed

vm/src/vm/interpreter.rs

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::{setting::Settings, thread, Context, VirtualMachine};
22
use crate::{
33
stdlib::{atexit, sys},
4+
vm::PyBaseExceptionRef,
45
PyResult,
56
};
67
use std::sync::atomic::Ordering;
@@ -59,26 +60,74 @@ impl Interpreter {
5960
Self { vm }
6061
}
6162

63+
/// Run a function with the main virtual machine and return a PyResult of the result.
64+
///
65+
/// To enter vm context multiple times or to avoid buffer/exception management, this function is preferred.
66+
/// `enter` is lightweight and it returns a python object in PyResult.
67+
/// You can stop or continue the execution multiple times by calling `enter`.
68+
///
69+
/// To finalize the vm once all desired `enter`s are called, calling `finalize` will be helpful.
70+
///
71+
/// See also [`run`] for managed way to run the interpreter.
6272
pub fn enter<F, R>(&self, f: F) -> R
6373
where
6474
F: FnOnce(&VirtualMachine) -> R,
6575
{
6676
thread::enter_vm(&self.vm, || f(&self.vm))
6777
}
6878

79+
/// Run [`enter`] and call `expect_pyresult` for the result.
80+
///
81+
/// This function is useful when you want to expect a result from the function,
82+
/// but also print useful panic information when exception raised.
83+
///
84+
/// See [`enter`] for more information.
85+
/// See [`expect_pyresult`] for more information.
86+
pub fn enter_and_expect<F, R>(&self, f: F, msg: &str) -> R
87+
where
88+
F: FnOnce(&VirtualMachine) -> PyResult<R>,
89+
{
90+
self.enter(|vm| {
91+
let result = f(vm);
92+
vm.expect_pyresult(result, msg)
93+
})
94+
}
95+
96+
/// Run a function with the main virtual machine and return exit code.
97+
///
98+
/// To enter vm context only once and safely terminate the vm, this function is preferred.
99+
/// Unlike [`enter`], `run` calls finalize and returns exit code.
100+
/// You will not be able to obtain Python exception in this way.
101+
///
102+
/// See [`finalize`] for the finalization steps.
103+
/// See also [`enter`] for pure function call to obtain Python exception.
69104
pub fn run<F, R>(self, f: F) -> u8
70105
where
71106
F: FnOnce(&VirtualMachine) -> PyResult<R>,
72107
{
108+
let res = self.enter(|vm| f(vm));
109+
self.finalize(res.err())
110+
}
111+
112+
/// Finalize vm and turns an exception to exit code.
113+
///
114+
/// Finalization steps including 4 steps:
115+
/// 1. Flush stdout and stderr.
116+
/// 1. Handle exit exception and turn it to exit code.
117+
/// 1. Run atexit exit functions.
118+
/// 1. Mark vm as finalized.
119+
///
120+
/// Note that calling `finalize` is not necessary by purpose though.
121+
pub fn finalize(self, exc: Option<PyBaseExceptionRef>) -> u8 {
73122
self.enter(|vm| {
74-
let res = f(vm);
75123
flush_std(vm);
76124

77125
// See if any exception leaked out:
78-
let exit_code = res
79-
.map(|_| 0)
80-
.map_err(|exc| vm.handle_exit_exception(exc))
81-
.unwrap_or_else(|code| code);
126+
let exit_code = if let Some(exc) = exc {
127+
vm.handle_exit_exception(exc)
128+
} else {
129+
0
130+
};
82131

83132
atexit::_run_exitfuncs(vm);
84133

0 commit comments

Comments
 (0)