chore+feat(home-assistant): update to pyo3 0.27 and update extraction errors, switch out SmolStr for Arc<str>, tighten up light service calls and implement some for notify, start implementing units of measurement like for power
This commit is contained in:
@@ -1,33 +1,64 @@
|
||||
use super::{event::context::context::Context, service::IntoServiceCall};
|
||||
use pyo3::prelude::*;
|
||||
use python_utils::{detach, validate_type_by_name};
|
||||
use pyo3::{
|
||||
exceptions::{PyException, PyTypeError},
|
||||
prelude::*,
|
||||
};
|
||||
use python_utils::{detach, validate_type_by_name, TypeByNameValidationError};
|
||||
use snafu::{ResultExt, Snafu};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ServiceRegistry(Py<PyAny>);
|
||||
|
||||
impl<'py> FromPyObject<'py> for ServiceRegistry {
|
||||
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
|
||||
impl<'a, 'py> FromPyObject<'a, 'py> for ServiceRegistry {
|
||||
type Error = TypeByNameValidationError;
|
||||
|
||||
fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
|
||||
// region: Validation
|
||||
validate_type_by_name(ob, "ServiceRegistry")?;
|
||||
validate_type_by_name(&ob, "ServiceRegistry")?;
|
||||
// endregion: Validation
|
||||
|
||||
Ok(Self(detach(ob)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum CallServiceError {
|
||||
/// couldn't successfully call `async_call` and turn it into a `Future`
|
||||
CallIntoFutureError { source: PyErr },
|
||||
|
||||
/// couldn't await the `Future` from the `async_call`
|
||||
AwaitFutureError { source: PyErr },
|
||||
|
||||
/// couldn't extract the service response as the requested type
|
||||
ExtractServiceResponseError { source: PyErr },
|
||||
}
|
||||
|
||||
impl From<CallServiceError> for PyErr {
|
||||
fn from(error: CallServiceError) -> Self {
|
||||
match &error {
|
||||
CallServiceError::CallIntoFutureError { .. } => PyException::new_err(error.to_string()),
|
||||
CallServiceError::AwaitFutureError { .. } => PyException::new_err(error.to_string()),
|
||||
CallServiceError::ExtractServiceResponseError { .. } => {
|
||||
PyTypeError::new_err(error.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ServiceRegistry {
|
||||
pub async fn call_service<
|
||||
'a,
|
||||
ServiceData: for<'py> IntoPyObject<'py>,
|
||||
Target: for<'py> IntoPyObject<'py>,
|
||||
Event: for<'py> IntoPyObject<'py>,
|
||||
ServiceResponse: for<'py> FromPyObject<'py>,
|
||||
ServiceResponse: 'static + for<'py> FromPyObjectOwned<'py>,
|
||||
>(
|
||||
&self,
|
||||
&'a self,
|
||||
service_call: impl IntoServiceCall<ServiceData = ServiceData>,
|
||||
context: Option<Context<Event>>,
|
||||
target: Option<Target>,
|
||||
return_response: bool,
|
||||
) -> PyResult<ServiceResponse> {
|
||||
) -> Result<ServiceResponse, CallServiceError> {
|
||||
let (domain, service, service_data) = service_call.into_service_call();
|
||||
|
||||
let blocking = true;
|
||||
@@ -42,13 +73,21 @@ impl ServiceRegistry {
|
||||
return_response,
|
||||
);
|
||||
|
||||
let future = Python::with_gil::<_, PyResult<_>>(|py| {
|
||||
let future = Python::attach::<_, PyResult<_>>(|py| {
|
||||
let service_registry = self.0.bind(py);
|
||||
let awaitable = service_registry.call_method("async_call", args, None)?;
|
||||
pyo3_async_runtimes::tokio::into_future(awaitable)
|
||||
})
|
||||
.context(CallIntoFutureSnafu)?;
|
||||
|
||||
let service_response = future.await.context(AwaitFutureSnafu)?;
|
||||
let service_response = Python::attach(move |py| {
|
||||
service_response
|
||||
.extract(py)
|
||||
.map_err(Into::into)
|
||||
.context(ExtractServiceResponseSnafu)
|
||||
})?;
|
||||
|
||||
let service_response = future.await?;
|
||||
Python::with_gil(|py| service_response.extract(py))
|
||||
Ok(service_response)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user