Merge pull request #232 from pganssle/update-datetime-docs

Add documentation and changelog for datetime bindings
This commit is contained in:
konstin 2018-09-28 22:45:34 +02:00 committed by GitHub
commit 78d3d11d12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 118 additions and 14 deletions

View File

@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* `#[pyclass]` objects can now be returned from rust functions
* `PyComplex` by kngwyu in [#226](https://github.com/PyO3/pyo3/pull/226)
* `PyDict::from_sequence()`, equivalent to `dict([(key, val), ...])`
* Bindings for the `datetime` standard library types: `PyDate`, `PyTime`, `PyDateTime`, `PyTzInfo`, `PyDelta` with associated `ffi` types, by pganssle [#200](https://github.com/PyO3/pyo3/pull/200).
### Removed
* Removed most entries from the prelude. The new prelude is small and clear.
@ -27,7 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Fixed
* Added an explenation that the GIL can temporarily be released even while holding a GILGuard.
* Added an explanation that the GIL can temporarily be released even while holding a GILGuard.
* Lots of clippy errors
* Fix segfault on calling an unknown method on a PyObject

View File

@ -1,5 +1,9 @@
#![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};
@ -101,6 +105,7 @@ const _PyDateTime_DATETIME_DATASIZE: usize = 10;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
/// Structure representing a `datetime.date`
pub struct PyDateTime_Date {
pub ob_base: PyObject,
pub hashcode: Py_hash_t,
@ -110,6 +115,7 @@ pub struct PyDateTime_Date {
#[repr(C)]
#[derive(Debug, Copy, Clone)]
/// Structure representing a `datetime.time`
pub struct PyDateTime_Time {
pub ob_base: PyObject,
pub hashcode: Py_hash_t,
@ -122,6 +128,7 @@ pub struct PyDateTime_Time {
#[repr(C)]
#[derive(Debug, Copy, Clone)]
/// Structure representing a `datetime.datetime`
pub struct PyDateTime_DateTime {
pub ob_base: PyObject,
pub hashcode: Py_hash_t,
@ -134,6 +141,7 @@ pub struct PyDateTime_DateTime {
#[repr(C)]
#[derive(Debug, Copy, Clone)]
/// Structure representing a `datetime.timedelta`
pub struct PyDateTime_Delta {
pub ob_base: PyObject,
pub hashcode: Py_hash_t,
@ -188,6 +196,13 @@ impl Deref for PyDateTimeAPI {
}
#[inline]
/// Populates the `PyDateTimeAPI` object
///
/// Unlike in C, this does *not* need to be actively invoked in Rust, which
/// will populate the `PyDateTimeAPI` struct automatically on first use.
/// Use this function only if you want to eagerly load the datetime module,
/// such as if you do not want the first call to a datetime function to be
/// slightly slower than subsequent calls.
pub unsafe fn PyDateTime_IMPORT() -> &'static PyDateTime_CAPI {
// PyDateTime_CAPSULE_NAME is a macro in C
let PyDateTime_CAPSULE_NAME = CString::new("datetime.datetime_CAPI").unwrap();
@ -201,62 +216,73 @@ pub unsafe fn PyDateTime_IMPORT() -> &'static PyDateTime_CAPI {
&(*PY_DATETIME_API_UNSAFE_CACHE)
}
//
// Type Check macros
//
/// Type Check macros
///
/// These are bindings around the C API typecheck macros, all of them return
/// `1` if True and `0` if False. In all type check macros, the argument (`op`)
/// must not be `NULL`.
#[inline]
/// Check if `op` is a `PyDateTimeAPI.DateType` or subtype.
pub unsafe fn PyDate_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.DateType) as c_int
}
#[inline]
/// Check if `op`'s type is exactly `PyDateTimeAPI.DateType`.
pub unsafe fn PyDate_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == PyDateTimeAPI.DateType) as c_int
}
#[inline]
/// Check if `op` is a `PyDateTimeAPI.DateTimeType` or subtype.
pub unsafe fn PyDateTime_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.DateTimeType) as c_int
}
#[inline]
/// Check if `op`'s type is exactly `PyDateTimeAPI.DateTimeType`.
pub unsafe fn PyDateTime_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == PyDateTimeAPI.DateTimeType) as c_int
}
#[inline]
/// Check if `op` is a `PyDateTimeAPI.TimeType` or subtype.
pub unsafe fn PyTime_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.TimeType) as c_int
}
#[inline]
/// Check if `op`'s type is exactly `PyDateTimeAPI.TimeType`.
pub unsafe fn PyTime_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == PyDateTimeAPI.TimeType) as c_int
}
#[inline]
/// Check if `op` is a `PyDateTimeAPI.DetaType` or subtype.
pub unsafe fn PyDelta_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.DeltaType) as c_int
}
#[inline]
/// Check if `op`'s type is exactly `PyDateTimeAPI.DeltaType`.
pub unsafe fn PyDelta_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == PyDateTimeAPI.DeltaType) as c_int
}
#[inline]
/// Check if `op` is a `PyDateTimeAPI.TZInfoType` or subtype.
pub unsafe fn PyTZInfo_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.TZInfoType) as c_int
}
#[inline]
/// Check if `op`'s type is exactly `PyDateTimeAPI.TZInfoType`.
pub unsafe fn PyTZInfo_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == PyDateTimeAPI.TZInfoType) as c_int
}
//
// Accessor functions
//
/// Accessor functions
///
macro_rules! _access_field {
($obj:expr, $type: ident, $field:tt) => {
(*($obj as *mut $type)).$field
@ -265,6 +291,8 @@ macro_rules! _access_field {
// Accessor functions for PyDateTime_Date and PyDateTime_DateTime
#[inline]
/// Retrieve the year component of a `PyDateTime_Date` or `PyDateTime_DateTime`.
/// Returns a signed integer greater than 0.
pub unsafe fn PyDateTime_GET_YEAR(o: *mut PyObject) -> c_int {
// This should work for Date or DateTime
let d = *(o as *mut PyDateTime_Date);
@ -272,12 +300,16 @@ pub unsafe fn PyDateTime_GET_YEAR(o: *mut PyObject) -> c_int {
}
#[inline]
/// Retrieve the month component of a `PyDateTime_Date` or `PyDateTime_DateTime`.
/// Returns a signed integer in the range `[1, 12]`.
pub unsafe fn PyDateTime_GET_MONTH(o: *mut PyObject) -> c_int {
let d = *(o as *mut PyDateTime_Date);
c_int::from(d.data[2])
}
#[inline]
/// Retrieve the day component of a `PyDateTime_Date` or `PyDateTime_DateTime`.
/// Returns a signed integer in the interval `[1, 31]`.
pub unsafe fn PyDateTime_GET_DAY(o: *mut PyObject) -> c_int {
let d = *(o as *mut PyDateTime_Date);
c_int::from(d.data[3])
@ -325,64 +357,94 @@ macro_rules! _PyDateTime_GET_TZINFO {
// Accessor functions for DateTime
#[inline]
/// Retrieve the hour component of a `PyDateTime_DateTime`.
/// Returns a signed integer in the interval `[0, 23]`
pub unsafe fn PyDateTime_DATE_GET_HOUR(o: *mut PyObject) -> c_int {
_PyDateTime_GET_HOUR!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
}
#[inline]
/// Retrieve the minute component of a `PyDateTime_DateTime`.
/// Returns a signed integer in the interval `[0, 59]`
pub unsafe fn PyDateTime_DATE_GET_MINUTE(o: *mut PyObject) -> c_int {
_PyDateTime_GET_MINUTE!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
}
#[inline]
/// Retrieve the second component of a `PyDateTime_DateTime`.
/// Returns a signed integer in the interval `[0, 59]`
pub unsafe fn PyDateTime_DATE_GET_SECOND(o: *mut PyObject) -> c_int {
_PyDateTime_GET_SECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
}
#[inline]
/// Retrieve the microsecond component of a `PyDateTime_DateTime`.
/// Returns a signed integer in the interval `[0, 999999]`
pub unsafe fn PyDateTime_DATE_GET_MICROSECOND(o: *mut PyObject) -> c_int {
_PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
}
#[cfg(Py_3_6)]
#[inline]
/// Retrieve the fold component of a `PyDateTime_DateTime`.
/// Returns a signed integer in the interval `[0, 1]`
///
/// Added in version Python 3.6
pub unsafe fn PyDateTime_DATE_GET_FOLD(o: *mut PyObject) -> c_uchar {
_PyDateTime_GET_FOLD!(o as *mut PyDateTime_DateTime)
}
#[inline]
/// Retrieve the tzinfo component of a `PyDateTime_DateTime`.
/// Returns a pointer to a `PyObject` that should be either NULL or an instance
/// of a `datetime.tzinfo` subclass.
pub unsafe fn PyDateTime_DATE_GET_TZINFO(o: *mut PyObject) -> *mut PyObject {
_PyDateTime_GET_TZINFO!(o as *mut PyDateTime_DateTime)
}
// Accessor functions for Time
#[inline]
/// Retrieve the hour component of a `PyDateTime_Time`.
/// Returns a signed integer in the interval `[0, 23]`
pub unsafe fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int {
_PyDateTime_GET_HOUR!((o as *mut PyDateTime_Time), 0)
}
#[inline]
/// Retrieve the minute component of a `PyDateTime_Time`.
/// Returns a signed integer in the interval `[0, 59]`
pub unsafe fn PyDateTime_TIME_GET_MINUTE(o: *mut PyObject) -> c_int {
_PyDateTime_GET_MINUTE!((o as *mut PyDateTime_Time), 0)
}
#[inline]
/// Retrieve the second component of a `PyDateTime_DateTime`.
/// Returns a signed integer in the interval `[0, 59]`
pub unsafe fn PyDateTime_TIME_GET_SECOND(o: *mut PyObject) -> c_int {
_PyDateTime_GET_SECOND!((o as *mut PyDateTime_Time), 0)
}
#[inline]
/// Retrieve the microsecond component of a `PyDateTime_DateTime`.
/// Returns a signed integer in the interval `[0, 999999]`
pub unsafe fn PyDateTime_TIME_GET_MICROSECOND(o: *mut PyObject) -> c_int {
_PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_Time), 0)
}
#[cfg(Py_3_6)]
#[inline]
/// Retrieve the fold component of a `PyDateTime_Time`.
/// Returns a signed integer in the interval `[0, 1]`
///
/// Added in version Python 3.6
pub unsafe fn PyDateTime_TIME_GET_FOLD(o: *mut PyObject) -> c_uchar {
_PyDateTime_GET_FOLD!(o as *mut PyDateTime_Time)
}
#[inline]
/// Retrieve the tzinfo component of a `PyDateTime_Time`.
/// Returns a pointer to a `PyObject` that should be either NULL or an instance
/// of a `datetime.tzinfo` subclass.
pub unsafe fn PyDateTime_TIME_GET_TZINFO(o: *mut PyObject) -> *mut PyObject {
_PyDateTime_GET_TZINFO!(o as *mut PyDateTime_Time)
}
@ -395,16 +457,34 @@ macro_rules! _access_delta_field {
}
#[inline]
/// Retrieve the days component of a `PyDateTime_Delta`.
///
/// Returns a signed integer in the interval [-999999999, 999999999].
///
/// Note: This retrieves a component from the underlying structure, it is *not*
/// a representation of the total duration of the structure.
pub unsafe fn PyDateTime_DELTA_GET_DAYS(o: *mut PyObject) -> c_int {
_access_delta_field!(o, days)
}
#[inline]
/// Retrieve the seconds component of a `PyDateTime_Delta`.
///
/// Returns a signed integer in the interval [0, 86399].
///
/// Note: This retrieves a component from the underlying structure, it is *not*
/// a representation of the total duration of the structure.
pub unsafe fn PyDateTime_DELTA_GET_SECONDS(o: *mut PyObject) -> c_int {
_access_delta_field!(o, seconds)
}
#[inline]
/// Retrieve the seconds component of a `PyDateTime_Delta`.
///
/// Returns a signed integer in the interval [0, 999999].
///
/// Note: This retrieves a component from the underlying structure, it is *not*
/// a representation of the total duration of the structure.
pub unsafe fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int {
_access_delta_field!(o, microseconds)
}

View File

@ -1,3 +1,7 @@
//! Safe Rust wrappers for types defined in the Python `datetime` library
//!
//! For more details about these types, see the [Python
//! documentation](https://docs.python.org/3/library/datetime.html)
use conversion::ToPyObject;
use err::PyResult;
use ffi;
@ -28,19 +32,27 @@ use std::os::raw::c_int;
use std::ptr;
use types::PyTuple;
// Traits
/// Access traits
/// Trait for accessing the date components of a struct containing a date.
pub trait PyDateAccess {
fn get_year(&self) -> i32;
fn get_month(&self) -> u8;
fn get_day(&self) -> u8;
}
/// Trait for accessing the components of a struct containing a timedelta.
///
/// Note: These access the individual components of a (day, second,
/// microsecond) representation of the delta, they are *not* intended as
/// aliases for calculating the total duration in each of these units.
pub trait PyDeltaAccess {
fn get_days(&self) -> i32;
fn get_seconds(&self) -> i32;
fn get_microseconds(&self) -> i32;
}
/// Trait for accessing the time components of a struct containing a time.
pub trait PyTimeAccess {
fn get_hour(&self) -> u8;
fn get_minute(&self) -> u8;
@ -50,7 +62,7 @@ pub trait PyTimeAccess {
fn get_fold(&self) -> u8;
}
// datetime.date bindings
/// Bindings around `datetime.date`
pub struct PyDate(PyObject);
pyobject_native_type!(PyDate, PyDateTime_DateType, PyDate_Check);
@ -67,6 +79,9 @@ impl PyDate {
}
}
/// Construct a `datetime.date` from a POSIX timestamp
///
/// This is equivalent to `datetime.date.fromtimestamp`
pub fn from_timestamp(py: Python, timestamp: i64) -> PyResult<Py<PyDate>> {
let args = PyTuple::new(py, &[timestamp]);
@ -91,7 +106,7 @@ impl PyDateAccess for PyDate {
}
}
// datetime.datetime bindings
/// Bindings for `datetime.datetime`
pub struct PyDateTime(PyObject);
pyobject_native_type!(PyDateTime, PyDateTime_DateTimeType, PyDateTime_Check);
@ -123,6 +138,9 @@ impl PyDateTime {
}
}
/// Construct a `datetime` object from a POSIX timestamp
///
/// This is equivalent to `datetime.datetime.from_timestamp`
pub fn from_timestamp(
py: Python,
timestamp: f64,
@ -185,7 +203,7 @@ impl PyTimeAccess for PyDateTime {
}
}
// datetime.time
/// Bindings for `datetime.time`
pub struct PyTime(PyObject);
pyobject_native_type!(PyTime, PyDateTime_TimeType, PyTime_Check);
@ -212,6 +230,9 @@ impl PyTime {
}
#[cfg(Py_3_6)]
/// Alternate constructor that takes a `fold` argument
///
/// First available in Python 3.6.
pub fn new_with_fold(
py: Python,
hour: u8,
@ -259,11 +280,13 @@ impl PyTimeAccess for PyTime {
}
}
// datetime.tzinfo bindings
/// Bindings for `datetime.tzinfo`
///
/// This is an abstract base class and should not be constructed directly.
pub struct PyTzInfo(PyObject);
pyobject_native_type!(PyTzInfo, PyDateTime_TZInfoType, PyTZInfo_Check);
// datetime.timedelta bindings
/// Bindings for `datetime.timedelta`
pub struct PyDelta(PyObject);
pyobject_native_type!(PyDelta, PyDateTime_DeltaType, PyDelta_Check);