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:
55
home-assistant/src/state/error_state.rs
Normal file
55
home-assistant/src/state/error_state.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use pyo3::{
|
||||
exceptions::{PyException, PyValueError},
|
||||
prelude::*,
|
||||
};
|
||||
use snafu::{ResultExt, Snafu};
|
||||
use strum::EnumString;
|
||||
|
||||
/// A state in Home Assistant that is known to represent an error of some kind:
|
||||
/// * `unavailable` (the device is likely offline or unreachable from the Home Assistant instance)
|
||||
/// * `unknown` (I don't know how to explain this one)
|
||||
#[derive(Debug, Clone, EnumString, strum::Display)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum ErrorState {
|
||||
Unavailable,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum ExtractErrorStateError {
|
||||
/// couldn't extract the object as a string
|
||||
ExtractStringError { source: PyErr },
|
||||
|
||||
/// the string had an unexpected value
|
||||
UnexpectedValue {
|
||||
source: <ErrorState as FromStr>::Err,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ExtractErrorStateError> for PyErr {
|
||||
fn from(error: ExtractErrorStateError) -> Self {
|
||||
match &error {
|
||||
ExtractErrorStateError::ExtractStringError { .. } => {
|
||||
PyException::new_err(error.to_string())
|
||||
}
|
||||
ExtractErrorStateError::UnexpectedValue { .. } => {
|
||||
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 ErrorState {
|
||||
type Error = ExtractErrorStateError;
|
||||
|
||||
fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
|
||||
let s = ob.extract::<String>().context(ExtractStringSnafu)?;
|
||||
|
||||
let state = ErrorState::from_str(&s).context(UnexpectedValueSnafu)?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
}
|
||||
64
home-assistant/src/state/mod.rs
Normal file
64
home-assistant/src/state/mod.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
use std::{convert::Infallible, str::FromStr};
|
||||
|
||||
use pyo3::{exceptions::PyException, prelude::*};
|
||||
use snafu::{ResultExt, Snafu};
|
||||
|
||||
pub mod error_state;
|
||||
pub mod unexpected_state;
|
||||
|
||||
pub use error_state::ErrorState;
|
||||
pub use unexpected_state::UnexpectedState;
|
||||
|
||||
#[derive(Debug, Clone, derive_more::Display)]
|
||||
pub enum HomeAssistantState<State> {
|
||||
Ok(State),
|
||||
Err(ErrorState),
|
||||
UnexpectedErr(UnexpectedState),
|
||||
}
|
||||
|
||||
impl<State: FromStr> FromStr for HomeAssistantState<State> {
|
||||
type Err = Infallible;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
|
||||
if let Ok(ok) = State::from_str(s) {
|
||||
return Ok(HomeAssistantState::Ok(ok));
|
||||
}
|
||||
|
||||
if let Ok(error) = ErrorState::from_str(s) {
|
||||
return Ok(HomeAssistantState::Err(error));
|
||||
}
|
||||
|
||||
Ok(HomeAssistantState::UnexpectedErr(UnexpectedState(s.into())))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum ExtractHomeAssistantStateError {
|
||||
/// couldn't extract the object as a string
|
||||
ExtractStringError { source: PyErr },
|
||||
}
|
||||
|
||||
impl From<ExtractHomeAssistantStateError> for PyErr {
|
||||
fn from(error: ExtractHomeAssistantStateError) -> Self {
|
||||
match &error {
|
||||
ExtractHomeAssistantStateError::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, State: FromStr + FromPyObject<'a, 'py>> FromPyObject<'a, 'py>
|
||||
for HomeAssistantState<State>
|
||||
{
|
||||
type Error = ExtractHomeAssistantStateError;
|
||||
|
||||
fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
|
||||
let s = ob.extract::<&str>().context(ExtractStringSnafu)?;
|
||||
|
||||
let Ok(state) = s.parse();
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
}
|
||||
35
home-assistant/src/state/unexpected_state.rs
Normal file
35
home-assistant/src/state/unexpected_state.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use pyo3::{exceptions::PyException, prelude::*};
|
||||
use snafu::{ResultExt, Snafu};
|
||||
|
||||
#[derive(Debug, Clone, derive_more::Display)]
|
||||
pub struct UnexpectedState(pub Arc<str>);
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum ExtractUnexpectedStateError {
|
||||
/// couldn't extract the object as a string
|
||||
ExtractStringError { source: PyErr },
|
||||
}
|
||||
|
||||
impl From<ExtractUnexpectedStateError> for PyErr {
|
||||
fn from(error: ExtractUnexpectedStateError) -> Self {
|
||||
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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user