use pyo3::{
prelude::*,
types::{PyDict, PyList},
};
use super::{to_pykey_err, to_pyvalue_err};
pub fn get_required_string(dict: &Bound<'_, PyDict>, key: &str) -> PyResult<String> {
dict.get_item(key)?
.ok_or_else(|| to_pykey_err(format!("Missing required key: {key}")))?
.extract()
}
pub fn get_required<T>(dict: &Bound<'_, PyDict>, key: &str) -> PyResult<T>
where
T: for<'a, 'py> FromPyObject<'a, 'py>,
for<'a, 'py> PyErr: From<<T as FromPyObject<'a, 'py>>::Error>,
{
dict.get_item(key)?
.ok_or_else(|| to_pykey_err(format!("Missing required key: {key}")))?
.extract()
.map_err(PyErr::from)
}
pub fn get_optional<T>(dict: &Bound<'_, PyDict>, key: &str) -> PyResult<Option<T>>
where
T: for<'a, 'py> FromPyObject<'a, 'py>,
for<'a, 'py> PyErr: From<<T as FromPyObject<'a, 'py>>::Error>,
{
match dict.get_item(key)? {
Some(value) => {
if value.is_none() {
Ok(None)
} else {
value.extract().map(Some).map_err(PyErr::from)
}
}
None => Ok(None),
}
}
pub fn get_required_parsed<T, F>(dict: &Bound<'_, PyDict>, key: &str, parser: F) -> PyResult<T>
where
F: FnOnce(String) -> Result<T, String>,
{
let value_str = get_required_string(dict, key)?;
parser(value_str).map_err(|e| to_pyvalue_err(format!("Failed to parse '{key}': {e}")))
}
pub fn get_optional_parsed<T, F>(
dict: &Bound<'_, PyDict>,
key: &str,
parser: F,
) -> PyResult<Option<T>>
where
F: FnOnce(String) -> Result<T, String>,
{
match dict.get_item(key)? {
Some(value) => {
if value.is_none() {
Ok(None)
} else {
let value_str: String = value.extract()?;
parser(value_str)
.map(Some)
.map_err(|e| to_pyvalue_err(format!("Failed to parse '{key}': {e}")))
}
}
None => Ok(None),
}
}
pub fn get_required_list<'py>(
dict: &Bound<'py, PyDict>,
key: &str,
) -> PyResult<Bound<'py, PyList>> {
dict.get_item(key)?
.ok_or_else(|| to_pykey_err(format!("Missing required key: {key}")))?
.downcast_into()
.map_err(Into::into)
}