diff --git a/examples/rustapi_module/src/lib.rs b/examples/rustapi_module/src/lib.rs index 84f14e8c..d160a3a9 100644 --- a/examples/rustapi_module/src/lib.rs +++ b/examples/rustapi_module/src/lib.rs @@ -186,6 +186,29 @@ fn issue_219() -> PyResult<()> { Ok(()) } +#[pyclass(extends=PyTzInfo)] +pub struct TzClass {} + +#[pymethods] +impl TzClass { + #[new] + fn __new__(obj: &PyRawObject) -> PyResult<()> { + obj.init(|_| TzClass {}) + } + + fn utcoffset(&self, py: Python, dt: &PyDateTime) -> PyResult> { + PyDelta::new(py, 0, 3600, 0, true) + } + + fn tzname(&self, py: Python, dt: &PyDateTime) -> PyResult { + Ok(String::from("+01:00")) + } + + fn dst(&self, py: Python, dt: &PyDateTime) -> PyResult> { + Ok(None) + } +} + #[pymodinit] fn datetime(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_function!(make_date))?; @@ -209,5 +232,6 @@ fn datetime(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_function!(issue_219))?; + m.add_class::()?; Ok(()) } diff --git a/examples/rustapi_module/tests/test_datetime.py b/examples/rustapi_module/tests/test_datetime.py index f41d5213..6d2eaebc 100644 --- a/examples/rustapi_module/tests/test_datetime.py +++ b/examples/rustapi_module/tests/test_datetime.py @@ -3,8 +3,7 @@ import rustapi_module.datetime as rdt import sys import datetime as pdt -import pytest - +import pytest from hypothesis import given from hypothesis import strategies as st from hypothesis.strategies import dates, datetimes @@ -263,3 +262,12 @@ def test_delta_err(args, err_type): def test_issue_219(): rdt.issue_219() + +def test_tz_class(): + tzi = rdt.TzClass() + + dt = pdt.datetime(2018, 1, 1, tzinfo=tzi) + + assert dt.tzname() == "+01:00" + assert dt.utcoffset() == pdt.timedelta(hours=1) + assert dt.dst() is None diff --git a/src/ffi/datetime.rs b/src/ffi/datetime.rs index de83a983..1418ff3a 100644 --- a/src/ffi/datetime.rs +++ b/src/ffi/datetime.rs @@ -1,9 +1,11 @@ -#![cfg_attr(feature="cargo-clippy", allow(type_complexity))] +#![cfg_attr(feature = "cargo-clippy", allow(type_complexity))] + //! FFI bindings to the functions and structs defined in `datetime.h` //! //! This is the unsafe thin wrapper around the [CPython C API](https://docs.python.org/3/c-api/datetime.html), //! and covers the various date and time related objects in the Python `datetime` //! standard library module. + use ffi::PyCapsule_Import; use ffi::Py_hash_t; use ffi::{PyObject, PyTypeObject}; @@ -14,16 +16,6 @@ use std::os::raw::{c_char, c_int, c_uchar}; use std::ptr; use std::sync::Once; -#[cfg_attr(windows, link(name = "pythonXY"))] -extern "C" { - pub static mut PyDateTime_DateType: PyTypeObject; - pub static mut PyDateTime_TimeType: PyTypeObject; - pub static mut PyDateTime_DateTimeType: PyTypeObject; - - pub static mut PyDateTime_DeltaType: PyTypeObject; - pub static mut PyDateTime_TZInfoType: PyTypeObject; -} - #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct PyDateTime_CAPI { diff --git a/src/types/datetime.rs b/src/types/datetime.rs index c6dc9b10..f10266b4 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -6,7 +6,7 @@ use conversion::ToPyObject; use err::PyResult; use ffi; use ffi::PyDateTimeAPI; -use ffi::{PyDateTime_Check, PyDateTime_DateTimeType}; +use ffi::{PyDateTime_Check, PyDate_Check, PyDelta_Check, PyTZInfo_Check, PyTime_Check}; #[cfg(Py_3_6)] use ffi::{PyDateTime_DATE_GET_FOLD, PyDateTime_TIME_GET_FOLD}; use ffi::{ @@ -16,15 +16,11 @@ use ffi::{ use ffi::{ PyDateTime_DELTA_GET_DAYS, PyDateTime_DELTA_GET_MICROSECONDS, PyDateTime_DELTA_GET_SECONDS, }; -use ffi::{PyDateTime_DateType, PyDate_Check}; -use ffi::{PyDateTime_DeltaType, PyDelta_Check}; use ffi::{PyDateTime_GET_DAY, PyDateTime_GET_MONTH, PyDateTime_GET_YEAR}; use ffi::{ PyDateTime_TIME_GET_HOUR, PyDateTime_TIME_GET_MICROSECOND, PyDateTime_TIME_GET_MINUTE, PyDateTime_TIME_GET_SECOND, }; -use ffi::{PyDateTime_TZInfoType, PyTZInfo_Check}; -use ffi::{PyDateTime_TimeType, PyTime_Check}; use instance::Py; use object::PyObject; use python::{Python, ToPyPointer}; @@ -64,7 +60,7 @@ pub trait PyTimeAccess { /// Bindings around `datetime.date` pub struct PyDate(PyObject); -pyobject_native_type!(PyDate, PyDateTime_DateType, PyDate_Check); +pyobject_native_type!(PyDate, *PyDateTimeAPI.DateType, PyDate_Check); impl PyDate { pub fn new(py: Python, year: i32, month: u8, day: u8) -> PyResult> { @@ -108,7 +104,7 @@ impl PyDateAccess for PyDate { /// Bindings for `datetime.datetime` pub struct PyDateTime(PyObject); -pyobject_native_type!(PyDateTime, PyDateTime_DateTimeType, PyDateTime_Check); +pyobject_native_type!(PyDateTime, *PyDateTimeAPI.DateTimeType, PyDateTime_Check); impl PyDateTime { pub fn new( @@ -205,7 +201,7 @@ impl PyTimeAccess for PyDateTime { /// Bindings for `datetime.time` pub struct PyTime(PyObject); -pyobject_native_type!(PyTime, PyDateTime_TimeType, PyTime_Check); +pyobject_native_type!(PyTime, *PyDateTimeAPI.TimeType, PyTime_Check); impl PyTime { pub fn new( @@ -284,11 +280,11 @@ impl PyTimeAccess for PyTime { /// /// This is an abstract base class and should not be constructed directly. pub struct PyTzInfo(PyObject); -pyobject_native_type!(PyTzInfo, PyDateTime_TZInfoType, PyTZInfo_Check); +pyobject_native_type!(PyTzInfo, *PyDateTimeAPI.TZInfoType, PyTZInfo_Check); /// Bindings for `datetime.timedelta` pub struct PyDelta(PyObject); -pyobject_native_type!(PyDelta, PyDateTime_DeltaType, PyDelta_Check); +pyobject_native_type!(PyDelta, *PyDateTimeAPI.DeltaType, PyDelta_Check); impl PyDelta { pub fn new(