use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use pyo3::types::PyComplex;
use pyo3::{
exceptions::PyValueError,
types::{PyDate, PyDateTime, PyDelta, PyTime, PyTzInfo},
};
use pyo3::{
types::{
PyBool, PyByteArray, PyBytes, PyDict, PyFloat, PyFrozenSet, PyInt, PyList, PySet, PyString,
},
FromPyObject, IntoPy, Py, PyAny, PyResult, Python,
};
#[cfg(feature = "complex")]
use num_complex::Complex;
#[cfg(feature = "complex")]
use num_traits::{Float, FloatConst};
#[cfg(feature = "complex")]
use pyo3::exceptions::PyFloatingPointError;
#[cfg(feature = "complex")]
use std::fmt::Display;
#[cfg(feature = "complex")]
use std::os::raw::c_double;
#[cfg(feature = "time")]
use crate::datetime::DateTime;
#[cfg(feature = "time")]
use pyo3::{types::PyTuple, ToPyObject};
#[cfg(feature = "time")]
use time::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset};
pub trait PyTryFrom<P>: Sized {
fn py_try_from(py: Python, item: &P) -> PyResult<Self>;
}
impl<P> PyTryFrom<PyAny> for Py<P>
where
Self: for<'a> FromPyObject<'a>,
{
fn py_try_from(_py: Python, item: &PyAny) -> PyResult<Self> {
item.extract()
}
}
impl<T, P> PyTryFrom<P> for Box<T>
where
T: PyTryFrom<P>,
{
fn py_try_from(py: Python, item: &P) -> PyResult<Self> {
T::py_try_from(py, item).map(Self::new)
}
}
#[macro_export]
macro_rules! private_py_try_from_py_pyany_inner {
($item: ident, $py: ident, $py_type: ty) => {{
let actual: &$py_type = $item.extract()?;
<Self as $crate::PyTryFrom<$py_type>>::py_try_from($py, actual)
}};
}
#[macro_export]
macro_rules! private_impl_py_try_from_pyany {
($py_type: ty => $rs_type: ty) => {
impl $crate::PyTryFrom<$crate::pyo3::PyAny> for $rs_type {
fn py_try_from(
py: $crate::pyo3::Python,
item: &$crate::pyo3::PyAny,
) -> $crate::pyo3::PyResult<Self> {
let actual: &$py_type = item.extract()?;
<Self as $crate::PyTryFrom<$py_type>>::py_try_from(py, actual)
}
}
};
}
#[macro_export]
#[allow(clippy::module_name_repetitions)]
macro_rules! private_impl_py_try_from {
(&$item: ident, $py: ident, $py_type: ty => $rs_type: ty $convert: block) => {
#[allow(clippy::use_self)]
impl $crate::PyTryFrom<$py_type> for $rs_type {
fn py_try_from(
$py: $crate::pyo3::Python,
$item: &$py_type,
) -> $crate::pyo3::PyResult<Self> {
$convert
}
}
};
}
#[macro_export]
macro_rules! private_impl_py_try_from_with_pyany {
(&$item: ident, $py: ident, $py_type: ty => $rs_type: ty $convert: block) => {
$crate::private_impl_py_try_from!(&$item, $py, $py_type => $rs_type $convert);
$crate::private_impl_py_try_from_pyany!($py_type => $rs_type);
};
}
macro_rules! impl_try_from_py_native {
($py_type: ty => $rs_type: ty) => {
private_impl_py_try_from!(&item, py, $crate::pyo3::Py<$py_type> => $rs_type {
let item: &$py_type = item.as_ref(py);
<Self as $crate::PyTryFrom<$py_type>>::py_try_from(py, item)
});
}
}
macro_rules! impl_try_from_self_python {
($py_type: ty) => {
private_impl_py_try_from!(&item, py, $py_type => $crate::pyo3::Py<$py_type> {
Ok(item.into_py(py))
});
private_impl_py_try_from!(&item, _py, $crate::pyo3::Py<$py_type> => $crate::pyo3::Py<$py_type> {
Ok(item.clone())
});
}
}
macro_rules! impl_try_from_self_rust {
($rs_type: ty) => {
private_impl_py_try_from!(&item, _py, $rs_type => $rs_type {
Ok(item.clone())
});
}
}
macro_rules! impl_try_from_primitive {
($py_type: ty => $rs_type: ty) => {
private_impl_py_try_from_with_pyany!(&item, _py, $py_type => $rs_type { item.extract() });
impl_try_from_py_native!($py_type => $rs_type);
};
}
impl_try_from_primitive!(PyBool => bool);
impl_try_from_self_python!(PyBool);
impl_try_from_self_rust!(bool);
impl_try_from_self_python!(PyByteArray);
impl_try_from_py_native!(PyByteArray => Vec<u8>);
private_impl_py_try_from!(&item, _py, PyByteArray => Vec<u8> {
Ok(item.to_vec())
});
impl_try_from_py_native!(PyByteArray => Box<[u8]>);
private_impl_py_try_from!(&item, py, PyByteArray => Box<[u8]> {
Vec::<u8>::py_try_from(py, item).map(From::from)
});
impl_try_from_self_python!(PyBytes);
impl_try_from_py_native!(PyBytes => Vec<u8>);
private_impl_py_try_from!(&item, _py, PyBytes => Vec<u8> {
Ok(item.as_bytes().to_vec())
});
impl_try_from_py_native!(PyBytes => Box<[u8]>);
private_impl_py_try_from!(&item, py, PyBytes => Box<[u8]> {
Vec::<u8>::py_try_from(py, item).map(From::from)
});
impl_try_from_self_python!(PyComplex);
#[cfg(feature = "complex")]
impl<F> PyTryFrom<Self> for Complex<F>
where
F: Copy + Float + FloatConst + Into<c_double> + Display,
{
fn py_try_from(_py: Python, item: &Self) -> PyResult<Self> {
Ok(*item)
}
}
#[cfg(feature = "complex")]
impl<F> PyTryFrom<Py<PyComplex>> for Complex<F>
where
F: Copy + Float + FloatConst + Into<c_double> + Display,
{
fn py_try_from(py: Python, item: &Py<PyComplex>) -> PyResult<Self> {
Self::py_try_from(py, item.as_ref(py))
}
}
#[cfg(feature = "complex")]
impl<F> PyTryFrom<PyComplex> for Complex<F>
where
F: Copy + Float + FloatConst + Into<c_double> + Display,
{
fn py_try_from(_py: Python, item: &PyComplex) -> PyResult<Self> {
let make_error = |val: c_double| {
PyFloatingPointError::new_err(format!(
"expected {val} to be between {} and {}, inclusive",
F::min_value(),
F::max_value(),
))
};
Ok(Self {
re: F::from(item.real()).ok_or_else(|| make_error(item.real()))?,
im: F::from(item.imag()).ok_or_else(|| make_error(item.imag()))?,
})
}
}
#[cfg(feature = "complex")]
impl<F> PyTryFrom<PyAny> for Complex<F>
where
F: Copy + Float + FloatConst + Into<c_double> + Display,
{
fn py_try_from(py: Python, item: &PyAny) -> PyResult<Self> {
let dict: &PyComplex = item.downcast()?;
Self::py_try_from(py, dict)
}
}
impl_try_from_self_python!(PyDate);
#[cfg(feature = "time")]
impl_try_from_self_rust!(Date);
#[cfg(feature = "time")]
impl_try_from_py_native!(PyDate => Date);
#[cfg(feature = "time")]
private_impl_py_try_from_with_pyany!(&item, py, PyDate => Date {
let year = item.getattr("year").map(|any| i32::py_try_from(py, any))??;
let month: u8 = item.getattr("month").map(|any| u8::py_try_from(py, any))??; let month: Month = month.try_into()
.map_err(|_| {
PyValueError::new_err(format!("Expected date month to be within 0-12, got {month}"))
})?;
let day = item.getattr("day").map(|any| u8::py_try_from(py, any))??;
Self::from_calendar_date(year, month, day).map_err(|err| {
PyValueError::new_err(format!("Failed to create Date object: {err}"))
})
});
impl_try_from_self_python!(PyDateTime);
#[cfg(feature = "time")]
impl_try_from_self_rust!(DateTime);
#[cfg(feature = "time")]
impl_try_from_py_native!(PyDateTime => DateTime);
#[cfg(feature = "time")]
private_impl_py_try_from_with_pyany!(&item, py, PyDateTime => DateTime {
let date = item.call_method0("date").map(|date| Date::py_try_from(py, date))??;
let (time, offset) = item.call_method0("timetz")
.map(|time| <(Time, Option<UtcOffset>)>::py_try_from(py, time))??;
let datetime = PrimitiveDateTime::new(date, time);
let datetime = offset.map_or(Self::Primitive(datetime), |offset| {
let datetime = OffsetDateTime::now_utc()
.replace_date_time(datetime)
.replace_offset(offset);
Self::Offset(datetime)
});
Ok(datetime)
});
impl_try_from_self_python!(PyDelta);
#[cfg(feature = "time")]
impl_try_from_self_rust!(Duration);
#[cfg(feature = "time")]
impl_try_from_py_native!(PyDelta => Duration);
#[cfg(feature = "time")]
private_impl_py_try_from_with_pyany!(&item, _py, PyDelta => Duration {
let days: i64 = item.getattr("days")?.extract()?;
let seconds: i64 = item.getattr("seconds")?.extract()?;
let microseconds: i32 = item.getattr("microseconds")?.extract()?;
let nanoseconds = microseconds.checked_mul(1000).ok_or_else(|| {
PyValueError::new_err("Could not fit {microseconds} microseconds as nanoseconds into a 32-bit signed integer")
})?;
let day_seconds = days.checked_mul(24 * 60 * 60).ok_or_else(|| {
PyValueError::new_err("Could not fit {days} days as seconds into a 64-bit signed integer")
})?;
let seconds = seconds.checked_add(day_seconds).ok_or_else(|| {
PyValueError::new_err("Could not add {days} days and {seconds} seconds into a 64-bit signed integer")
})?;
Ok(Self::new(seconds, nanoseconds))
});
impl_try_from_self_rust!(std::time::Duration);
impl_try_from_py_native!(PyDelta => std::time::Duration);
private_impl_py_try_from!(&item, _py, PyDelta => std::time::Duration {
let days: u64 = item.getattr("days")?.extract()?;
let seconds: u64 = item.getattr("seconds")?.extract()?;
let microseconds: u32 = item.getattr("microseconds")?.extract()?;
let nanoseconds = microseconds.checked_mul(1000).ok_or_else(|| {
PyValueError::new_err("Could not fit {microseconds} microseconds as nanoseconds into a 32-bit signed integer")
})?;
let day_seconds = days.checked_mul(24 * 60 * 60).ok_or_else(|| {
PyValueError::new_err("Could not fit {days} days as seconds into a 64-bit signed integer")
})?;
let seconds = seconds.checked_add(day_seconds).ok_or_else(|| {
PyValueError::new_err("Could not add {days} days and {seconds} seconds into a 64-bit signed integer")
})?;
Ok(Self::new(seconds, nanoseconds))
});
impl_try_from_self_python!(PyDict);
impl<K1, K2, V1, V2, Hasher> PyTryFrom<HashMap<K1, V1>> for HashMap<K2, V2, Hasher>
where
K2: Eq + std::hash::Hash + PyTryFrom<K1>,
V2: PyTryFrom<V1>,
Hasher: std::hash::BuildHasher + Default,
{
fn py_try_from(py: Python, item: &HashMap<K1, V1>) -> PyResult<Self> {
item.iter()
.map(|(key, val)| {
let key = K2::py_try_from(py, key)?;
let val = V2::py_try_from(py, val)?;
Ok((key, val))
})
.collect()
}
}
impl<K, V, Hasher> PyTryFrom<Py<PyDict>> for HashMap<K, V, Hasher>
where
K: Eq + std::hash::Hash + PyTryFrom<PyAny>,
V: PyTryFrom<PyAny>,
Hasher: std::hash::BuildHasher + Default,
{
fn py_try_from(py: Python, item: &Py<PyDict>) -> PyResult<Self> {
Self::py_try_from(py, item.as_ref(py))
}
}
impl<K, V, Hasher> PyTryFrom<PyDict> for HashMap<K, V, Hasher>
where
K: Eq + std::hash::Hash + PyTryFrom<PyAny>,
V: PyTryFrom<PyAny>,
Hasher: std::hash::BuildHasher + Default,
{
fn py_try_from(py: Python, item: &PyDict) -> PyResult<Self> {
let mut map = Self::with_capacity_and_hasher(item.len(), Hasher::default());
for (key, val) in item.iter() {
let key = K::py_try_from(py, key)?;
let val = V::py_try_from(py, val)?;
map.insert(key, val);
}
Ok(map)
}
}
impl<K, V, Hasher> PyTryFrom<PyAny> for HashMap<K, V, Hasher>
where
K: Eq + std::hash::Hash + PyTryFrom<PyAny>,
V: PyTryFrom<PyAny>,
Hasher: std::hash::BuildHasher + Default,
{
fn py_try_from(py: Python, item: &PyAny) -> PyResult<Self> {
let dict: &PyDict = item.downcast()?;
Self::py_try_from(py, dict)
}
}
impl<K1, K2, V1, V2> PyTryFrom<BTreeMap<K1, V1>> for BTreeMap<K2, V2>
where
K2: Ord + PyTryFrom<K1>,
V2: PyTryFrom<V1>,
{
fn py_try_from(py: Python, item: &BTreeMap<K1, V1>) -> PyResult<Self> {
item.iter()
.map(|(key, val)| {
let key = K2::py_try_from(py, key)?;
let val = V2::py_try_from(py, val)?;
Ok((key, val))
})
.collect()
}
}
impl<K, V> PyTryFrom<Py<PyDict>> for BTreeMap<K, V>
where
K: Ord + PyTryFrom<PyAny>,
V: PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, item: &Py<PyDict>) -> PyResult<Self> {
Self::py_try_from(py, item.as_ref(py))
}
}
impl<K, V> PyTryFrom<PyDict> for BTreeMap<K, V>
where
K: Ord + PyTryFrom<PyAny>,
V: PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, item: &PyDict) -> PyResult<Self> {
let mut map = Self::new();
for (key, val) in item.iter() {
let key = K::py_try_from(py, key)?;
let val = V::py_try_from(py, val)?;
map.insert(key, val);
}
Ok(map)
}
}
impl<K, V> PyTryFrom<PyAny> for BTreeMap<K, V>
where
K: Ord + PyTryFrom<PyAny>,
V: PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, item: &PyAny) -> PyResult<Self> {
let dict: &PyDict = item.downcast()?;
<Self as PyTryFrom<PyDict>>::py_try_from(py, dict)
}
}
impl_try_from_self_python!(PyFloat);
impl_try_from_self_rust!(f32);
impl_try_from_self_rust!(f64);
impl_try_from_primitive!(PyFloat => f32);
impl_try_from_primitive!(PyFloat => f64);
impl_try_from_self_python!(PyFrozenSet);
impl<T, Hasher> PyTryFrom<Py<PyFrozenSet>> for HashSet<T, Hasher>
where
T: Eq + std::hash::Hash + PyTryFrom<PyAny>,
Hasher: std::hash::BuildHasher + Default,
{
fn py_try_from(py: Python, set: &Py<PyFrozenSet>) -> PyResult<Self> {
Self::py_try_from(py, set.as_ref(py))
}
}
impl<T, Hasher> PyTryFrom<PyFrozenSet> for HashSet<T, Hasher>
where
T: Eq + std::hash::Hash + PyTryFrom<PyAny>,
Hasher: std::hash::BuildHasher + Default,
{
fn py_try_from(py: Python, set: &PyFrozenSet) -> PyResult<Self> {
let mut map = Self::with_capacity_and_hasher(set.len(), Hasher::default());
for item in set.iter() {
let item = T::py_try_from(py, item)?;
map.insert(item);
}
Ok(map)
}
}
impl<T> PyTryFrom<Py<PyFrozenSet>> for BTreeSet<T>
where
T: Ord + PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, set: &Py<PyFrozenSet>) -> PyResult<Self> {
Self::py_try_from(py, set.as_ref(py))
}
}
impl<T> PyTryFrom<PyFrozenSet> for BTreeSet<T>
where
T: Ord + PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, set: &PyFrozenSet) -> PyResult<Self> {
let mut map = Self::new();
for item in set.iter() {
let item = T::py_try_from(py, item)?;
map.insert(item);
}
Ok(map)
}
}
impl_try_from_self_python!(PyInt);
impl_try_from_self_rust!(i8);
impl_try_from_self_rust!(i16);
impl_try_from_self_rust!(i32);
impl_try_from_self_rust!(i64);
impl_try_from_self_rust!(i128);
impl_try_from_self_rust!(isize);
impl_try_from_self_rust!(u8);
impl_try_from_self_rust!(u16);
impl_try_from_self_rust!(u32);
impl_try_from_self_rust!(u64);
impl_try_from_self_rust!(u128);
impl_try_from_self_rust!(usize);
impl_try_from_primitive!(PyInt => i8);
impl_try_from_primitive!(PyInt => i16);
impl_try_from_primitive!(PyInt => i32);
impl_try_from_primitive!(PyInt => i64);
impl_try_from_primitive!(PyInt => i128);
impl_try_from_primitive!(PyInt => isize);
impl_try_from_primitive!(PyInt => u8);
impl_try_from_primitive!(PyInt => u16);
impl_try_from_primitive!(PyInt => u32);
impl_try_from_primitive!(PyInt => u64);
impl_try_from_primitive!(PyInt => u128);
impl_try_from_primitive!(PyInt => usize);
impl_try_from_self_python!(PyList);
impl<P, T> PyTryFrom<Vec<P>> for Vec<T>
where
T: PyTryFrom<P>,
{
fn py_try_from(py: Python, item: &Vec<P>) -> PyResult<Self> {
item.iter().map(|item| T::py_try_from(py, item)).collect()
}
}
impl<T> PyTryFrom<Py<PyList>> for Vec<T>
where
T: PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, py_list: &Py<PyList>) -> PyResult<Self> {
Self::py_try_from(py, py_list.as_ref(py))
}
}
impl<T> PyTryFrom<PyList> for Vec<T>
where
T: PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, py_list: &PyList) -> PyResult<Self> {
let mut list = Self::with_capacity(py_list.len());
for item in py_list.iter() {
let item = T::py_try_from(py, item)?;
list.push(item);
}
Ok(list)
}
}
impl<T> PyTryFrom<PyAny> for Vec<T>
where
T: PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, item: &PyAny) -> PyResult<Self> {
let actual: &PyList = item.downcast()?;
Self::py_try_from(py, actual)
}
}
impl<T> PyTryFrom<Py<PyList>> for Box<[T]>
where
T: PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, py_list: &Py<PyList>) -> PyResult<Self> {
Self::py_try_from(py, py_list.as_ref(py))
}
}
impl<T> PyTryFrom<PyList> for Box<[T]>
where
T: PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, py_list: &PyList) -> PyResult<Self> {
Vec::py_try_from(py, py_list).map(From::from)
}
}
impl<T> PyTryFrom<PyAny> for Box<[T]>
where
T: PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, item: &PyAny) -> PyResult<Self> {
let actual: &PyList = item.downcast()?;
Self::py_try_from(py, actual)
}
}
impl<T, P> PyTryFrom<Option<P>> for Option<T>
where
T: PyTryFrom<P>,
{
fn py_try_from(py: Python, item: &Option<P>) -> PyResult<Self> {
item.as_ref()
.map_or_else(|| Ok(None), |item| T::py_try_from(py, item).map(Some))
}
}
impl_try_from_self_python!(PySet);
impl<T, P, Hasher> PyTryFrom<HashSet<P, Hasher>> for HashSet<T, Hasher>
where
T: Eq + std::hash::Hash + PyTryFrom<P>,
Hasher: std::hash::BuildHasher + Default,
{
fn py_try_from(py: Python, set: &HashSet<P, Hasher>) -> PyResult<Self> {
set.iter().map(|item| T::py_try_from(py, item)).collect()
}
}
impl<T, Hasher> PyTryFrom<Py<PySet>> for HashSet<T, Hasher>
where
T: Eq + std::hash::Hash + PyTryFrom<PyAny>,
Hasher: std::hash::BuildHasher + Default,
{
fn py_try_from(py: Python, set: &Py<PySet>) -> PyResult<Self> {
Self::py_try_from(py, set.as_ref(py))
}
}
impl<T, Hasher> PyTryFrom<PySet> for HashSet<T, Hasher>
where
T: Eq + std::hash::Hash + PyTryFrom<PyAny>,
Hasher: std::hash::BuildHasher + Default,
{
fn py_try_from(py: Python, set: &PySet) -> PyResult<Self> {
let mut map = Self::with_capacity_and_hasher(set.len(), Hasher::default());
for item in set.iter() {
let item = T::py_try_from(py, item)?;
map.insert(item);
}
Ok(map)
}
}
impl<T, Hasher> PyTryFrom<PyAny> for HashSet<T, Hasher>
where
T: Eq + std::hash::Hash + PyTryFrom<PyAny>,
Hasher: std::hash::BuildHasher + Default,
{
fn py_try_from(py: Python, item: &PyAny) -> PyResult<Self> {
let set: &PySet = item.downcast()?;
Self::py_try_from(py, set)
}
}
impl<T, P> PyTryFrom<BTreeSet<P>> for BTreeSet<T>
where
T: Ord + PyTryFrom<P>,
{
fn py_try_from(py: Python, set: &BTreeSet<P>) -> PyResult<Self> {
set.iter().map(|item| T::py_try_from(py, item)).collect()
}
}
impl<T> PyTryFrom<Py<PySet>> for BTreeSet<T>
where
T: Ord + PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, set: &Py<PySet>) -> PyResult<Self> {
Self::py_try_from(py, set.as_ref(py))
}
}
impl<T> PyTryFrom<PySet> for BTreeSet<T>
where
T: Ord + PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, set: &PySet) -> PyResult<Self> {
let mut map = Self::new();
for item in set.iter() {
let item = T::py_try_from(py, item)?;
map.insert(item);
}
Ok(map)
}
}
impl<T> PyTryFrom<PyAny> for BTreeSet<T>
where
T: Ord + PyTryFrom<PyAny>,
{
fn py_try_from(py: Python, set: &PyAny) -> PyResult<Self> {
let set: &PySet = set.downcast()?;
<Self as PyTryFrom<PySet>>::py_try_from(py, set)
}
}
impl_try_from_self_python!(PyString);
impl_try_from_self_rust!(String);
impl_try_from_py_native!(PyString => String);
private_impl_py_try_from_with_pyany!(&item, _py, PyString => String {
item.to_str().map(ToString::to_string)
});
impl_try_from_self_python!(PyTime);
#[cfg(feature = "time")]
impl_try_from_self_rust!((Time, Option<UtcOffset>));
#[cfg(feature = "time")]
impl_try_from_py_native!(PyTime => (Time, Option<UtcOffset>));
#[cfg(feature = "time")]
private_impl_py_try_from_with_pyany!(&item, py, PyTime => (Time, Option<UtcOffset>) {
let hour: u8 = item.getattr("hour")?.downcast::<PyInt>()?.extract()?;
let minute: u8 = item.getattr("minute")?.downcast::<PyInt>()?.extract()?;
let seconds: u8 = item.getattr("second")?.downcast::<PyInt>()?.extract()?;
let microseconds: u32 = item.getattr("microsecond")?.downcast::<PyInt>()?.extract()?;
let tzinfo: Option<&PyTzInfo> = item.getattr("tzinfo")?.extract()?;
let offset = tzinfo.map(|tzinfo| UtcOffset::py_try_from(py, tzinfo)).transpose()?;
let timestamp = Time::from_hms_micro(hour, minute, seconds, microseconds).map_err(|err| {
PyValueError::new_err(format!("Could not create a Rust Time from {hour}:{minute}:{seconds}.{microseconds}: {err}"))
})?;
Ok((timestamp, offset))
});
impl_try_from_self_python!(PyTzInfo);
#[cfg(feature = "time")]
impl_try_from_self_rust!(UtcOffset);
#[cfg(feature = "time")]
impl_try_from_py_native!(PyTzInfo => UtcOffset);
#[cfg(feature = "time")]
private_impl_py_try_from_with_pyany!(&item, py, PyTzInfo => UtcOffset {
let args: Py<PyAny> = (py.None(),).to_object(py);
let args: &PyTuple = args.extract(py)?;
let duration = item.call_method1("utcoffset", args).map(|any| Duration::py_try_from(py, any))??;
let seconds = duration.whole_seconds();
let seconds = seconds.try_into().map_err(|_| {
PyValueError::new_err(format!("Cannot create a Rust UtcOffset from {seconds} seconds -- too many seconds!"))
})?;
let offset = Self::from_whole_seconds(seconds).map_err(|_| {
PyValueError::new_err(format!("Cannot create a Rust UtcOffset from {seconds} seconds -- too many seconds!"))
})?;
Ok(offset)
});