Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
775 changes: 399 additions & 376 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ polars = { version = "0.48.1", features = ["polars-io", "dtype-full"] }
chrono = { version = "0.4.38", features = ["serde"] }
pyo3 = { version = "0.24", features = ["chrono", "extension-module"] }
rayon = "1.10.0"
bincode = "1.3.3"

medmodels = { version = "0.4.6", path = "crates/medmodels" }
medmodels-core = { version = "0.4.6", path = "crates/medmodels-core" }
medmodels-utils = { version = "0.4.6", path = "crates/medmodels-utils" }
medmodels-python = { version = "0.4.6", path = "crates/medmodels-python" }
py-medmodels = { version = "0.4.6", path = "crates/py-medmodels" }
medmodels-pyo3-interop = { version = "0.4.6", path = "crates/medmodels-pyo3-interop" }
16 changes: 16 additions & 0 deletions crates/medmodels-pyo3-interop/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "medmodels-pyo3-interop"
version = { workspace = true }
description = { workspace = true }
edition = { workspace = true }
repository = { workspace = true }
license = { workspace = true }
readme = "README.md"


[dependencies]
medmodels = { workspace = true }
medmodels-python = { workspace = true }

pyo3 = { workspace = true }
bincode = { workspace = true }
Empty file.
57 changes: 57 additions & 0 deletions crates/medmodels-pyo3-interop/src/conversion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use medmodels::core::MedRecord;
use pyo3::{
types::{PyAnyMethods, PyBytes, PyBytesMethods},
Bound, FromPyObject, IntoPyObject, PyAny, PyErr, PyResult, Python,
};

#[repr(transparent)]
#[derive(Debug, Clone)]
pub struct PyMedRecord(pub MedRecord);

impl From<MedRecord> for PyMedRecord {
fn from(value: MedRecord) -> Self {
PyMedRecord(value)
}
}

impl From<PyMedRecord> for MedRecord {
fn from(value: PyMedRecord) -> Self {
value.0
}
}

impl AsRef<MedRecord> for PyMedRecord {
fn as_ref(&self) -> &MedRecord {
&self.0
}
}

impl<'py> FromPyObject<'py> for PyMedRecord {
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
let bytes = ob.call_method0("_to_bytes")?;
let py_bytes: &Bound<'py, PyBytes> = bytes.downcast()?;

let medrecord = bincode::deserialize(py_bytes.as_bytes())
.map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?;

Ok(Self(medrecord))
}
}

impl<'py> IntoPyObject<'py> for PyMedRecord {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;

fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let bytes = bincode::serialize(&self.0)
.map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?;

let py_bytes = PyBytes::new(py, &bytes);

let py_medrecord_class = py.import("medmodels._medmodels")?.getattr("PyMedRecord")?;
let obj = py_medrecord_class.call_method1("_from_bytes", (py_bytes,))?;

Ok(obj)
}
}
8 changes: 8 additions & 0 deletions crates/medmodels-pyo3-interop/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mod conversion;
pub mod traits;

pub use conversion::*;
pub use medmodels_python::prelude::{
PyAttributes, PyEdgeIndex, PyGroup, PyMedRecordAttribute, PyMedRecordError, PyMedRecordValue,
PyNodeIndex,
};
1 change: 1 addition & 0 deletions crates/medmodels-pyo3-interop/src/traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub use medmodels_python::medrecord::traits::*;
2 changes: 1 addition & 1 deletion crates/medmodels-python/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ chrono = { workspace = true }
serde = { workspace = true }
rayon = { workspace = true }
pyo3 = { workspace = true }
bincode = { workspace = true }

pyo3-polars = "0.21.0"
numpy = "0.24.0"
bincode = "1.3.3"
25 changes: 22 additions & 3 deletions crates/medmodels-python/src/medrecord/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ use crate::{
};
use attribute::PyMedRecordAttribute;
use errors::PyMedRecordError;
use medmodels::core::medrecord::{
Attributes, EdgeIndex, MedRecord, MedRecordAttribute, MedRecordValue,
use medmodels::core::{
errors::MedRecordError,
medrecord::{Attributes, EdgeIndex, MedRecord, MedRecordAttribute, MedRecordValue},
};
use pyo3::{
prelude::*,
types::{PyDict, PyFunction},
types::{PyBytes, PyDict, PyFunction},
};
use pyo3_polars::PyDataFrame;
use querying::{edges::PyEdgeOperand, nodes::PyNodeOperand, PyReturnOperand, PyReturnValue};
Expand All @@ -32,6 +33,7 @@ use value::PyMedRecordValue;
pub type PyAttributes = HashMap<PyMedRecordAttribute, PyMedRecordValue>;
pub type PyGroup = PyMedRecordAttribute;
pub type PyNodeIndex = PyMedRecordAttribute;
pub type PyEdgeIndex = EdgeIndex;
type Lut<T> = GILHashMap<usize, fn(&Bound<'_, PyAny>) -> PyResult<T>>;

#[pyclass]
Expand Down Expand Up @@ -64,6 +66,23 @@ impl PyMedRecord {
Self(MedRecord::new())
}

pub fn _to_bytes<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
let bytes = bincode::serialize(&self.0)
.map_err(|_| MedRecordError::ConversionError("Could not serialize MedRecord".into()))
.map_err(PyMedRecordError::from)?;

Ok(PyBytes::new(py, &bytes))
}

#[staticmethod]
pub fn _from_bytes(data: &Bound<'_, PyBytes>) -> PyResult<Self> {
let medrecord = bincode::deserialize(data.as_bytes())
.map_err(|_| MedRecordError::ConversionError("Could not deserialize MedRecord".into()))
.map_err(PyMedRecordError::from)?;

Ok(Self(medrecord))
}

#[staticmethod]
pub fn with_schema(schema: PySchema) -> Self {
Self(MedRecord::with_schema(schema.into()))
Expand Down
5 changes: 4 additions & 1 deletion crates/medmodels-python/src/prelude.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
pub use crate::medrecord::{
attribute::PyMedRecordAttribute,
datatype::{
PyAny, PyBool, PyDateTime, PyDuration, PyFloat, PyInt, PyNull, PyOption, PyString, PyUnion,
},
errors::PyMedRecordError,
overview::{
PyAttributeOverview, PyEdgeGroupOverview, PyGroupOverview, PyNodeGroupOverview, PyOverview,
},
Expand Down Expand Up @@ -40,5 +42,6 @@ pub use crate::medrecord::{
PyMatchMode,
},
schema::{PyAttributeDataType, PyAttributeType, PyGroupSchema, PySchema, PySchemaType},
PyMedRecord,
value::PyMedRecordValue,
PyAttributes, PyEdgeIndex, PyGroup, PyMedRecord, PyNodeIndex,
};
3 changes: 3 additions & 0 deletions medmodels/_medmodels.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ class PyMedRecord:
groups: List[Group]

def __init__(self) -> None: ...
def _to_bytes(self) -> bytes: ...
@staticmethod
def _from_bytes(data: bytes) -> PyMedRecord: ...
@staticmethod
def with_schema(schema: PySchema) -> PyMedRecord: ...
@staticmethod
Expand Down