1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
use std::{str::FromStr, fs};
use pyo3::{prelude::*, types::PyDict};
/// Represents a context for executing Python code.
pub struct PyContext {
/// Stores Python variables and their values.
pub variables: PyVar
}
impl Default for PyContext {
/// Constructs a new `PyContext` with default values.
fn default() -> Self {
PyContext { variables: Default::default() }
}
}
/// Represents Python variables and their values.
pub struct PyVar {
/// Stores local Python variables.
pub locals: Py<PyDict>
}
impl Default for PyVar {
/// Constructs a new `PyVar` with default values.
fn default() -> Self {
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
Self { locals: PyDict::new(py).into() }
})
}
}
impl PyContext {
/// Constructs a new empty `PyContext`.
pub fn new() -> PyContext {
PyContext { ..Default::default() }
}
/// Executes Python code provided as input.
///
/// # Arguments
///
/// * `input` - A string containing the Python code to execute.
pub fn run(&self, input: &str) {
let _ = self.execute_python(Some(&self.variables), &input);
}
/// Executes Python code from a file specified by `file`.
///
/// # Arguments
///
/// * `file` - The path to the file containing Python code.
///
/// # Errors
///
/// Returns an error if there is an issue reading the file or executing Python code.
pub fn run_file(&self, file: &str) -> Result<(), PyErr> {
let contents = fs::read_to_string(&file)?;
self.execute_python(Some(&self.variables), &contents)
}
/// Retrieves the value of a Python variable identified by `input`.
///
/// # Arguments
///
/// * `input` - The name of the Python variable to retrieve.
///
/// # Errors
///
/// Returns an error if parsing of the variable value fails.
pub fn get<T: FromStr>(&self, input: &str) -> Result<T, <T as FromStr>::Err> {
pyo3::prepare_freethreaded_python();
let out = Python::with_gil(|py| {
let locals: &PyDict = self._define(Some(&self.variables), &py);
let ret = locals.get_item(&input).unwrap().unwrap();
format!("{}",ret)
});
out.parse::<T>()
}
fn execute_python(&self, py_vars: Option<&PyVar>, input: &str) -> PyResult<()> {
pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
let locals: &PyDict = self._define(py_vars, &py);
let _ = py.run(&input, None, Some(locals)).unwrap();
});
Ok(())
}
/// Defines Python variables for execution.
///
/// # Arguments
///
/// * `py_vars` - Optional Python variables and their values.
/// * `py` - A Python interpreter.
///
/// # Returns
///
/// A reference to a Python dictionary containing the defined variables.
fn _define<'a>(&self, py_vars: Option<&'a PyVar>, py: &Python<'a>) -> &'a PyDict {
if py_vars.is_none() {
PyDict::new(*py).into()
} else {
py_vars.unwrap().locals.as_ref(*py)
}
}
}