Switch Py{Date}{Time} constructor parameters to i32
While the valid ranges for the constructor parameters is the same when expressed as either u32 or i32, since the Python API uses i32 in their public interface, we won't have to make any changes to the signatures if the Python behavior changes (e.g. supporting negative years) without their API changing.
This commit is contained in:
parent
113de1bcd3
commit
5d5689f95b
|
@ -14,7 +14,7 @@ use pyo3::{ObjectProtocol, ToPyObject};
|
||||||
use pyo3::{Py, PyResult, Python};
|
use pyo3::{Py, PyResult, Python};
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn make_date(py: Python, year: u32, month: u32, day: u32) -> PyResult<Py<PyDate>> {
|
fn make_date(py: Python, year: i32, month: i32, day: i32) -> PyResult<Py<PyDate>> {
|
||||||
PyDate::new(py, year, month, day)
|
PyDate::new(py, year, month, day)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,10 +33,10 @@ fn date_from_timestamp(py: Python, ts: i64) -> PyResult<Py<PyDate>> {
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn make_time(
|
fn make_time(
|
||||||
py: Python,
|
py: Python,
|
||||||
hour: u32,
|
hour: i32,
|
||||||
minute: u32,
|
minute: i32,
|
||||||
second: u32,
|
second: i32,
|
||||||
microsecond: u32,
|
microsecond: i32,
|
||||||
tzinfo: Option<&PyTzInfo>,
|
tzinfo: Option<&PyTzInfo>,
|
||||||
) -> PyResult<Py<PyTime>> {
|
) -> PyResult<Py<PyTime>> {
|
||||||
PyTime::new(
|
PyTime::new(
|
||||||
|
@ -53,10 +53,10 @@ fn make_time(
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn time_with_fold(
|
fn time_with_fold(
|
||||||
py: Python,
|
py: Python,
|
||||||
hour: u32,
|
hour: i32,
|
||||||
minute: u32,
|
minute: i32,
|
||||||
second: u32,
|
second: i32,
|
||||||
microsecond: u32,
|
microsecond: i32,
|
||||||
tzinfo: Option<&PyTzInfo>,
|
tzinfo: Option<&PyTzInfo>,
|
||||||
fold: bool,
|
fold: bool,
|
||||||
) -> PyResult<Py<PyTime>> {
|
) -> PyResult<Py<PyTime>> {
|
||||||
|
@ -94,7 +94,7 @@ fn get_time_tuple_fold(py: Python, dt: &PyTime) -> Py<PyTuple> {
|
||||||
dt.get_minute(),
|
dt.get_minute(),
|
||||||
dt.get_second(),
|
dt.get_second(),
|
||||||
dt.get_microsecond(),
|
dt.get_microsecond(),
|
||||||
dt.get_fold() as u32,
|
dt.get_fold() as i32,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -119,13 +119,13 @@ fn get_delta_tuple(py: Python, delta: &PyDelta) -> Py<PyTuple> {
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn make_datetime(
|
fn make_datetime(
|
||||||
py: Python,
|
py: Python,
|
||||||
year: u32,
|
year: i32,
|
||||||
month: u32,
|
month: i32,
|
||||||
day: u32,
|
day: i32,
|
||||||
hour: u32,
|
hour: i32,
|
||||||
minute: u32,
|
minute: i32,
|
||||||
second: u32,
|
second: i32,
|
||||||
microsecond: u32,
|
microsecond: i32,
|
||||||
tzinfo: Option<&PyTzInfo>,
|
tzinfo: Option<&PyTzInfo>,
|
||||||
) -> PyResult<Py<PyDateTime>> {
|
) -> PyResult<Py<PyDateTime>> {
|
||||||
PyDateTime::new(
|
PyDateTime::new(
|
||||||
|
@ -170,7 +170,7 @@ fn get_datetime_tuple_fold(py: Python, dt: &PyDateTime) -> Py<PyTuple> {
|
||||||
dt.get_minute(),
|
dt.get_minute(),
|
||||||
dt.get_second(),
|
dt.get_second(),
|
||||||
dt.get_microsecond(),
|
dt.get_microsecond(),
|
||||||
dt.get_fold() as u32,
|
dt.get_fold() as i32,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,9 @@ use python::{Python, ToPyPointer};
|
||||||
|
|
||||||
// Traits
|
// Traits
|
||||||
pub trait PyDateAccess {
|
pub trait PyDateAccess {
|
||||||
fn get_year(&self) -> u32;
|
fn get_year(&self) -> i32;
|
||||||
fn get_month(&self) -> u32;
|
fn get_month(&self) -> i32;
|
||||||
fn get_day(&self) -> u32;
|
fn get_day(&self) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyDeltaAccess {
|
pub trait PyDeltaAccess {
|
||||||
|
@ -40,10 +40,10 @@ pub trait PyDeltaAccess {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PyTimeAccess {
|
pub trait PyTimeAccess {
|
||||||
fn get_hour(&self) -> u32;
|
fn get_hour(&self) -> i32;
|
||||||
fn get_minute(&self) -> u32;
|
fn get_minute(&self) -> i32;
|
||||||
fn get_second(&self) -> u32;
|
fn get_second(&self) -> i32;
|
||||||
fn get_microsecond(&self) -> u32;
|
fn get_microsecond(&self) -> i32;
|
||||||
#[cfg(Py_3_6)]
|
#[cfg(Py_3_6)]
|
||||||
fn get_fold(&self) -> u8;
|
fn get_fold(&self) -> u8;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ pub struct PyDate(PyObject);
|
||||||
pyobject_native_type!(PyDate, PyDateTime_DateType, PyDate_Check);
|
pyobject_native_type!(PyDate, PyDateTime_DateType, PyDate_Check);
|
||||||
|
|
||||||
impl PyDate {
|
impl PyDate {
|
||||||
pub fn new(py: Python, year: u32, month: u32, day: u32) -> PyResult<Py<PyDate>> {
|
pub fn new(py: Python, year: i32, month: i32, day: i32) -> PyResult<Py<PyDate>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = (PyDateTimeAPI.Date_FromDate)(
|
let ptr = (PyDateTimeAPI.Date_FromDate)(
|
||||||
year as c_int,
|
year as c_int,
|
||||||
|
@ -74,16 +74,16 @@ impl PyDate {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PyDateAccess for PyDate {
|
impl PyDateAccess for PyDate {
|
||||||
fn get_year(&self) -> u32 {
|
fn get_year(&self) -> i32 {
|
||||||
unsafe { PyDateTime_GET_YEAR(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_GET_YEAR(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_month(&self) -> u32 {
|
fn get_month(&self) -> i32 {
|
||||||
unsafe { PyDateTime_GET_MONTH(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_GET_MONTH(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_day(&self) -> u32 {
|
fn get_day(&self) -> i32 {
|
||||||
unsafe { PyDateTime_GET_DAY(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_GET_DAY(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,13 +94,13 @@ pyobject_native_type!(PyDateTime, PyDateTime_DateTimeType, PyDateTime_Check);
|
||||||
impl PyDateTime {
|
impl PyDateTime {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
py: Python,
|
py: Python,
|
||||||
year: u32,
|
year: i32,
|
||||||
month: u32,
|
month: i32,
|
||||||
day: u32,
|
day: i32,
|
||||||
hour: u32,
|
hour: i32,
|
||||||
minute: u32,
|
minute: i32,
|
||||||
second: u32,
|
second: i32,
|
||||||
microsecond: u32,
|
microsecond: i32,
|
||||||
tzinfo: Option<&PyObject>,
|
tzinfo: Option<&PyObject>,
|
||||||
) -> PyResult<Py<PyDateTime>> {
|
) -> PyResult<Py<PyDateTime>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -139,34 +139,34 @@ impl PyDateTime {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PyDateAccess for PyDateTime {
|
impl PyDateAccess for PyDateTime {
|
||||||
fn get_year(&self) -> u32 {
|
fn get_year(&self) -> i32 {
|
||||||
unsafe { PyDateTime_GET_YEAR(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_GET_YEAR(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_month(&self) -> u32 {
|
fn get_month(&self) -> i32 {
|
||||||
unsafe { PyDateTime_GET_MONTH(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_GET_MONTH(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_day(&self) -> u32 {
|
fn get_day(&self) -> i32 {
|
||||||
unsafe { PyDateTime_GET_DAY(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_GET_DAY(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PyTimeAccess for PyDateTime {
|
impl PyTimeAccess for PyDateTime {
|
||||||
fn get_hour(&self) -> u32 {
|
fn get_hour(&self) -> i32 {
|
||||||
unsafe { PyDateTime_DATE_GET_HOUR(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_DATE_GET_HOUR(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_minute(&self) -> u32 {
|
fn get_minute(&self) -> i32 {
|
||||||
unsafe { PyDateTime_DATE_GET_MINUTE(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_DATE_GET_MINUTE(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_second(&self) -> u32 {
|
fn get_second(&self) -> i32 {
|
||||||
unsafe { PyDateTime_DATE_GET_SECOND(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_DATE_GET_SECOND(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_microsecond(&self) -> u32 {
|
fn get_microsecond(&self) -> i32 {
|
||||||
unsafe { PyDateTime_DATE_GET_MICROSECOND(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_DATE_GET_MICROSECOND(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(Py_3_6)]
|
#[cfg(Py_3_6)]
|
||||||
|
@ -182,10 +182,10 @@ pyobject_native_type!(PyTime, PyDateTime_TimeType, PyTime_Check);
|
||||||
impl PyTime {
|
impl PyTime {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
py: Python,
|
py: Python,
|
||||||
hour: u32,
|
hour: i32,
|
||||||
minute: u32,
|
minute: i32,
|
||||||
second: u32,
|
second: i32,
|
||||||
microsecond: u32,
|
microsecond: i32,
|
||||||
tzinfo: Option<&PyObject>,
|
tzinfo: Option<&PyObject>,
|
||||||
) -> PyResult<Py<PyTime>> {
|
) -> PyResult<Py<PyTime>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -207,10 +207,10 @@ impl PyTime {
|
||||||
#[cfg(Py_3_6)]
|
#[cfg(Py_3_6)]
|
||||||
pub fn new_with_fold(
|
pub fn new_with_fold(
|
||||||
py: Python,
|
py: Python,
|
||||||
hour: u32,
|
hour: i32,
|
||||||
minute: u32,
|
minute: i32,
|
||||||
second: u32,
|
second: i32,
|
||||||
microsecond: u32,
|
microsecond: i32,
|
||||||
tzinfo: Option<&PyObject>,
|
tzinfo: Option<&PyObject>,
|
||||||
fold: bool,
|
fold: bool,
|
||||||
) -> PyResult<Py<PyTime>> {
|
) -> PyResult<Py<PyTime>> {
|
||||||
|
@ -233,20 +233,20 @@ impl PyTime {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PyTimeAccess for PyTime {
|
impl PyTimeAccess for PyTime {
|
||||||
fn get_hour(&self) -> u32 {
|
fn get_hour(&self) -> i32 {
|
||||||
unsafe { PyDateTime_TIME_GET_HOUR(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_TIME_GET_HOUR(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_minute(&self) -> u32 {
|
fn get_minute(&self) -> i32 {
|
||||||
unsafe { PyDateTime_TIME_GET_MINUTE(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_TIME_GET_MINUTE(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_second(&self) -> u32 {
|
fn get_second(&self) -> i32 {
|
||||||
unsafe { PyDateTime_TIME_GET_SECOND(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_TIME_GET_SECOND(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_microsecond(&self) -> u32 {
|
fn get_microsecond(&self) -> i32 {
|
||||||
unsafe { PyDateTime_TIME_GET_MICROSECOND(self.as_ptr()) as u32 }
|
unsafe { PyDateTime_TIME_GET_MICROSECOND(self.as_ptr()) as i32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(Py_3_6)]
|
#[cfg(Py_3_6)]
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
extern crate pyo3;
|
extern crate pyo3;
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use std::iter;
|
||||||
|
|
||||||
|
use pyo3::prelude::*;
|
||||||
use pyo3::ffi::*;
|
use pyo3::ffi::*;
|
||||||
|
|
||||||
fn _get_subclasses<'p>(
|
fn _get_subclasses<'p>(
|
||||||
|
@ -123,19 +124,41 @@ fn test_datetime_utc() {
|
||||||
assert_eq!(offset, 0f32);
|
assert_eq!(offset, 0f32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static INVALID_DATES : &'static [(i32, i32, i32)] = &[
|
||||||
|
(-1, 1, 1),
|
||||||
|
(0, 1, 1),
|
||||||
|
(10000, 1, 1),
|
||||||
|
(2<<30, 1, 1),
|
||||||
|
(2018, 2<<30, 1),
|
||||||
|
(2018, 0, 1),
|
||||||
|
(2018, -1, 1),
|
||||||
|
(2018, 13, 1),
|
||||||
|
(2018, 1, 0),
|
||||||
|
(2017, 2, 29),
|
||||||
|
(2018, 1, -1),
|
||||||
|
(2018, 1, 32),
|
||||||
|
];
|
||||||
|
|
||||||
|
static INVALID_TIMES: &'static [(i32, i32, i32, i32)] = &[
|
||||||
|
(-1, 0, 0, 0),
|
||||||
|
(25, 0, 0, 0),
|
||||||
|
(2<<30, 0, 0, 0),
|
||||||
|
(0, -1, 0, 0),
|
||||||
|
(0, 60, 0, 0),
|
||||||
|
(0, 2<<30, 0, 0),
|
||||||
|
(0, 0, -1, 0),
|
||||||
|
(0, 0, 61, 0),
|
||||||
|
(0, 0, 2<<30, 0),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
#[cfg(Py_3_6)]
|
#[cfg(Py_3_6)]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pydate_out_of_bounds() {
|
fn test_pydate_out_of_bounds() {
|
||||||
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
|
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let vals = [
|
for val in INVALID_DATES.into_iter() {
|
||||||
(2147484672u32, 1, 1),
|
|
||||||
(2018, 2147484672u32, 1),
|
|
||||||
(2018, 1, 2147484672u32),
|
|
||||||
];
|
|
||||||
|
|
||||||
for val in vals.into_iter() {
|
|
||||||
let (year, month, day) = val;
|
let (year, month, day) = val;
|
||||||
let dt = PyDate::new(py, *year, *month, *day);
|
let dt = PyDate::new(py, *year, *month, *day);
|
||||||
let msg = format!("Should have raised an error: {:#?}", val);
|
let msg = format!("Should have raised an error: {:#?}", val);
|
||||||
|
@ -152,14 +175,7 @@ fn test_pytime_out_of_bounds() {
|
||||||
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
|
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let vals = [
|
for val in INVALID_TIMES.into_iter() {
|
||||||
(2147484672u32, 0, 0, 0),
|
|
||||||
(0, 2147484672u32, 0, 0),
|
|
||||||
(0, 0, 2147484672u32, 0),
|
|
||||||
(0, 0, 0, 2147484672u32),
|
|
||||||
];
|
|
||||||
|
|
||||||
for val in vals.into_iter() {
|
|
||||||
let (hour, minute, second, microsecond) = val;
|
let (hour, minute, second, microsecond) = val;
|
||||||
let dt = PyTime::new(py, *hour, *minute, *second, *microsecond, None);
|
let dt = PyTime::new(py, *hour, *minute, *second, *microsecond, None);
|
||||||
let msg = format!("Should have raised an error: {:#?}", val);
|
let msg = format!("Should have raised an error: {:#?}", val);
|
||||||
|
@ -176,18 +192,18 @@ fn test_pydatetime_out_of_bounds() {
|
||||||
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
|
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let vals = [
|
let valid_time = (0, 0, 0, 0);
|
||||||
(2147484672u32, 1, 1, 0, 0, 0, 0),
|
let valid_date = (2018, 1, 1);
|
||||||
(2018, 2147484672u32, 1, 0, 0, 0, 0),
|
|
||||||
(2018, 1, 2147484672u32, 0, 0, 0, 0),
|
|
||||||
(2018, 1, 1, 2147484672u32, 0, 0, 0),
|
|
||||||
(2018, 1, 1, 0, 2147484672u32, 0, 0),
|
|
||||||
(2018, 1, 1, 0, 0, 2147484672u32, 0),
|
|
||||||
(2018, 1, 1, 0, 0, 0, 2147484672u32),
|
|
||||||
];
|
|
||||||
|
|
||||||
for val in vals.into_iter() {
|
let invalid_dates = INVALID_DATES.into_iter().zip(iter::repeat(&valid_time));
|
||||||
let (year, month, day, hour, minute, second, microsecond) = val;
|
let invalid_times = iter::repeat(&valid_date).zip(INVALID_TIMES.into_iter());
|
||||||
|
|
||||||
|
let vals = invalid_dates.chain(invalid_times);
|
||||||
|
|
||||||
|
for val in vals {
|
||||||
|
let (date, time) = val;
|
||||||
|
let (year, month, day) = date;
|
||||||
|
let (hour, minute, second, microsecond) = time;
|
||||||
let dt = PyDateTime::new(
|
let dt = PyDateTime::new(
|
||||||
py,
|
py,
|
||||||
*year,
|
*year,
|
||||||
|
|
Loading…
Reference in New Issue