monarch_hyperactor/
context.rs1use hyperactor::Instance;
10use hyperactor::context;
11use hyperactor_mesh::comm::multicast::CastInfo;
12use ndslice::Extent;
13use ndslice::Point;
14use pyo3::exceptions::PyRuntimeError;
15use pyo3::prelude::*;
16
17use crate::actor::PythonActor;
18use crate::actor::root_client_actor;
19use crate::mailbox::PyMailbox;
20use crate::proc::PyActorId;
21use crate::runtime;
22use crate::shape::PyPoint;
23
24#[pyclass(name = "Instance", module = "monarch._src.actor.actor_mesh")]
25pub struct PyInstance {
26 inner: Instance<PythonActor>,
27 #[pyo3(get, set)]
28 proc_mesh: Option<Py<PyAny>>,
29 #[pyo3(get, set, name = "_controller_controller")]
30 controller_controller: Option<Py<PyAny>>,
31 #[pyo3(get, set)]
32 pub(crate) rank: PyPoint,
33 #[pyo3(get, set, name = "_children")]
34 children: Option<Py<PyAny>>,
35
36 #[pyo3(get, set, name = "name")]
37 name: String,
38 #[pyo3(get, set, name = "class_name")]
39 class_name: Option<String>,
40 #[pyo3(get, set, name = "creator")]
41 creator: Option<Py<PyAny>>,
42
43 #[pyo3(get, set, name = "_mock_tensor_engine_factory")]
44 mock_tensor_engine_factory: Option<Py<PyAny>>,
45}
46
47impl Clone for PyInstance {
48 fn clone(&self) -> Self {
49 PyInstance {
50 inner: self.inner.clone_for_py(),
51 proc_mesh: self.proc_mesh.clone(),
52 controller_controller: self.controller_controller.clone(),
53 rank: self.rank.clone(),
54 children: self.children.clone(),
55 name: self.name.clone(),
56 class_name: self.class_name.clone(),
57 creator: self.creator.clone(),
58 mock_tensor_engine_factory: self.mock_tensor_engine_factory.clone(),
59 }
60 }
61}
62
63impl std::ops::Deref for PyInstance {
64 type Target = Instance<PythonActor>;
65
66 fn deref(&self) -> &Self::Target {
67 &self.inner
68 }
69}
70
71#[pymethods]
72impl PyInstance {
73 #[getter]
74 pub(crate) fn _mailbox(&self) -> PyMailbox {
75 PyMailbox {
76 inner: self.inner.mailbox_for_py().clone(),
77 }
78 }
79
80 #[getter]
81 pub fn actor_id(&self) -> PyActorId {
82 self.inner.self_id().clone().into()
83 }
84
85 #[pyo3(signature = (reason = None))]
86 fn abort(&self, reason: Option<&str>) -> PyResult<()> {
87 let reason = reason.unwrap_or("(no reason provided)");
88 Ok(self.inner.abort(reason).map_err(anyhow::Error::from)?)
89 }
90
91 #[pyo3(signature = (reason = None))]
92 fn stop(&self, reason: Option<&str>) -> PyResult<()> {
93 tracing::info!(actor_id = %self.inner.self_id(), "stopping PyInstance");
94 let reason = reason.unwrap_or("(no reason provided)");
95 self.inner
96 .stop(reason)
97 .map_err(|e| PyRuntimeError::new_err(e.to_string()))
98 }
99
100 #[pyo3(signature = (reason = None))]
102 fn _stop_instance(&self, reason: Option<&str>) -> PyResult<()> {
103 self.stop(reason)
104 }
105
106 fn set_system(&self) {
112 self.inner.set_system();
113 }
114}
115
116impl PyInstance {
117 pub fn into_instance(self) -> Instance<PythonActor> {
118 self.inner
119 }
120}
121
122impl<I: context::Actor<A = PythonActor>> From<I> for PyInstance {
123 fn from(ins: I) -> Self {
124 PyInstance {
125 inner: ins.instance().clone_for_py(),
126 proc_mesh: None,
127 controller_controller: None,
128 rank: PyPoint::new(0, Extent::unity().into()),
129 children: None,
130 name: "root".to_string(),
131 class_name: None,
132 creator: None,
133 mock_tensor_engine_factory: None,
134 }
135 }
136}
137
138#[pyclass(name = "Context", module = "monarch._src.actor.actor_mesh")]
139pub struct PyContext {
140 instance: Py<PyInstance>,
141 rank: Point,
142}
143
144#[pymethods]
145impl PyContext {
146 #[getter]
147 fn actor_instance(&self) -> &Py<PyInstance> {
148 &self.instance
149 }
150
151 #[getter]
152 fn message_rank(&self) -> PyPoint {
153 self.rank.clone().into()
154 }
155
156 #[staticmethod]
157 fn _root_client_context(py: Python<'_>) -> PyResult<PyContext> {
158 let _guard = runtime::get_tokio_runtime().enter();
159 let instance: PyInstance = root_client_actor(py).into();
160 Ok(PyContext {
161 instance: instance.into_pyobject(py)?.into(),
162 rank: Extent::unity().point_of_rank(0).unwrap(),
163 })
164 }
165
166 #[staticmethod]
170 fn _from_instance(py: Python<'_>, instance: PyInstance) -> PyResult<PyContext> {
171 Ok(PyContext {
172 instance: instance.into_pyobject(py)?.into(),
173 rank: Extent::unity().point_of_rank(0).unwrap(),
174 })
175 }
176}
177
178impl PyContext {
179 pub(crate) fn new<T: hyperactor::actor::Actor>(
180 cx: &hyperactor::Context<T>,
181 instance: Py<PyInstance>,
182 ) -> PyContext {
183 PyContext {
184 instance,
185 rank: cx.cast_point(),
186 }
187 }
188}
189
190pub fn register_python_bindings(hyperactor_mod: &Bound<'_, PyModule>) -> PyResult<()> {
191 hyperactor_mod.add_class::<PyInstance>()?;
192 hyperactor_mod.add_class::<PyContext>()?;
193 Ok(())
194}