Add datetime.datetime and switch to PyResult<Py<T>>

This commit is contained in:
Paul Ganssle 2018-04-06 13:39:45 -04:00
parent 52a64a9240
commit d7b90c1b3a
No known key found for this signature in database
GPG key ID: CD54FCE3D964BEFB
5 changed files with 101 additions and 19 deletions

View file

@ -5,12 +5,12 @@ use ffi3::object::*;
use ffi3::pycapsule::PyCapsule_Import;
#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
pub static mut PyDateTime_Date: PyTypeObject;
pub static mut PyDateTime_Time: PyTypeObject;
pub static mut PyDateTime_DateTime: PyTypeObject;
pub static mut PyDateTime_DateType: PyTypeObject;
pub static mut PyDateTime_TimeType: PyTypeObject;
pub static mut PyDateTime_DateTimeType: PyTypeObject;
pub static mut PyDateTime_Delta: PyTypeObject;
pub static mut PyDateTime_TZInfo: PyTypeObject;
pub static mut PyDateTime_DeltaType: PyTypeObject;
pub static mut PyDateTime_TZInfoType: PyTypeObject;
}
@ -101,6 +101,11 @@ pub struct PyDateTime_CAPI {
unsafe impl Sync for PyDateTime_CAPI {}
lazy_static! {
pub static ref PyDateTimeAPI: PyDateTime_CAPI = unsafe { PyDateTime_IMPORT() };
}
#[inline(always)]
pub unsafe fn PyDateTime_IMPORT() -> PyDateTime_CAPI {
// PyDateTime_CAPSULE_NAME is a macro in C
@ -113,5 +118,15 @@ pub unsafe fn PyDateTime_IMPORT() -> PyDateTime_CAPI {
#[inline(always)]
pub unsafe fn PyDate_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyDateTime_Date) as c_int
PyObject_TypeCheck(op, PyDateTimeAPI.DateType) as c_int
}
#[inline(always)]
pub unsafe fn PyDateTime_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.DateTimeType) as c_int
}
#[inline(always)]
pub unsafe fn PyTZInfo_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.TZInfoType) as c_int
}

View file

@ -1,27 +1,61 @@
use err::PyResult;
use object::PyObject;
use std::os::raw::c_int;
use ffi::{PyDateTime_CAPI, PyDateTime_IMPORT};
use ffi::{PyDateTimeAPI};
use python::{Python, ToPyPointer};
use instance::Py;
// datetime.date bindings
pub struct PyDate(PyObject);
pyobject_convert!(PyDate);
pyobject_nativetype!(PyDate, PyDateTime_Date, PyDate_Check);
lazy_static! {
static ref PyDateTimeAPI: PyDateTime_CAPI = unsafe { PyDateTime_IMPORT() };
}
pyobject_nativetype!(PyDate, PyDateTime_DateType, PyDate_Check);
impl PyDate {
pub fn new(py: Python, year: u32, month: u32, day: u32) -> Py<PyDate> {
pub fn new(py: Python, year: u32, month: u32, day: u32) -> PyResult<Py<PyDate>> {
let y = year as c_int;
let m = month as c_int;
let d = day as c_int;
unsafe {
let ptr = PyDateTimeAPI.Date_FromDate.unwrap()(y, m, d, PyDateTimeAPI.DateType);
Py::from_owned_ptr_or_panic(ptr)
Py::from_owned_ptr_or_err(py, ptr)
}
}
}
// datetime.datetime bindings
pub struct PyDateTime(PyObject);
pyobject_convert!(PyDateTime);
pyobject_nativetype!(PyDateTime, PyDateTime_DateTimeType, PyDateTime_Check);
impl PyDateTime {
pub fn new(py: Python, year: u32, month: u32, day: u32,
hour: u32, minute: u32, second: u32, microsecond: u32,
tzinfo: &PyObject) -> PyResult<Py<PyDateTime>> {
let y = year as c_int;
let mo = month as c_int;
let d = day as c_int;
let h = hour as c_int;
let mi = minute as c_int;
let s = second as c_int;
let u = microsecond as c_int;
unsafe {
let ptr = PyDateTimeAPI.DateTime_FromDateAndTime.unwrap()(
y, mo, d, h, mi, s, u, tzinfo.as_ptr(),
PyDateTimeAPI.DateTimeType
);
Py::from_owned_ptr_or_err(py, ptr)
}
}
}
// datetime.tzinfo bindings
pub struct PyTzInfo(PyObject);
pyobject_convert!(PyTzInfo);
pyobject_nativetype!(PyTzInfo, PyDateTime_TZInfoType, PyTZInfo_Check);

View file

@ -5,7 +5,7 @@ mod exc_impl;
pub use self::boolobject::PyBool;
pub use self::bytearray::PyByteArray;
pub use self::datetime::{PyDate};
pub use self::datetime::{PyDate,PyDateTime,PyTzInfo};
pub use self::dict::PyDict;
pub use self::floatob::PyFloat;
pub use self::iterator::PyIterator;

View file

@ -1,15 +1,27 @@
#![feature(proc_macro, specialization)]
extern crate pyo3;
use pyo3::{py, Py, Python, PyModule, PyResult};
use pyo3::prelude::PyDate;
use pyo3::{ToPyObject};
use pyo3::prelude::{PyObject};
use pyo3::prelude::{PyDate, PyDateTime, PyTzInfo};
#[py::modinit(datetime)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "make_date")]
fn make_date(py: Python, year: u32, month: u32, day: u32) -> PyResult<Py<PyDate>> {
Ok(PyDate::new(py, year, month, day))
PyDate::new(py, year, month, day)
}
#[pyfn(m, "make_datetime")]
fn make_datetime(py: Python, year: u32, month: u32, day: u32,
hour: u32, minute: u32, second: u32, microsecond: u32,
tzinfo: Option<&PyTzInfo>) -> PyResult<Py<PyDateTime>> {
let tzi : PyObject = match tzinfo {
Some(t) => t.to_object(py),
None => py.None(),
};
PyDateTime::new(py, year, month, day, hour, minute, second, microsecond, &tzi)
}
Ok(())

View file

@ -9,6 +9,27 @@ def test_date():
assert rdt.make_date(2017, 9, 1) == pdt.date(2017, 9, 1)
def test_date_fails():
def test_invalid_date_fails():
with pytest.raises(ValueError):
rdt.make_date(2017, 2, 30)
@pytest.mark.parametrize('args, kwargs', [
((2017, 9, 1, 12, 45, 30, 0), {}),
((2017, 9, 1, 12, 45, 30, 0), {'tzinfo': pdt.timezone.utc}),
])
def test_datetime(args, kwargs):
act = rdt.make_datetime(*args, **kwargs)
exp = pdt.datetime(*args, **kwargs)
assert act == exp
def test_invalid_datetime_fails():
with pytest.raises(ValueError):
rdt.make_datetime(2011, 1, 42, 0, 0, 0, 0)
def test_datetime_typeerror():
with pytest.raises(TypeError):
rdt.make_datetime('2011', 1, 1, 0, 0, 0, 0)