Compare commits

...

3 Commits

17 changed files with 51 additions and 98 deletions

View File

@@ -4,8 +4,8 @@ use ijson::{IArray, INumber, IObject, IString, IValue};
#[cfg(feature = "pyo3")] #[cfg(feature = "pyo3")]
use pyo3::{ use pyo3::{
exceptions::{PyException, PyTypeError, PyValueError}, exceptions::{PyException, PyTypeError, PyValueError},
prelude::*, types::{PyAnyMethods as _, PyList, PyNone, PyTypeMethods as _},
types::{PyList, PyNone}, Borrowed, Bound, FromPyObject, IntoPyObject, PyAny, PyErr, Python,
}; };
use snafu::{ResultExt, Snafu}; use snafu::{ResultExt, Snafu};

View File

@@ -7,8 +7,8 @@ use itertools::Itertools;
#[cfg(feature = "pyo3")] #[cfg(feature = "pyo3")]
use pyo3::{ use pyo3::{
exceptions::PyTypeError, exceptions::PyTypeError,
prelude::*, types::{PyAnyMethods as _, PyNone, PyTuple, PyTypeMethods as _},
types::{PyNone, PyTuple}, Borrowed, Bound, FromPyObject, IntoPyObject, PyAny, PyErr, Python,
}; };
use snafu::{ResultExt, Snafu}; use snafu::{ResultExt, Snafu};

View File

@@ -5,7 +5,11 @@ use driver_kasa::connection::LB130USHandle;
use futures::stream::{FuturesUnordered, StreamExt}; use futures::stream::{FuturesUnordered, StreamExt};
use home_assistant::{home_assistant::HomeAssistant, object_id::ObjectId}; use home_assistant::{home_assistant::HomeAssistant, object_id::ObjectId};
use protocol::light::{Kelvin, TurnToTemperature}; use protocol::light::{Kelvin, TurnToTemperature};
use pyo3::prelude::*; use pyo3::{
pyfunction, pymodule,
types::{PyModule, PyModuleMethods as _},
wrap_pyfunction, Bound, PyAny, PyResult, Python,
};
use shadow_rs::shadow; use shadow_rs::shadow;
use tokio::time::{interval, MissedTickBehavior}; use tokio::time::{interval, MissedTickBehavior};
use tracing::{level_filters::LevelFilter, Level}; use tracing::{level_filters::LevelFilter, Level};

View File

@@ -1,6 +1,9 @@
use super::id::Id; use super::id::Id;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use pyo3::{prelude::*, types::PyType}; use pyo3::{
types::{PyAnyMethods, PyModule, PyType},
Bound, FromPyObject, IntoPyObject, Py, PyAny, PyErr, Python,
};
/// The context that triggered something. /// The context that triggered something.
#[derive(Debug, FromPyObject)] #[derive(Debug, FromPyObject)]

View File

@@ -1,5 +1,5 @@
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use pyo3::prelude::*; use pyo3::FromPyObject;
use super::event_origin::EventOrigin; use super::event_origin::EventOrigin;

View File

@@ -2,7 +2,8 @@ use std::str::FromStr;
use pyo3::{ use pyo3::{
exceptions::{PyException, PyTypeError, PyValueError}, exceptions::{PyException, PyTypeError, PyValueError},
prelude::*, types::PyAnyMethods,
Borrowed, FromPyObject, PyAny, PyErr,
}; };
use snafu::{ResultExt, Snafu}; use snafu::{ResultExt, Snafu};

View File

@@ -1,7 +1,8 @@
use std::convert::Infallible; use std::convert::Infallible;
use pyo3::prelude::*; use pyo3::{
types::PyAnyMethods as _, Borrowed, Bound, FromPyObject, IntoPyObject, Py, PyAny, PyErr, Python,
};
use python_utils::{detach, validate_type_by_name, TypeByNameValidationError}; use python_utils::{detach, validate_type_by_name, TypeByNameValidationError};
use snafu::{ResultExt, Snafu}; use snafu::{ResultExt, Snafu};

View File

@@ -1,4 +1,4 @@
use pyo3::prelude::*; use pyo3::FromPyObject;
#[derive(Debug, FromPyObject)] #[derive(Debug, FromPyObject)]
#[pyo3(from_item_all)] #[pyo3(from_item_all)]

View File

@@ -1,5 +1,5 @@
use attributes::LightAttributes; use attributes::LightAttributes;
use pyo3::prelude::*; use pyo3::{FromPyObject, Py, PyAny, Python};
use snafu::{ResultExt, Snafu}; use snafu::{ResultExt, Snafu};
use state::LightState; use state::LightState;

View File

@@ -7,7 +7,7 @@ use crate::{
state::{ErrorState, HomeAssistantState, UnexpectedState}, state::{ErrorState, HomeAssistantState, UnexpectedState},
}; };
use protocol::light::{GetState, SetState}; use protocol::light::{GetState, SetState};
use pyo3::prelude::*; use pyo3::Python;
use python_utils::IsNone; use python_utils::IsNone;
use snafu::{ResultExt, Snafu}; use snafu::{ResultExt, Snafu};

View File

@@ -1,54 +1,13 @@
use std::str::FromStr; use python_utils::{FromPyFromStr, ToStrToPy};
use pyo3::{
exceptions::{PyException, PyValueError},
prelude::*,
};
use snafu::{ResultExt, Snafu};
use strum::EnumString; use strum::EnumString;
#[derive(Debug, Clone, EnumString, strum::Display)] #[derive(Debug, Clone, EnumString, strum::Display, FromPyFromStr, ToStrToPy)]
#[strum(serialize_all = "snake_case")] #[strum(serialize_all = "snake_case")]
pub enum LightState { pub enum LightState {
On, On,
Off, Off,
} }
#[derive(Debug, Snafu)]
pub enum ExtractLightStateError {
/// couldn't extract the object as a string
ExtractStringError { source: PyErr },
/// couldn't parse the string as a [`LightState`]
ParseError {
source: <LightState as FromStr>::Err,
},
}
impl From<ExtractLightStateError> for PyErr {
fn from(error: ExtractLightStateError) -> Self {
match &error {
ExtractLightStateError::ExtractStringError { .. } => {
PyException::new_err(error.to_string())
}
ExtractLightStateError::ParseError { .. } => PyValueError::new_err(error.to_string()),
}
}
}
// TODO: replace with a derive(PyFromStr) (analogous to serde_with::DeserializeFromStr) once I make one
impl<'a, 'py> FromPyObject<'a, 'py> for LightState {
type Error = ExtractLightStateError;
fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
let s = ob.extract::<&str>().context(ExtractStringSnafu)?;
let state = LightState::from_str(&s).context(ParseSnafu)?;
Ok(state)
}
}
impl From<LightState> for protocol::light::State { impl From<LightState> for protocol::light::State {
fn from(light_state: LightState) -> Self { fn from(light_state: LightState) -> Self {
match light_state { match light_state {

View File

@@ -1,6 +1,9 @@
use arbitrary_value::{arbitrary::Arbitrary, map::Map}; use arbitrary_value::{arbitrary::Arbitrary, map::Map};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use pyo3::{prelude::*, types::PyTuple}; use pyo3::{
types::{PyAnyMethods as _, PyModule, PyTuple},
Borrowed, FromPyObject, IntoPyObject, Py, PyAny, PyErr, Python,
};
use python_utils::{detach, validate_type_by_name, TypeByNameValidationError}; use python_utils::{detach, validate_type_by_name, TypeByNameValidationError};
#[derive(Debug)] #[derive(Debug)]
@@ -54,7 +57,7 @@ pub struct LogData<ExcInfo> {
} }
impl HassLogger { impl HassLogger {
pub fn new(py: Python<'_>, name: &str) -> PyResult<Self> { pub fn new(py: Python<'_>, name: &str) -> Result<Self, PyErr> {
static LOGGING_MODULE: OnceCell<Py<PyModule>> = OnceCell::new(); static LOGGING_MODULE: OnceCell<Py<PyModule>> = OnceCell::new();
let logging_module = LOGGING_MODULE let logging_module = LOGGING_MODULE
@@ -71,7 +74,7 @@ impl HassLogger {
msg: &str, msg: &str,
args: Vec<Arbitrary>, args: Vec<Arbitrary>,
log_data: Option<LogData<ExcInfo>>, log_data: Option<LogData<ExcInfo>>,
) -> PyResult<()> { ) -> Result<(), PyErr> {
let mut all_args = vec![msg.into_pyobject(py)?.into_any()]; let mut all_args = vec![msg.into_pyobject(py)?.into_any()];
for arg in args { for arg in args {
let arg = arg.into_pyobject(py)?; let arg = arg.into_pyobject(py)?;
@@ -94,7 +97,7 @@ impl HassLogger {
msg: &str, msg: &str,
args: Vec<Arbitrary>, args: Vec<Arbitrary>,
log_data: Option<LogData<ExcInfo>>, log_data: Option<LogData<ExcInfo>>,
) -> PyResult<()> { ) -> Result<(), PyErr> {
let mut all_args = vec![msg.into_pyobject(py)?.into_any()]; let mut all_args = vec![msg.into_pyobject(py)?.into_any()];
for arg in args { for arg in args {
let arg = arg.into_pyobject(py)?; let arg = arg.into_pyobject(py)?;
@@ -117,7 +120,7 @@ impl HassLogger {
msg: &str, msg: &str,
args: Vec<Arbitrary>, args: Vec<Arbitrary>,
log_data: Option<LogData<ExcInfo>>, log_data: Option<LogData<ExcInfo>>,
) -> PyResult<()> { ) -> Result<(), PyErr> {
let mut all_args = vec![msg.into_pyobject(py)?.into_any()]; let mut all_args = vec![msg.into_pyobject(py)?.into_any()];
for arg in args { for arg in args {
let arg = arg.into_pyobject(py)?; let arg = arg.into_pyobject(py)?;
@@ -141,7 +144,7 @@ impl HassLogger {
msg: &str, msg: &str,
args: Vec<Arbitrary>, args: Vec<Arbitrary>,
log_data: Option<LogData<ExcInfo>>, log_data: Option<LogData<ExcInfo>>,
) -> PyResult<()> { ) -> Result<(), PyErr> {
let mut all_args = vec![msg.into_pyobject(py)?.into_any()]; let mut all_args = vec![msg.into_pyobject(py)?.into_any()];
for arg in args { for arg in args {
let arg = arg.into_pyobject(py)?; let arg = arg.into_pyobject(py)?;
@@ -164,7 +167,7 @@ impl HassLogger {
msg: &str, msg: &str,
args: Vec<Arbitrary>, args: Vec<Arbitrary>,
log_data: Option<LogData<ExcInfo>>, log_data: Option<LogData<ExcInfo>>,
) -> PyResult<()> { ) -> Result<(), PyErr> {
let mut all_args = vec![msg.into_pyobject(py)?.into_any()]; let mut all_args = vec![msg.into_pyobject(py)?.into_any()];
for arg in args { for arg in args {
let arg = arg.into_pyobject(py)?; let arg = arg.into_pyobject(py)?;

View File

@@ -1,7 +1,9 @@
use super::{event::context::context::Context, service::IntoServiceCall}; use super::{event::context::context::Context, service::IntoServiceCall};
use pyo3::{ use pyo3::{
conversion::FromPyObjectOwned,
exceptions::{PyException, PyTypeError}, exceptions::{PyException, PyTypeError},
prelude::*, types::PyAnyMethods as _,
Borrowed, FromPyObject, IntoPyObject, Py, PyAny, PyErr, Python,
}; };
use python_utils::{detach, validate_type_by_name, TypeByNameValidationError}; use python_utils::{detach, validate_type_by_name, TypeByNameValidationError};
use snafu::{ResultExt, Snafu}; use snafu::{ResultExt, Snafu};
@@ -73,7 +75,7 @@ impl ServiceRegistry {
return_response, return_response,
); );
let future = Python::attach::<_, PyResult<_>>(|py| { let future = Python::attach::<_, Result<_, PyErr>>(|py| {
let service_registry = self.0.bind(py); let service_registry = self.0.bind(py);
let awaitable = service_registry.call_method("async_call", args, None)?; let awaitable = service_registry.call_method("async_call", args, None)?;
pyo3_async_runtimes::tokio::into_future(awaitable) pyo3_async_runtimes::tokio::into_future(awaitable)

View File

@@ -1,35 +1,14 @@
use std::sync::Arc; use std::{convert::Infallible, str::FromStr, sync::Arc};
use pyo3::{exceptions::PyException, prelude::*}; use python_utils::{FromPyFromStr, ToStrToPy};
use snafu::{ResultExt, Snafu};
#[derive(Debug, Clone, derive_more::Display)] #[derive(Debug, Clone, derive_more::Display, FromPyFromStr, ToStrToPy)]
pub struct UnexpectedState(pub Arc<str>); pub struct UnexpectedState(pub Arc<str>);
#[derive(Debug, Snafu)] impl FromStr for UnexpectedState {
pub enum ExtractUnexpectedStateError { type Err = Infallible;
/// couldn't extract the object as a string
ExtractStringError { source: PyErr },
}
impl From<ExtractUnexpectedStateError> for PyErr { fn from_str(s: &str) -> Result<Self, Self::Err> {
fn from(error: ExtractUnexpectedStateError) -> Self { Ok(Self(s.into()))
match &error {
ExtractUnexpectedStateError::ExtractStringError { .. } => {
PyException::new_err(error.to_string())
}
}
}
}
// TODO: replace with a derive(PyFromStr) (analogous to serde_with::DeserializeFromStr) once I make one
impl<'a, 'py> FromPyObject<'a, 'py> for UnexpectedState {
type Error = ExtractUnexpectedStateError;
fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
let s = ob.extract::<String>().context(ExtractStringSnafu)?;
let s = s.into();
Ok(UnexpectedState(s))
} }
} }

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use super::entity_id::EntityId; use super::entity_id::EntityId;
use super::state_object::StateObject; use super::state_object::StateObject;
use pyo3::prelude::*; use pyo3::{conversion::FromPyObjectOwned, Borrowed, FromPyObject, Py, PyAny, PyErr, Python};
use python_utils::{detach, validate_type_by_name, TypeByNameValidationError}; use python_utils::{detach, validate_type_by_name, TypeByNameValidationError};
use snafu::{ResultExt, Snafu}; use snafu::{ResultExt, Snafu};

View File

@@ -7,8 +7,8 @@ use chrono::{DateTime, Utc};
use emitter_and_signal::signal::Signal; use emitter_and_signal::signal::Signal;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use pyo3::{ use pyo3::{
prelude::*, types::{PyAnyMethods as _, PyCFunction, PyDict, PyModule, PyTuple},
types::{PyCFunction, PyDict, PyTuple}, Bound, FromPyObject, IntoPyObject as _, Py, PyAny, PyErr, Python,
}; };
use snafu::{ResultExt, Snafu}; use snafu::{ResultExt, Snafu};
use std::{future::Future, sync::Arc}; use std::{future::Future, sync::Arc};
@@ -86,7 +86,7 @@ impl<
while let Some(publisher) = publisher_stream.wait().await { while let Some(publisher) = publisher_stream.wait().await {
let (new_state_sender, mut new_state_receiver) = mpsc::channel(8); let (new_state_sender, mut new_state_receiver) = mpsc::channel(8);
let untrack = Python::attach::<_, PyResult<_>>(|py| { let untrack = Python::attach::<_, Result<_, PyErr>>(|py| {
static EVENT_MODULE: OnceCell<Py<PyModule>> = OnceCell::new(); static EVENT_MODULE: OnceCell<Py<PyModule>> = OnceCell::new();
let event_module = EVENT_MODULE let event_module = EVENT_MODULE

View File

@@ -1,6 +1,7 @@
use pyo3::{ use pyo3::{
exceptions::{PyException, PyTypeError}, exceptions::{PyException, PyTypeError},
prelude::*, types::{PyAnyMethods as _, PyStringMethods, PyTypeMethods as _},
Borrowed, Bound, Py, PyAny, PyErr,
}; };
use snafu::{ResultExt, Snafu}; use snafu::{ResultExt, Snafu};