feat: FromPyFromStr and ToStrToPy macros YAY

This commit is contained in:
J / Jacob Babich
2026-07-09 01:35:49 -04:00
parent c637ad2d76
commit 9a9cefee37
25 changed files with 343 additions and 394 deletions

View File

@@ -1,7 +1,10 @@
use std::{convert::Infallible, str::FromStr};
use pyo3::{types::{PyDict, PyString, PyDictMethods}, Bound, IntoPyObject, Python, PyErr};
use python_utils::IntoPyObjectViaDisplay;
use pyo3::{
types::{PyDict, PyDictMethods, PyString},
Bound, IntoPyObject, PyErr, Python,
};
use python_utils::{FromPyFromStr, IntoPyObjectViaDisplay, ToStrToPy};
use snafu::Snafu;
use strum::EnumString;
use url::Url;
@@ -84,7 +87,7 @@ impl TryFrom<String> for NonSpecialMessage {
}
/// How much of a notification is visible on the lock screen
#[derive(Debug, Clone, Default, EnumString, strum::Display)]
#[derive(Debug, Clone, Default, EnumString, strum::Display, FromPyFromStr, ToStrToPy)]
#[strum(serialize_all = "snake_case")]
pub enum Visibility {
/// always show all notification content
@@ -98,38 +101,14 @@ pub enum Visibility {
Secret,
}
// TODO: replace with a derive(DisplayToPy) (analogous to serde_with::SerializeDisplay) once I make one
impl<'py> IntoPyObject<'py> for Visibility {
type Target = PyString;
type Output = Bound<'py, Self::Target>;
type Error = Infallible;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let s = self.to_string();
s.into_pyobject(py)
}
}
#[derive(Debug, Clone, EnumString, strum::Display)]
#[derive(Debug, Clone, EnumString, strum::Display, FromPyFromStr, ToStrToPy)]
pub enum Behavior {
/// prompt for text to return with the event
#[strum(serialize = "textInput")]
TextInput,
}
// TODO: replace with a derive(DisplayToPy) (analogous to serde_with::SerializeDisplay) once I make one
impl<'py> IntoPyObject<'py> for Behavior {
type Target = PyString;
type Output = Bound<'py, Self::Target>;
type Error = Infallible;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let s = self.to_string();
s.into_pyobject(py)
}
}
#[derive(Debug, Clone, Default, EnumString, strum::Display)]
#[derive(Debug, Clone, Default, EnumString, strum::Display, FromPyFromStr, ToStrToPy)]
#[strum(serialize_all = "camelCase")]
pub enum ActivationMode {
/// launch the app when tapped
@@ -139,18 +118,6 @@ pub enum ActivationMode {
Background,
}
// TODO: replace with a derive(DisplayToPy) (analogous to serde_with::SerializeDisplay) once I make one
impl<'py> IntoPyObject<'py> for ActivationMode {
type Target = PyString;
type Output = Bound<'py, Self::Target>;
type Error = Infallible;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let s = self.to_string();
s.into_pyobject(py)
}
}
// TODO: better typed versions like `CallNumber` or `OpenWebpage` where Action: From<CallNumber> and Action: From<OpenWebPage>
#[derive(Debug, Clone, IntoPyObject, typed_builder::TypedBuilder)]
#[builder(field_defaults(default, setter(strip_option(fallback_suffix = "_option"))))]
@@ -190,7 +157,7 @@ pub struct Action {
pub icon: Option<String>,
}
#[derive(Debug, Clone, Default, EnumString, strum::Display)]
#[derive(Debug, Clone, Default, EnumString, strum::Display, FromPyFromStr, ToStrToPy)]
#[strum(serialize_all = "snake_case", suffix = "_stream")]
pub enum MediaStream {
Alarm,
@@ -203,18 +170,6 @@ pub enum MediaStream {
System,
}
// TODO: replace with a derive(DisplayToPy) (analogous to serde_with::SerializeDisplay) once I make one
impl<'py> IntoPyObject<'py> for MediaStream {
type Target = PyString;
type Output = Bound<'py, Self::Target>;
type Error = Infallible;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let s = self.to_string();
s.into_pyobject(py)
}
}
#[derive(Debug, Default, Clone, typed_builder::TypedBuilder)]
#[builder(field_defaults(default, setter(strip_option(fallback_suffix = "_option"))))]
pub struct NotifyMobileAppServiceDataData {
@@ -232,7 +187,13 @@ impl<'py> IntoPyObject<'py> for NotifyMobileAppServiceDataData {
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let NotifyMobileAppServiceDataData { actions, command, media_stream, tts_text, visibility } = self;
let NotifyMobileAppServiceDataData {
actions,
command,
media_stream,
tts_text,
visibility,
} = self;
let dict = PyDict::new(py);
@@ -279,7 +240,11 @@ impl<'py> IntoPyObject<'py> for NotifyMobileAppServiceData {
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let NotifyMobileAppServiceData { message, title, data } = self;
let NotifyMobileAppServiceData {
message,
title,
data,
} = self;
let dict = PyDict::new(py);
@@ -293,4 +258,4 @@ impl<'py> IntoPyObject<'py> for NotifyMobileAppServiceData {
Ok(dict)
}
}
}