#![cfg(all(Py_3_9, feature = "chrono-tz"))]
#![doc = concat!("pyo3 = { version = \"", env!("CARGO_PKG_VERSION"), "\", features = [\"chrono-tz\"] }")]
use crate::exceptions::PyValueError;
use crate::pybacked::PyBackedStr;
use crate::sync::GILOnceCell;
use crate::types::{any::PyAnyMethods, PyType};
use crate::{
intern, Bound, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject,
};
use chrono_tz::Tz;
use std::str::FromStr;
impl ToPyObject for Tz {
fn to_object(&self, py: Python<'_>) -> PyObject {
static ZONE_INFO: GILOnceCell<Py<PyType>> = GILOnceCell::new();
ZONE_INFO
.get_or_try_init_type_ref(py, "zoneinfo", "ZoneInfo")
.unwrap()
.call1((self.name(),))
.unwrap()
.unbind()
}
}
impl IntoPy<PyObject> for Tz {
fn into_py(self, py: Python<'_>) -> PyObject {
self.to_object(py)
}
}
impl FromPyObject<'_> for Tz {
fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<Tz> {
Tz::from_str(
&ob.getattr(intern!(ob.py(), "key"))?
.extract::<PyBackedStr>()?,
)
.map_err(|e| PyValueError::new_err(e.to_string()))
}
}
#[cfg(all(test, not(windows)))] mod tests {
use super::*;
#[test]
fn test_frompyobject() {
Python::with_gil(|py| {
assert_eq!(
new_zoneinfo(py, "Europe/Paris").extract::<Tz>().unwrap(),
Tz::Europe__Paris
);
assert_eq!(new_zoneinfo(py, "UTC").extract::<Tz>().unwrap(), Tz::UTC);
assert_eq!(
new_zoneinfo(py, "Etc/GMT-5").extract::<Tz>().unwrap(),
Tz::Etc__GMTMinus5
);
});
}
#[test]
fn test_topyobject() {
Python::with_gil(|py| {
let assert_eq = |l: PyObject, r: Bound<'_, PyAny>| {
assert!(l.bind(py).eq(r).unwrap());
};
assert_eq(
Tz::Europe__Paris.to_object(py),
new_zoneinfo(py, "Europe/Paris"),
);
assert_eq(Tz::UTC.to_object(py), new_zoneinfo(py, "UTC"));
assert_eq(
Tz::Etc__GMTMinus5.to_object(py),
new_zoneinfo(py, "Etc/GMT-5"),
);
});
}
fn new_zoneinfo<'py>(py: Python<'py>, name: &str) -> Bound<'py, PyAny> {
zoneinfo_class(py).call1((name,)).unwrap()
}
fn zoneinfo_class(py: Python<'_>) -> Bound<'_, PyAny> {
py.import_bound("zoneinfo")
.unwrap()
.getattr("ZoneInfo")
.unwrap()
}
}