use pyo3::prelude::*;
use pyo3::types::{PyDict, PyList};
pub(crate) fn get_or_load_module<'py>(py: Python<'py>, file: &str) -> PyResult<Bound<'py, PyAny>> {
let module_name = format!(
"deq_python_module_{}",
file.replace(|c: char| !c.is_ascii_alphanumeric(), "_")
);
let sys = py.import("sys")?;
let modules = sys.getattr("modules")?;
if let Ok(existing) = modules.get_item(&module_name) {
return Ok(existing);
}
let util = py.import("importlib.util")?;
let spec = util.call_method1("spec_from_file_location", (&module_name, file))?;
let module = util.call_method1("module_from_spec", (spec.clone(),))?;
spec.getattr("loader")?.call_method1("exec_module", (module.clone(),))?;
modules.set_item(&module_name, module.clone())?;
Ok(module)
}
pub(crate) fn get_or_load_module_from_source<'py>(
py: Python<'py>,
virtual_filename: &str,
source: &str,
) -> PyResult<Bound<'py, PyAny>> {
let module_name = format!(
"deq_python_module_{}",
virtual_filename.replace(|c: char| !c.is_ascii_alphanumeric(), "_")
);
let sys = py.import("sys")?;
let modules = sys.getattr("modules")?;
if let Ok(existing) = modules.get_item(&module_name) {
return Ok(existing);
}
let types = py.import("types")?;
let module = types.getattr("ModuleType")?.call1((&module_name,))?;
module.setattr("__file__", virtual_filename)?;
let builtins = py.import("builtins")?;
let code = builtins.getattr("compile")?.call1((source, virtual_filename, "exec"))?;
let dict = module.getattr("__dict__")?;
builtins.getattr("exec")?.call1((code, dict))?;
modules.set_item(&module_name, module.clone())?;
Ok(module)
}
pub(crate) fn json_value_to_py<'py>(py: Python<'py>, value: &serde_json::Value) -> PyResult<Bound<'py, PyAny>> {
match value {
serde_json::Value::Null => Ok(py.None().into_bound(py)),
serde_json::Value::Bool(b) => Ok(pyo3::types::PyBool::new(py, *b).to_owned().into_any()),
serde_json::Value::Number(n) => {
if let Some(i) = n.as_i64() {
Ok(i.into_pyobject(py)?.into_any())
} else if let Some(u) = n.as_u64() {
Ok(u.into_pyobject(py)?.into_any())
} else if let Some(f) = n.as_f64() {
Ok(f.into_pyobject(py)?.into_any())
} else {
Ok(n.to_string().into_pyobject(py)?.into_any())
}
}
serde_json::Value::String(s) => Ok(s.into_pyobject(py)?.into_any()),
serde_json::Value::Array(items) => {
let list = PyList::empty(py);
for item in items {
list.append(json_value_to_py(py, item)?)?;
}
Ok(list.into_any())
}
serde_json::Value::Object(map) => {
let dict = PyDict::new(py);
for (key, val) in map {
dict.set_item(key, json_value_to_py(py, val)?)?;
}
Ok(dict.into_any())
}
}
}