use http::Extensions;
use pyo3::{PyObject, PyResult, Python, ToPyObject};
mod lambda;
pub mod layer;
#[cfg(test)]
mod testing;
#[derive(Clone)]
pub struct PyContext {
inner: PyObject,
lambda_ctx: lambda::PyContextLambda,
}
impl PyContext {
pub fn new(inner: PyObject) -> PyResult<Self> {
Ok(Self {
lambda_ctx: lambda::PyContextLambda::new(inner.clone())?,
inner,
})
}
pub fn populate_from_extensions(&self, _ext: &Extensions) {
self.lambda_ctx
.populate_from_extensions(self.inner.clone(), _ext);
}
}
impl ToPyObject for PyContext {
fn to_object(&self, _py: Python<'_>) -> PyObject {
self.inner.clone()
}
}
#[cfg(test)]
mod tests {
use http::Extensions;
use pyo3::{prelude::*, py_run};
use super::testing::get_context;
#[test]
fn py_context() -> PyResult<()> {
pyo3::prepare_freethreaded_python();
let ctx = get_context(
r#"
class Context:
foo: int = 0
bar: str = 'qux'
ctx = Context()
ctx.foo = 42
"#,
);
Python::with_gil(|py| {
py_run!(
py,
ctx,
r#"
assert ctx.foo == 42
assert ctx.bar == 'qux'
# Make some modifications
ctx.foo += 1
ctx.bar = 'baz'
"#
);
});
ctx.populate_from_extensions(&Extensions::new());
Python::with_gil(|py| {
py_run!(
py,
ctx,
r#"
# Make sure we are preserving any modifications
assert ctx.foo == 43
assert ctx.bar == 'baz'
"#
);
});
Ok(())
}
#[test]
fn works_with_none() -> PyResult<()> {
pyo3::prepare_freethreaded_python();
let ctx = get_context("ctx = None");
Python::with_gil(|py| {
py_run!(py, ctx, "assert ctx is None");
});
Ok(())
}
}