amberjs 1.17.0

JavaScript/TypeScript runtime built with Rust and V8
Documentation
// Python Runtime Integration
// Provides seamless integration between Amber and Python

use anyhow::{anyhow, Result};
use pyo3::types::{PyDict, PyModule};
use pyo3::{pyfunction, wrap_pyfunction, PyObject, PyResult, Python};
use std::sync::Arc;
use tokio::sync::RwLock;

/// Python GIL (Global Interpreter Lock) manager
#[derive(Debug)]
pub struct PythonGIL {
    _python: Python<'static>,
}
/// Python runtime engine
#[derive(Debug)]
pub struct PythonRuntime {
    gil: Arc<PythonGIL>,
    amber_api: Arc<AmberAPI>,
    context_pool: Arc<RwLock<Vec<PythonContext>>>,
}
/// Python context for execution
#[derive(Debug)]
struct PythonContext {
    py: Python<'static>,
    globals: PyObject,
    locals: PyObject,
}
/// Amber API exposed to Python
#[derive(Debug)]
pub struct AmberAPI {
    runtime: Arc<dyn AmberRuntimeInterface>,
}
/// Interface for Amber runtime operations
pub trait AmberRuntimeInterface: Send + Sync {
    fn execute_script(&self, script: &str) -> Result<String>;
    fn get_variable(&self, name: &str) -> Result<String>;
    fn set_variable(&self, name: &str, value: &str) -> Result<()>;
}
impl PythonGIL {
    /// Create a new Python GIL manager
    pub fn new() -> Result<Self> {
        Python::with_gil(|py| Ok(PythonGIL { _python: py }))
    }
}
impl PythonRuntime {
    /// Create a new Python runtime
    pub fn new(amber_api: Arc<AmberAPI>) -> Result<Self> {
        let gil: _ = Arc::new(PythonGIL::new()?);
        let context_pool: _ = Arc::new(RwLock::new(Vec::new()));
        Ok(PythonRuntime {
            gil,
            amber_api,
            context_pool,
        })
    }
    /// Get or create a Python context
    async fn get_context(&self) -> Result<PythonContext> {
        let mut pool = self.context_pool.write().await;
        if let Some(context) = pool.pop() {
            Ok(context)
        } else {
            Python::with_gil(|py| {
                let globals: _ = PyDict::new(py).into();
                let locals: _ = PyDict::new(py).into();
                Ok(PythonContext {
                    py,
                    globals,
                    locals,
                })
            })
        }
    }
    /// Return a context to the pool
    async fn return_context(&self, context: PythonContext) {
        let mut pool = self.context_pool.write().await;
        pool.push(context);
    }
    /// Execute Python code
    pub async fn execute_python(&self, code: &str) -> Result<String> {
        let context: _ = self.get_context().await?;
        let result: _ = Python::with_gil(|py| {
            let result: _ = py.run(
                code,
                Some(context.globals.clone()),
                Some(context.locals.clone()),
            );
            match result {
                Ok(_) => {
                    // Try to get the last expression value
                    let value: _ = context.globals.get_item(py, "_");
                    match value {
                        Ok(Some(val)) => Ok(val.to_string()),
                        Ok(None) => Ok("None".to_string()),
                        Err(e) => Ok(format!("Error: {}", e)),
                    }
                }
                Err(e) => Err(anyhow!("Python execution error: {}", e)),
            }
        });
        self.return_context(context).await;
        result
    }
    /// Call a Python function
    pub async fn call_python_function(
        &self,
        module: &str,
        func: &str,
        args: &[String],
    ) -> Result<String> {
        let code: _ = format!(
            "import {}\nresult = {}({})",
            module,
            func,
            args.iter().map(|a| format!("'{}'", a)).collect::<Vec<_>().join(", ")
        );
        self.execute_python(&code).await
    }
    /// Execute Python script with Amber API access
    pub async fn execute_with_amber_api(&self, code: &str) -> Result<String> {
        let context: _ = self.get_context().await?;
        let result: _ = Python::with_gil(|py| {
            // Inject Amber API into the global scope
            let amber_module: _ = PyModule::create(py, "amber_runtime")?;
            amber_module.add_function(wrap_pyfunction!(amber_get_variable, amber_module)?)?;
            amber_module.add_function(wrap_pyfunction!(amber_set_variable, amber_module)?)?;
            amber_module.add_function(wrap_pyfunction!(amber_execute, amber_module)?)?;
            let amber_api_obj: _ = pyo3::types::PyModule::from_object(py, amber_module)?;
            context.globals.set_item(py, "amber", amber_api_obj)?;
            // Execute the user code
            let result: _ = py.run(
                code,
                Some(context.globals.clone()),
                Some(context.locals.clone()),
            );
            match result {
                Ok(_) => {
                    let value: _ = context.globals.get_item(py, "_");
                    match value {
                        Ok(Some(val)) => Ok(val.to_string()),
                        Ok(None) => Ok("None".to_string()),
                        Err(e) => Ok(format!("Error: {}", e)),
                    }
                }
                Err(e) => Err(anyhow!("Python execution error: {}", e)),
            }
        });
        self.return_context(context).await;
        result
    }
}
/// Python callable function to get variable from Amber runtime
#[pyfunction]
fn amber_get_variable(name: &str) -> PyResult<String> {
    // This is a placeholder - in real implementation, this would call into Amber runtime
    Ok(format!("Value of {} from Amber", name))
}
/// Python callable function to set variable in Amber runtime
#[pyfunction]
fn amber_set_variable(name: &str, value: &str) -> PyResult<()> {
    // This is a placeholder - in real implementation, this would call into Amber runtime
    println!("Setting Amber variable {} = {}", name, value);
    Ok(())
}
/// Python callable function to execute script in Amber runtime
#[pyfunction]
fn amber_execute(script: &str) -> PyResult<String> {
    // This is a placeholder - in real implementation, this would call into Amber runtime
    Ok(format!("Executed in Amber: {}", script))
}
#[cfg(test)]
mod tests {
    use super::*;

    fn amber_api() -> Arc<AmberAPI> {
        Arc::new(AmberAPI {
            runtime: Arc::new(MockAmberRuntime),
        })
    }

    #[tokio::test]
    async fn test_python_basic_execution() {
        let runtime: _ = PythonRuntime::new(amber_api()).unwrap();
        let result: _ = runtime.execute_python("print('Hello from Python!')").await;
        assert!(result.is_ok());
        let result: _ = runtime.execute_python("2 + 2").await;
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "4");
    }
    #[tokio::test]
    async fn test_python_function_call() {
        let runtime: _ = PythonRuntime::new(amber_api()).unwrap();
        // First define a function
        runtime
            .execute_python("def test_func(x, y): return x + y")
            .await
            .unwrap();
        let result: _ = runtime
            .call_python_function("__main__", "test_func", &["3".to_string(), "4".to_string()])
            .await;
        assert!(result.is_ok());
    }
    #[tokio::test]
    async fn test_python_amber_api() {
        let runtime: _ = PythonRuntime::new(amber_api()).unwrap();
        let code: _ = r#"
amber.get_variable("test_var")
"#;
        let result: _ = runtime.execute_with_amber_api(code).await;
        assert!(result.is_ok());
    }
    struct MockAmberRuntime;
    impl AmberRuntimeInterface for MockAmberRuntime {
        fn execute_script(&self, script: &str) -> Result<String> {
            Ok(format!("Executed: {}", script))
        }
        fn get_variable(&self, name: &str) -> Result<String> {
            Ok(format!("value_of_{}", name))
        }
        fn set_variable(&self, name: &str, value: &str) -> Result<()> {
            Ok(())
        }
    }
}