Merge pull request #200 from pganssle/datetime

Initial datetime bindings
This commit is contained in:
konstin 2018-08-22 18:00:05 +02:00 committed by GitHub
commit 3e7d5280ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
76 changed files with 1708 additions and 198 deletions

View File

@ -38,7 +38,7 @@ before_install:
- source ./ci/travis/setup.sh
install:
- pip install setuptools-rust pytest pytest-benchmark
- pip install setuptools-rust pytest pytest-benchmark tox
script:
- ./ci/travis/test.sh

View File

@ -7,7 +7,11 @@ cargo test --features $FEATURES
for example in examples/*; do
cd $example
python setup.py install
pytest -v tests
if [ -f tox.ini ]; then
tox -e py
else
pip install -e .
pytest -v tests
fi
cd $TRAVIS_BUILD_DIR
done

6
examples/rustapi_module/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
.pytest_cache
.mypy_cache
.hypothesis
.tox
*.py[co]

View File

@ -0,0 +1,15 @@
[package]
authors = ["PyO3 Authors"]
name = "rustapi-module"
version = "0.1.0"
description = "A Python wrapper for the Rust API for purposes of testing"
[dependencies]
[dependencies.pyo3]
path = "../../"
features = ["extension-module"]
[lib]
name = "rustapi_module"
crate-type = ["cdylib"]

View File

@ -0,0 +1,2 @@
[build-system]
requires = ["setuptools", "wheel", "setuptools_rust>=0.10.2"]

View File

@ -0,0 +1,3 @@
hypothesis>=3.55
pytest>=3.5.0
setuptools-rust>=0.10.2

View File

@ -0,0 +1,56 @@
import sys
from setuptools import setup
from setuptools.command.test import test as TestCommand
from setuptools_rust import RustExtension
class PyTest(TestCommand):
user_options = []
def run(self):
self.run_command("test_rust")
import subprocess
errno = subprocess.call(['pytest', 'tests'])
raise SystemExit(errno)
def get_py_version_cfgs():
# For now each Cfg Py_3_X flag is interpreted as "at least 3.X"
version = sys.version_info[0:2]
if version[0] == 2:
return ['--cfg=Py_2']
py3_min = 5
out_cfg = []
for minor in range(py3_min, version[1]+1):
out_cfg.append('--cfg=Py_3_%d' % minor)
return out_cfg
install_requires = []
tests_require = install_requires + ['pytest', 'pytest-benchmark']
setup(
name='rustapi-module',
version='0.1.0',
classifiers=[
'License :: OSI Approved :: MIT License',
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'Programming Language :: Python',
'Programming Language :: Rust',
'Operating System :: POSIX',
'Operating System :: MacOS :: MacOS X',
],
packages=['rustapi_module'],
rust_extensions=[RustExtension('rustapi_module.datetime', 'Cargo.toml',
rustc_flags=get_py_version_cfgs())],
install_requires=install_requires,
tests_require=tests_require,
include_package_data=True,
zip_safe=False,
cmdclass=dict(test=PyTest)
)

View File

@ -0,0 +1,217 @@
#![feature(specialization)]
#[macro_use]
extern crate pyo3;
use pyo3::prelude::PyDeltaAccess;
use pyo3::prelude::PyModule;
use pyo3::prelude::PyObject;
use pyo3::prelude::{pyfunction, pymodinit};
use pyo3::prelude::{PyDate, PyDateTime, PyDelta, PyTime, PyTzInfo};
use pyo3::prelude::{PyDateAccess, PyTimeAccess};
use pyo3::prelude::{PyDict, PyTuple};
use pyo3::{ObjectProtocol, ToPyObject};
use pyo3::{Py, PyResult, Python};
#[pyfunction]
fn make_date(py: Python, year: i32, month: u8, day: u8) -> PyResult<Py<PyDate>> {
PyDate::new(py, year, month, day)
}
#[pyfunction]
fn get_date_tuple(py: Python, d: &PyDate) -> Py<PyTuple> {
PyTuple::new(
py,
&[d.get_year(), d.get_month() as i32, d.get_day() as i32],
)
}
#[pyfunction]
fn date_from_timestamp(py: Python, ts: i64) -> PyResult<Py<PyDate>> {
let timestamp = ts.to_object(py);
let args = PyTuple::new(py, &[timestamp]);
PyDate::from_timestamp(py, &args.to_object(py))
}
#[pyfunction]
fn make_time(
py: Python,
hour: u8,
minute: u8,
second: u8,
microsecond: u32,
tzinfo: Option<&PyTzInfo>,
) -> PyResult<Py<PyTime>> {
PyTime::new(
py,
hour,
minute,
second,
microsecond,
tzinfo.map(|o| o.to_object(py)).as_ref(),
)
}
#[cfg(Py_3_6)]
#[pyfunction]
fn time_with_fold(
py: Python,
hour: u8,
minute: u8,
second: u8,
microsecond: u32,
tzinfo: Option<&PyTzInfo>,
fold: bool,
) -> PyResult<Py<PyTime>> {
PyTime::new_with_fold(
py,
hour,
minute,
second,
microsecond,
tzinfo.map(|o| o.to_object(py)).as_ref(),
fold,
)
}
#[pyfunction]
fn get_time_tuple(py: Python, dt: &PyTime) -> Py<PyTuple> {
PyTuple::new(
py,
&[
dt.get_hour() as u32,
dt.get_minute() as u32,
dt.get_second() as u32,
dt.get_microsecond(),
],
)
}
#[cfg(Py_3_6)]
#[pyfunction]
fn get_time_tuple_fold(py: Python, dt: &PyTime) -> Py<PyTuple> {
PyTuple::new(
py,
&[
dt.get_hour() as u32,
dt.get_minute() as u32,
dt.get_second() as u32,
dt.get_microsecond(),
dt.get_fold() as u32,
],
)
}
#[pyfunction]
fn make_delta(py: Python, days: i32, seconds: i32, microseconds: i32) -> PyResult<Py<PyDelta>> {
PyDelta::new(py, days, seconds, microseconds, true)
}
#[pyfunction]
fn get_delta_tuple(py: Python, delta: &PyDelta) -> Py<PyTuple> {
PyTuple::new(
py,
&[
delta.get_days(),
delta.get_seconds(),
delta.get_microseconds(),
],
)
}
#[pyfunction]
fn make_datetime(
py: Python,
year: i32,
month: u8,
day: u8,
hour: u8,
minute: u8,
second: u8,
microsecond: u32,
tzinfo: Option<&PyTzInfo>,
) -> PyResult<Py<PyDateTime>> {
PyDateTime::new(
py,
year,
month,
day,
hour,
minute,
second,
microsecond,
tzinfo.map(|o| (o.to_object(py))).as_ref(),
)
}
#[pyfunction]
fn get_datetime_tuple(py: Python, dt: &PyDateTime) -> Py<PyTuple> {
PyTuple::new(
py,
&[
dt.get_year(),
dt.get_month() as i32,
dt.get_day() as i32,
dt.get_hour() as i32,
dt.get_minute() as i32,
dt.get_second() as i32,
dt.get_microsecond() as i32,
],
)
}
#[cfg(Py_3_6)]
#[pyfunction]
fn get_datetime_tuple_fold(py: Python, dt: &PyDateTime) -> Py<PyTuple> {
PyTuple::new(
py,
&[
dt.get_year(),
dt.get_month() as i32,
dt.get_day() as i32,
dt.get_hour() as i32,
dt.get_minute() as i32,
dt.get_second() as i32,
dt.get_microsecond() as i32,
dt.get_fold() as i32,
],
)
}
#[pyfunction]
fn datetime_from_timestamp(py: Python, ts: f64, tz: Option<&PyTzInfo>) -> PyResult<Py<PyDateTime>> {
let timestamp: PyObject = ts.to_object(py);
let tzi: PyObject = match tz {
Some(t) => t.to_object(py),
None => py.None(),
};
let args = PyTuple::new(py, &[timestamp, tzi]);
let kwargs = PyDict::new(py);
PyDateTime::from_timestamp(py, &args.to_object(py), &kwargs.to_object(py))
}
#[pymodinit]
fn datetime(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_function!(make_date))?;
m.add_function(wrap_function!(get_date_tuple))?;
m.add_function(wrap_function!(date_from_timestamp))?;
m.add_function(wrap_function!(make_time))?;
m.add_function(wrap_function!(get_time_tuple))?;
m.add_function(wrap_function!(make_delta))?;
m.add_function(wrap_function!(get_delta_tuple))?;
m.add_function(wrap_function!(make_datetime))?;
m.add_function(wrap_function!(get_datetime_tuple))?;
m.add_function(wrap_function!(datetime_from_timestamp))?;
// Python 3.6+ functions
#[cfg(Py_3_6)]
{
m.add_function(wrap_function!(time_with_fold));
m.add_function(wrap_function!(get_time_tuple_fold));
m.add_function(wrap_function!(get_datetime_tuple_fold));
}
Ok(())
}

View File

@ -0,0 +1,263 @@
import rustapi_module.datetime as rdt
import sys
import datetime as pdt
import pytest
from hypothesis import given
from hypothesis import strategies as st
from hypothesis.strategies import dates, datetimes
# Constants
def _get_utc():
timezone = getattr(pdt, 'timezone', None)
if timezone:
return timezone.utc
else:
class UTC(pdt.tzinfo):
def utcoffset(self, dt):
return pdt.timedelta(0)
def dst(self, dt):
return pdt.timedelta(0)
def tzname(self, dt):
return "UTC"
return UTC()
UTC = _get_utc()
MAX_SECONDS = int(pdt.timedelta.max.total_seconds())
MIN_SECONDS = int(pdt.timedelta.min.total_seconds())
try:
MAX_DAYS = pdt.timedelta.max // pdt.timedelta(days=1)
MIN_DAYS = pdt.timedelta.min // pdt.timedelta(days=1)
except Exception:
# Python 2 compatibility
MAX_DAYS = MAX_SECONDS // pdt.timedelta(days=1).total_seconds()
MIN_DAYS = MIN_SECONDS // pdt.timedelta(days=1).total_seconds()
MAX_MICROSECONDS = int(pdt.timedelta.max.total_seconds() * 1e6)
MIN_MICROSECONDS = int(pdt.timedelta.min.total_seconds() * 1e6)
HAS_FOLD = getattr(pdt.datetime, 'fold', False)
# Helper functions
get_timestamp = getattr(pdt.datetime, 'timestamp', None)
if get_timestamp is None:
def get_timestamp(dt):
# Python 2 compatibility
return (dt - pdt.datetime(1970, 1, 1)).total_seconds()
xfail_date_bounds = pytest.mark.xfail(sys.version_info < (3, 6),
reason="Date bounds were not checked in the C constructor prior to version 3.6")
# Tests
def test_date():
assert rdt.make_date(2017, 9, 1) == pdt.date(2017, 9, 1)
@given(d=st.dates())
def test_date_accessors(d):
act = rdt.get_date_tuple(d)
exp = (d.year, d.month, d.day)
assert act == exp
@xfail_date_bounds
def test_invalid_date_fails():
with pytest.raises(ValueError):
rdt.make_date(2017, 2, 30)
@given(d=dates())
def test_date_from_timestamp(d):
ts = get_timestamp(pdt.datetime.combine(d, pdt.time(0)))
assert rdt.date_from_timestamp(int(ts)) == pdt.date.fromtimestamp(ts)
@pytest.mark.parametrize('args, kwargs', [
((0, 0, 0, 0, None), {}),
((1, 12, 14, 124731), {}),
((1, 12, 14, 124731), {'tzinfo': UTC}),
])
def test_time(args, kwargs):
act = rdt.make_time(*args, **kwargs)
exp = pdt.time(*args, **kwargs)
assert act == exp
assert act.tzinfo is exp.tzinfo
@given(t=st.times())
def test_time(t):
act = rdt.get_time_tuple(t)
exp = (t.hour, t.minute, t.second, t.microsecond)
assert act == exp
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
@given(t=st.times())
def test_time_fold(t):
t_nofold = t.replace(fold=0)
t_fold = t.replace(fold=1)
for t in (t_nofold, t_fold):
act = rdt.get_time_tuple_fold(t)
exp = (t.hour, t.minute, t.second, t.microsecond, t.fold)
assert act == exp
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
@pytest.mark.parametrize('fold', [False, True])
def test_time_fold(fold):
t = rdt.time_with_fold(0, 0, 0, 0, None, fold)
assert t.fold == fold
@pytest.mark.xfail
@pytest.mark.parametrize('args', [
(-1, 0, 0, 0),
(0, -1, 0, 0),
(0, 0, -1, 0),
(0, 0, 0, -1),
])
def test_invalid_time_fails_xfail(args):
with pytest.raises(ValueError):
rdt.make_time(*args)
@xfail_date_bounds
@pytest.mark.parametrize('args', [
(24, 0, 0, 0),
(25, 0, 0, 0),
(0, 60, 0, 0),
(0, 61, 0, 0),
(0, 0, 60, 0),
(0, 0, 61, 0),
(0, 0, 0, 1000000)
])
def test_invalid_time_fails(args):
with pytest.raises(ValueError):
rdt.make_time(*args)
@pytest.mark.parametrize('args', [
('0', 0, 0, 0),
(0, '0', 0, 0),
(0, 0, '0', 0),
(0, 0, 0, '0'),
(0, 0, 0, 0, 'UTC')
])
def test_time_typeerror(args):
with pytest.raises(TypeError):
rdt.make_time(*args)
@pytest.mark.parametrize('args, kwargs', [
((2017, 9, 1, 12, 45, 30, 0), {}),
((2017, 9, 1, 12, 45, 30, 0), {'tzinfo': UTC}),
])
def test_datetime(args, kwargs):
act = rdt.make_datetime(*args, **kwargs)
exp = pdt.datetime(*args, **kwargs)
assert act == exp
assert act.tzinfo is exp.tzinfo
@given(dt=st.datetimes())
def test_datetime_tuple(dt):
act = rdt.get_datetime_tuple(dt)
exp = dt.timetuple()[0:6] + (dt.microsecond, )
assert act == exp
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
@given(dt=st.datetimes())
def test_datetime_tuple_fold(dt):
dt_fold = dt.replace(fold=1)
dt_nofold = dt.replace(fold=0)
for dt in (dt_fold, dt_nofold):
act = rdt.get_datetime_tuple_fold(dt)
exp = dt.timetuple()[0:6] + (dt.microsecond, dt.fold)
assert act == exp
@xfail_date_bounds
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)
@given(dt=datetimes())
def test_datetime_from_timestamp(dt):
ts = get_timestamp(dt)
assert rdt.datetime_from_timestamp(ts) == pdt.datetime.fromtimestamp(ts)
def test_datetime_from_timestamp_tzinfo():
d1 = rdt.datetime_from_timestamp(0, tz=UTC)
d2 = rdt.datetime_from_timestamp(0, tz=UTC)
assert d1 == d2
assert d1.tzinfo is d2.tzinfo
@pytest.mark.parametrize('args', [
(0, 0, 0),
(1, 0, 0),
(-1, 0, 0),
(0, 1, 0),
(0, -1, 0),
(1, -1, 0),
(-1, 1, 0),
(0, 0, 123456),
(0, 0, -123456),
])
def test_delta(args):
act = pdt.timedelta(*args)
exp = rdt.make_delta(*args)
assert act == exp
@given(td=st.timedeltas())
def test_delta_accessors(td):
act = rdt.get_delta_tuple(td)
exp = (td.days, td.seconds, td.microseconds)
assert act == exp
@pytest.mark.parametrize('args,err_type', [
((MAX_DAYS + 1, 0, 0), OverflowError),
((MIN_DAYS - 1, 0, 0), OverflowError),
((0, MAX_SECONDS + 1, 0), OverflowError),
((0, MIN_SECONDS - 1, 0), OverflowError),
((0, 0, MAX_MICROSECONDS + 1), OverflowError),
((0, 0, MIN_MICROSECONDS - 1), OverflowError),
(('0', 0, 0), TypeError),
((0, '0', 0), TypeError),
((0, 0, '0'), TypeError),
])
def test_delta_err(args, err_type):
with pytest.raises(err_type):
rdt.make_delta(*args)

View File

@ -0,0 +1,14 @@
[tox]
envlist = py27,
py35,
py36,
py37,
minversion = 2.9.0
skip_missing_interpreters = true
[testenv]
description = Run the unit tests under {basepython}
deps = -rrequirements-dev.txt
usedevelop = True
commands = pip install -e .
pytest

View File

@ -86,7 +86,7 @@ fn impl_class(
let extra = if let Some(token) = token {
Some(quote! {
impl ::pyo3::PyObjectWithToken for #cls {
#[inline(always)]
#[inline]
fn py<'p>(&'p self) -> ::pyo3::Python<'p> {
self.#token.py()
}
@ -243,7 +243,7 @@ fn impl_class(
}
impl ::pyo3::typeob::PyTypeObject for #cls {
#[inline(always)]
#[inline]
fn init_type() {
static START: std::sync::Once = std::sync::ONCE_INIT;
START.call_once(|| {

410
src/ffi/datetime.rs Normal file
View File

@ -0,0 +1,410 @@
#![cfg_attr(feature="cargo-clippy", allow(type_complexity))]
use ffi::PyCapsule_Import;
use ffi::Py_hash_t;
use ffi::{PyObject, PyTypeObject};
use ffi::{PyObject_TypeCheck, Py_TYPE};
use std::ffi::CString;
use std::ops::Deref;
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 {
pub DateType: *mut PyTypeObject,
pub DateTimeType: *mut PyTypeObject,
pub TimeType: *mut PyTypeObject,
pub DeltaType: *mut PyTypeObject,
pub TZInfoType: *mut PyTypeObject,
#[cfg(Py_3_7)]
pub TimeZone_UTC: *mut PyObject,
pub Date_FromDate:
unsafe extern "C" fn(year: c_int, month: c_int, day: c_int, cls: *mut PyTypeObject)
-> *mut PyObject,
pub DateTime_FromDateAndTime: unsafe extern "C" fn(
year: c_int,
month: c_int,
day: c_int,
hour: c_int,
minute: c_int,
second: c_int,
microsecond: c_int,
tzinfo: *mut PyObject,
cls: *mut PyTypeObject,
) -> *mut PyObject,
pub Time_FromTime: unsafe extern "C" fn(
hour: c_int,
minute: c_int,
second: c_int,
microsecond: c_int,
tzinfo: *mut PyObject,
cls: *mut PyTypeObject,
) -> *mut PyObject,
pub Delta_FromDelta: unsafe extern "C" fn(
days: c_int,
seconds: c_int,
microseconds: c_int,
normalize: c_int,
cls: *mut PyTypeObject,
) -> *mut PyObject,
#[cfg(Py_3_7)]
pub TimeZone_FromTimeZone:
unsafe extern "C" fn(offset: *mut PyObject, name: *mut PyObject) -> *mut PyObject,
pub DateTime_FromTimestamp:
unsafe extern "C" fn(cls: *mut PyTypeObject, args: *mut PyObject, kwargs: *mut PyObject)
-> *mut PyObject,
pub Date_FromTimestamp:
unsafe extern "C" fn(cls: *mut PyTypeObject, args: *mut PyObject) -> *mut PyObject,
#[cfg(Py_3_6)]
pub DateTime_FromDateAndTimeAndFold: unsafe extern "C" fn(
year: c_int,
month: c_int,
day: c_int,
hour: c_int,
minute: c_int,
second: c_int,
microsecond: c_int,
tzinfo: *mut PyObject,
fold: c_int,
cls: *mut PyTypeObject,
) -> *mut PyObject,
#[cfg(Py_3_6)]
pub Time_FromTimeAndFold: unsafe extern "C" fn(
hour: c_int,
minute: c_int,
second: c_int,
microsecond: c_int,
tzinfo: *mut PyObject,
fold: c_int,
cls: *mut PyTypeObject,
) -> *mut PyObject,
}
// Type struct wrappers
const _PyDateTime_DATE_DATASIZE: usize = 4;
const _PyDateTime_TIME_DATASIZE: usize = 6;
const _PyDateTime_DATETIME_DATASIZE: usize = 10;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct PyDateTime_Date {
pub ob_base: PyObject,
pub hashcode: Py_hash_t,
pub hastzinfo: c_char,
pub data: [c_uchar; _PyDateTime_DATE_DATASIZE],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct PyDateTime_Time {
pub ob_base: PyObject,
pub hashcode: Py_hash_t,
pub hastzinfo: c_char,
pub data: [c_uchar; _PyDateTime_TIME_DATASIZE],
#[cfg(Py_3_6)]
pub fold: c_uchar,
pub tzinfo: *mut PyObject,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct PyDateTime_DateTime {
pub ob_base: PyObject,
pub hashcode: Py_hash_t,
pub hastzinfo: c_char,
pub data: [c_uchar; _PyDateTime_DATETIME_DATASIZE],
#[cfg(Py_3_6)]
pub fold: c_uchar,
pub tzinfo: *mut PyObject,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct PyDateTime_Delta {
pub ob_base: PyObject,
pub hashcode: Py_hash_t,
pub days: c_int,
pub seconds: c_int,
pub microseconds: c_int,
}
// C API Capsule
// Note: This is "roll-your-own" lazy-static implementation is necessary because
// of the interaction between the call_once locks and the GIL. It turns out that
// calling PyCapsule_Import releases and re-acquires the GIL during the import,
// so if you have two threads attempting to use the PyDateTimeAPI singleton
// under the GIL, it causes a deadlock; what happens is:
//
// Thread 1 acquires GIL
// Thread 1 acquires the call_once lock
// Thread 1 calls PyCapsule_Import, thus releasing the GIL
// Thread 2 acquires the GIL
// Thread 2 blocks waiting for the call_once lock
// Thread 1 blocks waiting for the GIL
//
// However, Python's import mechanism acquires a module-specific lock around
// each import call, so all call importing datetime will return the same
// object, making the call_once lock superfluous. As such, we can weaken
// the guarantees of the cache, such that PyDateTime_IMPORT can be called
// until __PY_DATETIME_API_UNSAFE_CACHE is populated, which will happen exactly
// one time. So long as PyDateTime_IMPORT has no side effects (it should not),
// this will be at most a slight waste of resources.
static PY_DATETIME_API_ONCE: Once = Once::new();
static mut PY_DATETIME_API_UNSAFE_CACHE: *const PyDateTime_CAPI = ptr::null();
pub struct PyDateTimeAPI {
__private_field: (),
}
pub static PyDateTimeAPI: PyDateTimeAPI = PyDateTimeAPI {
__private_field: (),
};
impl Deref for PyDateTimeAPI {
type Target = PyDateTime_CAPI;
fn deref(&self) -> &'static PyDateTime_CAPI {
unsafe {
if !PY_DATETIME_API_UNSAFE_CACHE.is_null() {
&(*PY_DATETIME_API_UNSAFE_CACHE)
} else {
PyDateTime_IMPORT()
}
}
}
}
#[inline]
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();
let capsule = PyCapsule_Import(PyDateTime_CAPSULE_NAME.as_ptr(), 1) as *const PyDateTime_CAPI;
PY_DATETIME_API_ONCE.call_once(move || {
PY_DATETIME_API_UNSAFE_CACHE = capsule;
});
&(*PY_DATETIME_API_UNSAFE_CACHE)
}
//
// Type Check macros
//
#[inline]
pub unsafe fn PyDate_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.DateType) as c_int
}
#[inline]
pub unsafe fn PyDate_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == PyDateTimeAPI.DateType) as c_int
}
#[inline]
pub unsafe fn PyDateTime_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.DateTimeType) as c_int
}
#[inline]
pub unsafe fn PyDateTime_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == PyDateTimeAPI.DateTimeType) as c_int
}
#[inline]
pub unsafe fn PyTime_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.TimeType) as c_int
}
#[inline]
pub unsafe fn PyTime_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == PyDateTimeAPI.TimeType) as c_int
}
#[inline]
pub unsafe fn PyDelta_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.DeltaType) as c_int
}
#[inline]
pub unsafe fn PyDelta_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == PyDateTimeAPI.DeltaType) as c_int
}
#[inline]
pub unsafe fn PyTZInfo_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, PyDateTimeAPI.TZInfoType) as c_int
}
#[inline]
pub unsafe fn PyTZInfo_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == PyDateTimeAPI.TZInfoType) as c_int
}
//
// Accessor functions
//
macro_rules! _access_field {
($obj:expr, $type: ident, $field:tt) => {
(*($obj as *mut $type)).$field
};
}
// Accessor functions for PyDateTime_Date and PyDateTime_DateTime
#[inline]
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);
(c_int::from(d.data[0]) << 8 | c_int::from(d.data[1]))
}
#[inline]
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]
pub unsafe fn PyDateTime_GET_DAY(o: *mut PyObject) -> c_int {
let d = *(o as *mut PyDateTime_Date);
c_int::from(d.data[3])
}
// Accessor macros for times
macro_rules! _PyDateTime_GET_HOUR {
($o: expr, $offset:expr) => {
c_int::from((*$o).data[$offset + 0])
};
}
macro_rules! _PyDateTime_GET_MINUTE {
($o: expr, $offset:expr) => {
c_int::from((*$o).data[$offset + 1])
};
}
macro_rules! _PyDateTime_GET_SECOND {
($o: expr, $offset:expr) => {
c_int::from((*$o).data[$offset + 2])
};
}
macro_rules! _PyDateTime_GET_MICROSECOND {
($o: expr, $offset:expr) => {
(c_int::from((*$o).data[$offset + 3]) << 16)
| (c_int::from((*$o).data[$offset + 4]) << 8)
| (c_int::from((*$o).data[$offset + 5]))
};
}
#[cfg(Py_3_6)]
macro_rules! _PyDateTime_GET_FOLD {
($o: expr) => {
(*$o).fold
};
}
macro_rules! _PyDateTime_GET_TZINFO {
($o: expr) => {
(*$o).tzinfo
};
}
// Accessor functions for DateTime
#[inline]
pub unsafe fn PyDateTime_DATE_GET_HOUR(o: *mut PyObject) -> c_int {
_PyDateTime_GET_HOUR!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
}
#[inline]
pub unsafe fn PyDateTime_DATE_GET_MINUTE(o: *mut PyObject) -> c_int {
_PyDateTime_GET_MINUTE!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
}
#[inline]
pub unsafe fn PyDateTime_DATE_GET_SECOND(o: *mut PyObject) -> c_int {
_PyDateTime_GET_SECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
}
#[inline]
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]
pub unsafe fn PyDateTime_DATE_GET_FOLD(o: *mut PyObject) -> c_uchar {
_PyDateTime_GET_FOLD!(o as *mut PyDateTime_DateTime)
}
#[inline]
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]
pub unsafe fn PyDateTime_TIME_GET_HOUR(o: *mut PyObject) -> c_int {
_PyDateTime_GET_HOUR!((o as *mut PyDateTime_Time), 0)
}
#[inline]
pub unsafe fn PyDateTime_TIME_GET_MINUTE(o: *mut PyObject) -> c_int {
_PyDateTime_GET_MINUTE!((o as *mut PyDateTime_Time), 0)
}
#[inline]
pub unsafe fn PyDateTime_TIME_GET_SECOND(o: *mut PyObject) -> c_int {
_PyDateTime_GET_SECOND!((o as *mut PyDateTime_Time), 0)
}
#[inline]
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]
pub unsafe fn PyDateTime_TIME_GET_FOLD(o: *mut PyObject) -> c_uchar {
_PyDateTime_GET_FOLD!(o as *mut PyDateTime_Time)
}
#[inline]
pub unsafe fn PyDateTime_TIME_GET_TZINFO(o: *mut PyObject) -> *mut PyObject {
_PyDateTime_GET_TZINFO!(o as *mut PyDateTime_Time)
}
// Accessor functions for PyDateTime_Delta
macro_rules! _access_delta_field {
($obj:expr, $field:tt) => {
_access_field!($obj, PyDateTime_Delta, $field)
};
}
#[inline]
pub unsafe fn PyDateTime_DELTA_GET_DAYS(o: *mut PyObject) -> c_int {
_access_delta_field!(o, days)
}
#[inline]
pub unsafe fn PyDateTime_DELTA_GET_SECONDS(o: *mut PyObject) -> c_int {
_access_delta_field!(o, seconds)
}
#[inline]
pub unsafe fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int {
_access_delta_field!(o, microseconds)
}

11
src/ffi/mod.rs Normal file
View File

@ -0,0 +1,11 @@
#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]
#[cfg(not(Py_3))]
pub use ffi2::*;
#[cfg(Py_3)]
pub use ffi3::*;
pub use self::datetime::*;
pub(crate) mod datetime;

View File

@ -12,18 +12,18 @@ extern "C" {
pub fn PyBool_FromLong(arg1: c_long) -> *mut PyObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyBool_Check(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyBool_Type;
(Py_TYPE(op) == u) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn Py_False() -> *mut PyObject {
&mut _Py_ZeroStruct as *mut PyBoolObject as *mut PyObject
}
#[inline(always)]
#[inline]
pub unsafe fn Py_True() -> *mut PyObject {
&mut _Py_TrueStruct as *mut PyBoolObject as *mut PyObject
}

View File

@ -7,7 +7,7 @@ extern "C" {
pub static mut PyBuffer_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyBuffer_Check(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyBuffer_Type;
(Py_TYPE(op) == u) as c_int

View File

@ -42,7 +42,7 @@ extern "C" {
pub fn PyByteArray_Resize(bytearray: *mut PyObject, len: Py_ssize_t) -> c_int;
}
#[inline(always)]
#[inline]
pub unsafe fn PyByteArray_AS_STRING(o: *mut PyObject) -> *mut c_char {
PyByteArray_AsString(o)
// #define PyByteArray_AS_STRING(self) \
@ -50,7 +50,7 @@ pub unsafe fn PyByteArray_AS_STRING(o: *mut PyObject) -> *mut c_char {
// Py_SIZE(self) ? ((PyByteArrayObject *)(self))->ob_bytes : _PyByteArray_empty_string)
}
#[inline(always)]
#[inline]
pub unsafe fn PyByteArray_GET_SIZE(o: *mut PyObject) -> Py_ssize_t {
// #define PyByteArray_GET_SIZE(self) (assert(PyByteArray_Check(self)),Py_SIZE(self))
PyByteArray_Size(o)

View File

@ -19,7 +19,7 @@ extern "C" {
pub static mut PyCell_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyCell_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyCell_Type) as c_int
}
@ -31,12 +31,12 @@ extern "C" {
pub fn PyCell_Set(op: *mut PyObject, obj: *mut PyObject) -> c_int;
}
#[inline(always)]
#[inline]
pub unsafe fn PyCell_GET(op: *mut PyObject) -> *mut PyObject {
(*(op as *mut PyCellObject)).ob_ref
}
#[inline(always)]
#[inline]
pub unsafe fn PyCell_SET(op: *mut PyObject, obj: *mut PyObject) {
(*(op as *mut PyCellObject)).ob_ref = obj;
}

View File

@ -56,19 +56,19 @@ extern "C" {
pub static mut PyMethod_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyClass_Check(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyClass_Type;
(Py_TYPE(op) == u) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyInstance_Check(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyInstance_Type;
(Py_TYPE(op) == u) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyMethod_Check(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyMethod_Type;
(Py_TYPE(op) == u) as c_int
@ -100,17 +100,17 @@ extern "C" {
pub fn PyMethod_ClearFreeList() -> c_int;
}
#[inline(always)]
#[inline]
pub unsafe fn PyMethod_GET_FUNCTION(meth: *mut PyObject) -> *mut PyObject {
(*(meth as *mut PyMethodObject)).im_func
}
#[inline(always)]
#[inline]
pub unsafe fn PyMethod_GET_SELF(meth: *mut PyObject) -> *mut PyObject {
(*(meth as *mut PyMethodObject)).im_self
}
#[inline(always)]
#[inline]
pub unsafe fn PyMethod_GET_CLASS(meth: *mut PyObject) -> *mut PyObject {
(*(meth as *mut PyMethodObject)).im_class
}

View File

@ -6,7 +6,7 @@ extern "C" {
pub static mut PyCObject_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyCObject_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyCObject_Type) as c_int
}

View File

@ -88,7 +88,7 @@ extern "C" {
) -> *mut PyObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyCode_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyCode_Type) as c_int
}

View File

@ -37,12 +37,12 @@ extern "C" {
pub static mut PyComplex_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyComplex_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyComplex_Type)
}
#[inline(always)]
#[inline]
pub unsafe fn PyComplex_CheckExact(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyComplex_Type;
(Py_TYPE(op) == u) as c_int

View File

@ -86,7 +86,7 @@ extern "C" {
) -> *mut PyObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyDescr_IsData(d: *mut PyObject) -> c_int {
(*Py_TYPE(d)).tp_descr_set.is_some() as c_int
}

View File

@ -15,12 +15,12 @@ extern "C" {
pub static mut PyDictValues_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyDict_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_DICT_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyDict_CheckExact(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyDict_Type;
(Py_TYPE(op) == u) as c_int

View File

@ -7,12 +7,12 @@ extern "C" {
pub static mut PyFile_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyFile_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyFile_Type)
}
#[inline(always)]
#[inline]
pub unsafe fn PyFile_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyFile_Type) as c_int
}

View File

@ -19,12 +19,12 @@ extern "C" {
pub static mut PyFloat_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyFloat_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyFloat_Type)
}
#[inline(always)]
#[inline]
pub unsafe fn PyFloat_CheckExact(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyFloat_Type;
(Py_TYPE(op) == u) as c_int

View File

@ -6,7 +6,7 @@ extern "C" {
pub static mut PyFunction_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyFunction_Check(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyFunction_Type;
(Py_TYPE(op) == u) as c_int

View File

@ -23,12 +23,12 @@ extern "C" {
pub static mut PyGen_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyGen_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyGen_Type)
}
#[inline(always)]
#[inline]
pub unsafe fn PyGen_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyGen_Type) as c_int
}

View File

@ -20,12 +20,12 @@ extern "C" {
pub static mut PyInt_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyInt_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_INT_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyInt_CheckExact(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyInt_Type;
(Py_TYPE(op) == u) as c_int

View File

@ -10,12 +10,12 @@ extern "C" {
pub fn PyCallIter_New(arg1: *mut PyObject, arg2: *mut PyObject) -> *mut PyObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PySeqIter_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PySeqIter_Type) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyCallIter_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyCallIter_Type) as c_int
}

View File

@ -21,30 +21,30 @@ extern "C" {
pub static mut PyList_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyList_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LIST_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyList_CheckExact(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyList_Type;
(Py_TYPE(op) == u) as c_int
}
// Macro, trading safety for speed
#[inline(always)]
#[inline]
pub unsafe fn PyList_GET_ITEM(op: *mut PyObject, i: Py_ssize_t) -> *mut PyObject {
*(*(op as *mut PyListObject)).ob_item.offset(i as isize)
}
#[inline(always)]
#[inline]
pub unsafe fn PyList_GET_SIZE(op: *mut PyObject) -> Py_ssize_t {
Py_SIZE(op)
}
/// Macro, *only* to be used to fill in brand new lists
#[inline(always)]
#[inline]
pub unsafe fn PyList_SET_ITEM(op: *mut PyObject, i: Py_ssize_t, v: *mut PyObject) {
*(*(op as *mut PyListObject)).ob_item.offset(i as isize) = v;
}

View File

@ -12,12 +12,12 @@ extern "C" {
pub static mut PyLong_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyLong_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LONG_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyLong_CheckExact(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyLong_Type;
(Py_TYPE(op) == u) as c_int

View File

@ -7,18 +7,18 @@ extern "C" {
pub static mut PyMemoryView_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyMemoryView_Check(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyMemoryView_Type;
(Py_TYPE(op) == u) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyMemoryView_GET_BUFFER(op: *mut PyObject) -> *mut Py_buffer {
&mut (*(op as *mut PyMemoryViewObject)).view
}
#[inline(always)]
#[inline]
pub unsafe fn PyMemoryView_GET_BASE(op: *mut PyObject) -> *mut PyObject {
(*(op as *mut PyMemoryViewObject)).view.obj
}

View File

@ -7,7 +7,7 @@ extern "C" {
pub static mut PyCFunction_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyCFunction_Check(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyCFunction_Type;
(Py_TYPE(op) == u) as c_int
@ -119,7 +119,7 @@ extern "C" {
pub fn PyCFunction_ClearFreeList() -> c_int;
}
#[inline(always)]
#[inline]
pub unsafe fn PyCFunction_New(ml: *mut PyMethodDef, slf: *mut PyObject) -> *mut PyObject {
PyCFunction_NewEx(ml, slf, ptr::null_mut())
}

View File

@ -132,13 +132,13 @@ pub const Py_file_input: c_int = 257;
pub const Py_eval_input: c_int = 258;
#[cfg(not(py_sys_config = "Py_USING_UNICODE"))]
#[inline(always)]
#[inline]
pub fn PyUnicode_Check(op: *mut PyObject) -> libc::c_int {
0
}
#[cfg(not(py_sys_config = "Py_USING_UNICODE"))]
#[inline(always)]
#[inline]
pub fn PyUnicode_CheckExact(op: *mut PyObject) -> libc::c_int {
0
}

View File

@ -95,7 +95,7 @@ pub const PYTHON_API_VERSION: c_int = 1013;
target_pointer_width = "64",
not(py_sys_config = "Py_TRACE_REFS")
))]
#[inline(always)]
#[inline]
pub unsafe fn Py_InitModule4(
name: *const c_char,
methods: *mut PyMethodDef,
@ -107,7 +107,7 @@ pub unsafe fn Py_InitModule4(
}
#[cfg(all(target_pointer_width = "64", py_sys_config = "Py_TRACE_REFS"))]
#[inline(always)]
#[inline]
pub unsafe fn Py_InitModule4(
name: *const c_char,
methods: *mut PyMethodDef,
@ -122,7 +122,7 @@ pub unsafe fn Py_InitModule4(
not(target_pointer_width = "64"),
py_sys_config = "Py_TRACE_REFS"
))]
#[inline(always)]
#[inline]
pub unsafe fn Py_InitModule4(
name: *const c_char,
methods: *mut PyMethodDef,
@ -133,7 +133,7 @@ pub unsafe fn Py_InitModule4(
Py_InitModule4TraceRefs(name, methods, doc, _self, apiver)
}
#[inline(always)]
#[inline]
pub unsafe fn Py_InitModule(name: *const c_char, methods: *mut PyMethodDef) -> *mut PyObject {
Py_InitModule4(
name,
@ -144,7 +144,7 @@ pub unsafe fn Py_InitModule(name: *const c_char, methods: *mut PyMethodDef) -> *
)
}
#[inline(always)]
#[inline]
pub unsafe fn Py_InitModule3(
name: *const c_char,
methods: *mut PyMethodDef,

View File

@ -8,12 +8,12 @@ extern "C" {
pub static mut PyModule_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyModule_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyModule_Type)
}
#[inline(always)]
#[inline]
pub unsafe fn PyModule_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyModule_Type) as c_int
}

View File

@ -6,7 +6,7 @@ use std::os::raw::{c_char, c_double, c_int, c_long, c_uint, c_void};
use std::ptr;
#[repr(C)]
#[derive(Copy, Clone)]
#[derive(Debug, Copy, Clone)]
pub struct PyObject {
#[cfg(py_sys_config = "Py_TRACE_REFS")]
pub _ob_next: *mut PyObject,
@ -37,17 +37,17 @@ pub struct PyVarObject {
pub ob_size: Py_ssize_t,
}
#[inline(always)]
#[inline]
pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t {
(*ob).ob_refcnt
}
#[inline(always)]
#[inline]
pub unsafe fn Py_TYPE(ob: *mut PyObject) -> *mut PyTypeObject {
(*ob).ob_type
}
#[inline(always)]
#[inline]
pub unsafe fn Py_SIZE(ob: *mut PyObject) -> Py_ssize_t {
(*(ob as *mut PyVarObject)).ob_size
}
@ -564,7 +564,7 @@ extern "C" {
pub fn PyType_IsSubtype(a: *mut PyTypeObject, b: *mut PyTypeObject) -> c_int;
}
#[inline(always)]
#[inline]
pub unsafe fn PyObject_TypeCheck(ob: *mut PyObject, tp: *mut PyTypeObject) -> c_int {
(Py_TYPE(ob) == tp || PyType_IsSubtype(Py_TYPE(ob), tp) != 0) as c_int
}
@ -576,12 +576,12 @@ extern "C" {
pub static mut PySuper_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyType_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyType_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == (&mut PyType_Type as *mut _)) as c_int
}
@ -611,7 +611,7 @@ extern "C" {
pub fn PyObject_Str(o: *mut PyObject) -> *mut PyObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyObject_Bytes(o: *mut PyObject) -> *mut PyObject {
PyObject_Str(o)
}
@ -755,18 +755,18 @@ pub const Py_TPFLAGS_DEFAULT: c_long = (Py_TPFLAGS_HAVE_GETCHARBUFFER
| Py_TPFLAGS_HAVE_INDEX
| 0);
#[inline(always)]
#[inline]
pub unsafe fn PyType_HasFeature(t: *mut PyTypeObject, f: c_long) -> c_int {
(((*t).tp_flags & f) != 0) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyType_FastSubclass(t: *mut PyTypeObject, f: c_long) -> c_int {
PyType_HasFeature(t, f)
}
// Reference counting macros.
#[inline(always)]
#[inline]
pub unsafe fn Py_INCREF(op: *mut PyObject) {
if cfg!(py_sys_config = "Py_REF_DEBUG") {
Py_IncRef(op)
@ -775,7 +775,7 @@ pub unsafe fn Py_INCREF(op: *mut PyObject) {
}
}
#[inline(always)]
#[inline]
pub unsafe fn Py_DECREF(op: *mut PyObject) {
if cfg!(py_sys_config = "Py_REF_DEBUG") || cfg!(py_sys_config = "COUNT_ALLOCS") {
Py_DecRef(op)
@ -787,7 +787,7 @@ pub unsafe fn Py_DECREF(op: *mut PyObject) {
}
}
#[inline(always)]
#[inline]
pub unsafe fn Py_CLEAR(op: &mut *mut PyObject) {
let tmp = *op;
if !tmp.is_null() {
@ -796,14 +796,14 @@ pub unsafe fn Py_CLEAR(op: &mut *mut PyObject) {
}
}
#[inline(always)]
#[inline]
pub unsafe fn Py_XINCREF(op: *mut PyObject) {
if !op.is_null() {
Py_INCREF(op)
}
}
#[inline(always)]
#[inline]
pub unsafe fn Py_XDECREF(op: *mut PyObject) {
if !op.is_null() {
Py_DECREF(op)
@ -819,12 +819,12 @@ extern "C" {
static mut _Py_NotImplementedStruct: PyObject;
}
#[inline(always)]
#[inline]
pub unsafe fn Py_None() -> *mut PyObject {
&mut _Py_NoneStruct
}
#[inline(always)]
#[inline]
pub unsafe fn Py_NotImplemented() -> *mut PyObject {
&mut _Py_NotImplementedStruct
}
@ -855,7 +855,7 @@ extern "C" {
pub const PyTrash_UNWIND_LEVEL: c_int = 50;
#[inline(always)]
#[inline]
pub unsafe fn Py_TRASHCAN<F: FnOnce() -> ()>(op: *mut PyObject, body: F) {
let tstate = ffi2::pystate::PyThreadState_GET();
if tstate.is_null() || (*tstate).trash_delete_nesting < PyTrash_UNWIND_LEVEL {

View File

@ -30,14 +30,14 @@ extern "C" {
}
/// Test if a type has a GC head
#[inline(always)]
#[inline]
#[allow(unused_parens)]
pub unsafe fn PyType_IS_GC(t: *mut PyTypeObject) -> c_int {
PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)
}
/// Test if an object has a GC head
#[inline(always)]
#[inline]
pub unsafe fn PyObject_IS_GC(o: *mut PyObject) -> c_int {
(PyType_IS_GC(Py_TYPE(o)) != 0 && match (*Py_TYPE(o)).tp_is_gc {
Some(tp_is_gc) => tp_is_gc(o) != 0,
@ -46,13 +46,13 @@ pub unsafe fn PyObject_IS_GC(o: *mut PyObject) -> c_int {
}
/* Test if a type supports weak references */
#[inline(always)]
#[inline]
#[allow(unused_parens)]
pub unsafe fn PyType_SUPPORTS_WEAKREFS(t: *mut PyTypeObject) -> c_int {
(PyType_HasFeature((t), Py_TPFLAGS_HAVE_WEAKREFS) != 0 && ((*t).tp_weaklistoffset > 0)) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyObject_GET_WEAKREFS_LISTPTR(o: *mut PyObject) -> *mut *mut PyObject {
let weaklistoffset = (*Py_TYPE(o)).tp_weaklistoffset as isize;
(o as *mut c_char).offset(weaklistoffset) as *mut *mut PyObject

View File

@ -92,13 +92,13 @@ extern "C" {
}
#[cfg(py_sys_config = "Py_DEBUG")]
#[inline(always)]
#[inline]
pub unsafe fn PyThreadState_GET() -> *mut PyThreadState {
PyThreadState_Get()
}
#[cfg(not(py_sys_config = "Py_DEBUG"))]
#[inline(always)]
#[inline]
pub unsafe fn PyThreadState_GET() -> *mut PyThreadState {
_PyThreadState_Current
}

View File

@ -6,7 +6,7 @@ extern "C" {
pub static mut PyRange_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyRange_Check(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyRange_Type;
(Py_TYPE(op) == u) as c_int

View File

@ -7,7 +7,7 @@ extern "C" {
static mut _Py_EllipsisObject: PyObject;
}
#[inline(always)]
#[inline]
pub unsafe fn Py_Ellipsis() -> *mut PyObject {
&mut _Py_EllipsisObject
}
@ -32,7 +32,7 @@ extern "C" {
pub static mut PyEllipsis_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PySlice_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PySlice_Type) as c_int
}

View File

@ -23,12 +23,12 @@ extern "C" {
pub static mut PyString_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyString_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_STRING_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyBaseString_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(
Py_TYPE(op),
@ -36,18 +36,18 @@ pub unsafe fn PyBaseString_Check(op: *mut PyObject) -> c_int {
)
}
#[inline(always)]
#[inline]
pub unsafe fn PyString_CheckExact(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyString_Type;
(Py_TYPE(op) == u) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyString_GET_SIZE(op: *mut PyObject) -> Py_ssize_t {
(*(op as *mut PyStringObject)).ob_size
}
#[inline(always)]
#[inline]
pub unsafe fn PyString_AS_STRING(op: *mut PyObject) -> *mut c_char {
(*(op as *mut PyStringObject)).ob_sval.as_mut_ptr()
}

View File

@ -26,7 +26,7 @@ extern "C" {
pub static mut PyTraceBack_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyTraceBack_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyTraceBack_Type) as c_int
}

View File

@ -20,19 +20,19 @@ extern "C" {
pub static mut PyTuple_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyTuple_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TUPLE_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyTuple_CheckExact(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyTuple_Type;
(Py_TYPE(op) == u) as c_int
}
// Macro, trading safety for speed
#[inline(always)]
#[inline]
pub unsafe fn PyTuple_GET_ITEM(op: *mut PyObject, i: Py_ssize_t) -> *mut PyObject {
*(*(op as *mut PyTupleObject))
.ob_item
@ -40,13 +40,13 @@ pub unsafe fn PyTuple_GET_ITEM(op: *mut PyObject, i: Py_ssize_t) -> *mut PyObjec
.offset(i as isize)
}
#[inline(always)]
#[inline]
pub unsafe fn PyTuple_GET_SIZE(op: *mut PyObject) -> Py_ssize_t {
Py_SIZE(op)
}
/// Macro, *only* to be used to fill in brand new tuples
#[inline(always)]
#[inline]
pub unsafe fn PyTuple_SET_ITEM(op: *mut PyObject, i: Py_ssize_t, v: *mut PyObject) {
*(*(op as *mut PyTupleObject))
.ob_item

View File

@ -35,33 +35,33 @@ extern "C" {
pub static mut PyUnicode_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyUnicode_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_UNICODE_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyUnicode_CheckExact(op: *mut PyObject) -> c_int {
let u: *mut PyTypeObject = &mut PyUnicode_Type;
(Py_TYPE(op) == u) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyUnicode_GET_SIZE(o: *mut PyObject) -> Py_ssize_t {
(*(o as *mut PyUnicodeObject)).length
}
#[inline(always)]
#[inline]
pub unsafe fn PyUnicode_GET_DATA_SIZE(o: *mut PyObject) -> Py_ssize_t {
(*(o as *mut PyUnicodeObject)).length * Py_UNICODE_SIZE
}
#[inline(always)]
#[inline]
pub unsafe fn PyUnicode_AS_UNICODE(o: *mut PyObject) -> *mut Py_UNICODE {
(*(o as *mut PyUnicodeObject)).data
}
#[inline(always)]
#[inline]
pub unsafe fn PyUnicode_AS_DATA(o: *mut PyObject) -> *const c_char {
(*(o as *mut PyUnicodeObject)).data as *const c_char
}
@ -642,31 +642,31 @@ extern "C" {
fn _PyUnicodeUCS2_IsAlpha(ch: Py_UNICODE) -> c_int;
}
#[inline(always)]
#[inline]
#[cfg(py_sys_config = "Py_UNICODE_SIZE_4")]
pub unsafe fn PyUnicode_FromStringAndSize(u: *const c_char, size: Py_ssize_t) -> *mut PyObject {
PyUnicodeUCS4_FromStringAndSize(u, size)
}
#[inline(always)]
#[inline]
#[cfg(not(py_sys_config = "Py_UNICODE_SIZE_4"))]
pub unsafe fn PyUnicode_FromStringAndSize(u: *const c_char, size: Py_ssize_t) -> *mut PyObject {
PyUnicodeUCS2_FromStringAndSize(u, size)
}
#[inline(always)]
#[inline]
#[cfg(py_sys_config = "Py_UNICODE_SIZE_4")]
pub unsafe fn PyUnicode_AsUTF8String(u: *mut PyObject) -> *mut PyObject {
PyUnicodeUCS4_AsUTF8String(u)
}
#[inline(always)]
#[inline]
#[cfg(not(py_sys_config = "Py_UNICODE_SIZE_4"))]
pub unsafe fn PyUnicode_AsUTF8String(u: *mut PyObject) -> *mut PyObject {
PyUnicodeUCS2_AsUTF8String(u)
}
#[inline(always)]
#[inline]
#[cfg(py_sys_config = "Py_UNICODE_SIZE_4")]
pub unsafe fn PyUnicode_FromEncodedObject(
obj: *mut PyObject,
@ -676,7 +676,7 @@ pub unsafe fn PyUnicode_FromEncodedObject(
PyUnicodeUCS4_FromEncodedObject(obj, encoding, errors)
}
#[inline(always)]
#[inline]
#[cfg(not(py_sys_config = "Py_UNICODE_SIZE_4"))]
pub unsafe fn PyUnicode_FromEncodedObject(
obj: *mut PyObject,

View File

@ -25,23 +25,23 @@ extern "C" {
static mut _PyWeakref_CallableProxyType: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyWeakref_CheckRef(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut _PyWeakref_RefType)
}
#[inline(always)]
#[inline]
pub unsafe fn PyWeakref_CheckRefExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut _PyWeakref_RefType) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyWeakref_CheckProxy(op: *mut PyObject) -> c_int {
((Py_TYPE(op) == &mut _PyWeakref_ProxyType)
|| (Py_TYPE(op) == &mut _PyWeakref_CallableProxyType)) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyWeakref_Check(op: *mut PyObject) -> c_int {
(PyWeakref_CheckRef(op) != 0 || PyWeakref_CheckProxy(op) != 0) as c_int
}
@ -56,7 +56,7 @@ extern "C" {
pub fn _PyWeakref_ClearRef(slf: *mut PyWeakReference);
}
#[inline(always)]
#[inline]
pub unsafe fn PyWeakref_GET_OBJECT(_ref: *mut PyObject) -> *mut PyObject {
let obj = (*(_ref as *mut PyWeakReference)).wr_object;
if Py_REFCNT(obj) > 0 {

View File

@ -10,17 +10,17 @@ extern "C" {
pub fn PyBool_FromLong(arg1: c_long) -> *mut PyObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyBool_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyBool_Type) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn Py_False() -> *mut PyObject {
&mut _Py_FalseStruct as *mut PyLongObject as *mut PyObject
}
#[inline(always)]
#[inline]
pub unsafe fn Py_True() -> *mut PyObject {
&mut _Py_TrueStruct as *mut PyLongObject as *mut PyObject
}

View File

@ -8,12 +8,12 @@ extern "C" {
pub static mut PyByteArrayIter_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyByteArray_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyByteArray_Type)
}
#[inline(always)]
#[inline]
pub unsafe fn PyByteArray_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyByteArray_Type) as c_int
}

View File

@ -8,12 +8,12 @@ extern "C" {
pub static mut PyBytesIter_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyBytes_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_BYTES_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyBytes_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyBytes_Type) as c_int
}

View File

@ -6,12 +6,12 @@ extern "C" {
pub static mut PyComplex_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyComplex_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyComplex_Type)
}
#[inline(always)]
#[inline]
pub unsafe fn PyComplex_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyComplex_Type) as c_int
}

View File

@ -13,32 +13,32 @@ extern "C" {
pub static mut PyDictValues_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyDict_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_DICT_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyDict_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyDict_Type) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyDictKeys_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyDictKeys_Type) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyDictItems_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyDictItems_Type) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyDictValues_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyDictValues_Type) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyDictViewSet_Check(op: *mut PyObject) -> c_int {
(PyDictKeys_Check(op) != 0 || PyDictItems_Check(op) != 0) as c_int
}

View File

@ -6,12 +6,12 @@ extern "C" {
pub static mut PyFloat_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyFloat_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyFloat_Type)
}
#[inline(always)]
#[inline]
pub unsafe fn PyFloat_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyFloat_Type) as c_int
}

View File

@ -23,12 +23,12 @@ extern "C" {
pub static mut PyGen_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyGen_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyGen_Type)
}
#[inline(always)]
#[inline]
pub unsafe fn PyGen_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyGen_Type) as c_int
}
@ -44,7 +44,7 @@ extern "C" {
pub static mut PyCoro_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyCoro_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyCoro_Type)
}
@ -54,7 +54,7 @@ extern "C" {
pub static mut _PyCoroWrapper_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyCoroWrapper_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut _PyCoroWrapper_Type)
}
@ -66,13 +66,13 @@ extern "C" {
}
#[cfg(Py_3_6)]
#[inline(always)]
#[inline]
pub unsafe fn PyAsyncGen_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyAsyncGen_Type)
}
#[cfg(not(Py_3_6))]
#[inline(always)]
#[inline]
pub unsafe fn PyAsyncGen_Check(_op: *mut PyObject) -> c_int {
0
}

View File

@ -10,12 +10,12 @@ extern "C" {
pub fn PyCallIter_New(arg1: *mut PyObject, arg2: *mut PyObject) -> *mut PyObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PySeqIter_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PySeqIter_Type) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyCallIter_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyCallIter_Type) as c_int
}

View File

@ -9,12 +9,12 @@ extern "C" {
pub static mut PyListRevIter_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyList_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LIST_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyList_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyList_Type) as c_int
}

View File

@ -12,12 +12,12 @@ extern "C" {
pub static mut PyLong_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyLong_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LONG_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyLong_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyLong_Type) as c_int
}

View File

@ -7,7 +7,7 @@ extern "C" {
pub static mut PyMemoryView_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyMemoryView_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyMemoryView_Type) as c_int
}

View File

@ -7,7 +7,7 @@ extern "C" {
pub static mut PyCFunction_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyCFunction_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyCFunction_Type) as c_int
}
@ -63,7 +63,7 @@ impl Default for PyMethodDef {
}
}
#[inline(always)]
#[inline]
pub unsafe fn PyCFunction_New(ml: *mut PyMethodDef, slf: *mut PyObject) -> *mut PyObject {
PyCFunction_NewEx(ml, slf, ptr::null_mut())
}

View File

@ -8,12 +8,12 @@ extern "C" {
pub static mut PyModule_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyModule_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut PyModule_Type)
}
#[inline(always)]
#[inline]
pub unsafe fn PyModule_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyModule_Type) as c_int
}

View File

@ -34,7 +34,7 @@ pub struct PyVarObject {
pub ob_size: Py_ssize_t,
}
#[inline(always)]
#[inline]
pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t {
if ob.is_null() {
panic!();
@ -42,12 +42,12 @@ pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t {
(*ob).ob_refcnt
}
#[inline(always)]
#[inline]
pub unsafe fn Py_TYPE(ob: *mut PyObject) -> *mut PyTypeObject {
(*ob).ob_type
}
#[inline(always)]
#[inline]
pub unsafe fn Py_SIZE(ob: *mut PyObject) -> Py_ssize_t {
(*(ob as *mut PyVarObject)).ob_size
}
@ -616,7 +616,7 @@ extern "C" {
pub fn PyType_IsSubtype(a: *mut PyTypeObject, b: *mut PyTypeObject) -> c_int;
}
#[inline(always)]
#[inline]
pub unsafe fn PyObject_TypeCheck(ob: *mut PyObject, tp: *mut PyTypeObject) -> c_int {
(Py_TYPE(ob) == tp || PyType_IsSubtype(Py_TYPE(ob), tp) != 0) as c_int
}
@ -633,12 +633,12 @@ extern "C" {
pub fn PyType_GetFlags(arg1: *mut PyTypeObject) -> c_ulong;
}
#[inline(always)]
#[inline]
pub unsafe fn PyType_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyType_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyType_Type) as c_int
}
@ -753,19 +753,19 @@ pub const Py_TPFLAGS_DEFAULT: c_ulong =
pub const Py_TPFLAGS_HAVE_FINALIZE: c_ulong = 1;
#[inline(always)]
#[inline]
#[cfg(Py_LIMITED_API)]
pub unsafe fn PyType_HasFeature(t: *mut PyTypeObject, f: c_ulong) -> c_int {
((PyType_GetFlags(t) & f) != 0) as c_int
}
#[inline(always)]
#[inline]
#[cfg(not(Py_LIMITED_API))]
pub unsafe fn PyType_HasFeature(t: *mut PyTypeObject, f: c_ulong) -> c_int {
(((*t).tp_flags & f) != 0) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyType_FastSubclass(t: *mut PyTypeObject, f: c_ulong) -> c_int {
PyType_HasFeature(t, f)
}
@ -776,7 +776,7 @@ extern "C" {
}
// Reference counting macros.
#[inline(always)]
#[inline]
pub unsafe fn Py_INCREF(op: *mut PyObject) {
if cfg!(py_sys_config = "Py_REF_DEBUG") {
Py_IncRef(op)
@ -785,7 +785,7 @@ pub unsafe fn Py_INCREF(op: *mut PyObject) {
}
}
#[inline(always)]
#[inline]
pub unsafe fn Py_DECREF(op: *mut PyObject) {
if cfg!(py_sys_config = "Py_REF_DEBUG") {
Py_DecRef(op)
@ -797,7 +797,7 @@ pub unsafe fn Py_DECREF(op: *mut PyObject) {
}
}
#[inline(always)]
#[inline]
pub unsafe fn Py_CLEAR(op: &mut *mut PyObject) {
let tmp = *op;
if !tmp.is_null() {
@ -806,14 +806,14 @@ pub unsafe fn Py_CLEAR(op: &mut *mut PyObject) {
}
}
#[inline(always)]
#[inline]
pub unsafe fn Py_XINCREF(op: *mut PyObject) {
if !op.is_null() {
Py_INCREF(op)
}
}
#[inline(always)]
#[inline]
pub unsafe fn Py_XDECREF(op: *mut PyObject) {
if !op.is_null() {
Py_DECREF(op)
@ -829,12 +829,12 @@ extern "C" {
static mut _Py_NotImplementedStruct: PyObject;
}
#[inline(always)]
#[inline]
pub unsafe fn Py_None() -> *mut PyObject {
&mut _Py_NoneStruct
}
#[inline(always)]
#[inline]
pub unsafe fn Py_NotImplemented() -> *mut PyObject {
&mut _Py_NotImplementedStruct
}

View File

@ -48,14 +48,14 @@ extern "C" {
}
/// Test if a type has a GC head
#[inline(always)]
#[inline]
#[allow(unused_parens)]
pub unsafe fn PyType_IS_GC(t: *mut PyTypeObject) -> c_int {
PyType_HasFeature(t, Py_TPFLAGS_HAVE_GC)
}
/// Test if an object has a GC head
#[inline(always)]
#[inline]
#[cfg(not(Py_LIMITED_API))]
pub unsafe fn PyObject_IS_GC(o: *mut PyObject) -> c_int {
(PyType_IS_GC(Py_TYPE(o)) != 0 && match (*Py_TYPE(o)).tp_is_gc {
@ -80,13 +80,13 @@ extern "C" {
}
/// Test if a type supports weak references
#[inline(always)]
#[inline]
#[cfg(not(Py_LIMITED_API))]
pub unsafe fn PyType_SUPPORTS_WEAKREFS(t: *mut PyTypeObject) -> c_int {
((*t).tp_weaklistoffset > 0) as c_int
}
#[inline(always)]
#[inline]
#[cfg(not(Py_LIMITED_API))]
pub unsafe fn PyObject_GET_WEAKREFS_LISTPTR(o: *mut PyObject) -> *mut *mut PyObject {
let weaklistoffset = (*Py_TYPE(o)).tp_weaklistoffset as isize;

View File

@ -58,7 +58,7 @@ extern "C" {
pub fn PyGILState_GetThisThreadState() -> *mut PyThreadState;
}
#[inline(always)]
#[inline]
pub unsafe fn PyThreadState_GET() -> *mut PyThreadState {
PyThreadState_Get()
}

View File

@ -8,7 +8,7 @@ extern "C" {
pub static mut PyLongRangeIter_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyRange_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyRange_Type) as c_int
}

View File

@ -7,7 +7,7 @@ extern "C" {
static mut _Py_EllipsisObject: PyObject;
}
#[inline(always)]
#[inline]
pub unsafe fn Py_Ellipsis() -> *mut PyObject {
&mut _Py_EllipsisObject
}
@ -18,7 +18,7 @@ extern "C" {
pub static mut PyEllipsis_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PySlice_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PySlice_Type) as c_int
}

View File

@ -8,7 +8,7 @@ extern "C" {
pub static mut PyTraceBack_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyTraceBack_Check(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyTraceBack_Type) as c_int
}

View File

@ -15,12 +15,12 @@ extern "C" {
pub static mut PyTupleIter_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyTuple_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TUPLE_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyTuple_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyTuple_Type) as c_int
}
@ -41,7 +41,7 @@ extern "C" {
}
// Macro, trading safety for speed
#[inline(always)]
#[inline]
#[cfg(not(Py_LIMITED_API))]
pub unsafe fn PyTuple_GET_ITEM(op: *mut PyObject, i: Py_ssize_t) -> *mut PyObject {
*(*(op as *mut PyTupleObject))
@ -50,14 +50,14 @@ pub unsafe fn PyTuple_GET_ITEM(op: *mut PyObject, i: Py_ssize_t) -> *mut PyObjec
.offset(i as isize)
}
#[inline(always)]
#[inline]
#[cfg(not(Py_LIMITED_API))]
pub unsafe fn PyTuple_GET_SIZE(op: *mut PyObject) -> Py_ssize_t {
Py_SIZE(op)
}
/// Macro, *only* to be used to fill in brand new tuples
#[inline(always)]
#[inline]
#[cfg(not(Py_LIMITED_API))]
pub unsafe fn PyTuple_SET_ITEM(op: *mut PyObject, i: Py_ssize_t, v: *mut PyObject) {
*(*(op as *mut PyTupleObject))

View File

@ -16,12 +16,12 @@ extern "C" {
pub static mut PyUnicodeIter_Type: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyUnicode_Check(op: *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_UNICODE_SUBCLASS)
}
#[inline(always)]
#[inline]
pub unsafe fn PyUnicode_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut PyUnicode_Type) as c_int
}

View File

@ -10,23 +10,23 @@ extern "C" {
static mut _PyWeakref_CallableProxyType: PyTypeObject;
}
#[inline(always)]
#[inline]
pub unsafe fn PyWeakref_CheckRef(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, &mut _PyWeakref_RefType)
}
#[inline(always)]
#[inline]
pub unsafe fn PyWeakref_CheckRefExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == &mut _PyWeakref_RefType) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyWeakref_CheckProxy(op: *mut PyObject) -> c_int {
((Py_TYPE(op) == &mut _PyWeakref_ProxyType)
|| (Py_TYPE(op) == &mut _PyWeakref_CallableProxyType)) as c_int
}
#[inline(always)]
#[inline]
pub unsafe fn PyWeakref_Check(op: *mut PyObject) -> c_int {
(PyWeakref_CheckRef(op) != 0 || PyWeakref_CheckProxy(op) != 0) as c_int
}

View File

@ -22,7 +22,7 @@ impl PyToken {
PyToken(PhantomData)
}
#[inline(always)]
#[inline]
pub fn py(&self) -> Python {
unsafe { Python::assume_gil_acquired() }

View File

@ -129,21 +129,15 @@ extern crate spin;
#[doc(hidden)]
pub extern crate mashup;
/// Rust FFI declarations for Python
pub mod ffi;
#[cfg(not(Py_3))]
mod ffi2;
#[cfg(Py_3)]
mod ffi3;
/// Rust FFI declarations for Python
pub mod ffi {
#[cfg(not(Py_3))]
pub use ffi2::*;
#[cfg(Py_3)]
pub use ffi3::*;
}
pub use conversion::{
FromPyObject, IntoPyObject, IntoPyTuple, PyTryFrom, PyTryInto, ReturnTypeIntoPyResult,
ToBorrowedObject, ToPyObject,

300
src/objects/datetime.rs Normal file
View File

@ -0,0 +1,300 @@
use err::PyResult;
use ffi;
use ffi::PyDateTimeAPI;
use ffi::{PyDateTime_Check, PyDateTime_DateTimeType};
use ffi::{
PyDateTime_DATE_GET_HOUR, PyDateTime_DATE_GET_MICROSECOND, PyDateTime_DATE_GET_MINUTE,
PyDateTime_DATE_GET_SECOND,
};
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 object::PyObject;
use std::os::raw::c_int;
#[cfg(Py_3_6)]
use ffi::{PyDateTime_DATE_GET_FOLD, PyDateTime_TIME_GET_FOLD};
use instance::Py;
use python::{Python, ToPyPointer};
// Traits
pub trait PyDateAccess {
fn get_year(&self) -> i32;
fn get_month(&self) -> u8;
fn get_day(&self) -> u8;
}
pub trait PyDeltaAccess {
fn get_days(&self) -> i32;
fn get_seconds(&self) -> i32;
fn get_microseconds(&self) -> i32;
}
pub trait PyTimeAccess {
fn get_hour(&self) -> u8;
fn get_minute(&self) -> u8;
fn get_second(&self) -> u8;
fn get_microsecond(&self) -> u32;
#[cfg(Py_3_6)]
fn get_fold(&self) -> u8;
}
// datetime.date bindings
pub struct PyDate(PyObject);
pyobject_native_type!(PyDate, PyDateTime_DateType, PyDate_Check);
impl PyDate {
pub fn new(py: Python, year: i32, month: u8, day: u8) -> PyResult<Py<PyDate>> {
unsafe {
let ptr = (PyDateTimeAPI.Date_FromDate)(
year as c_int,
month as c_int,
day as c_int,
PyDateTimeAPI.DateType,
);
Py::from_owned_ptr_or_err(py, ptr)
}
}
pub fn from_timestamp(py: Python, args: &PyObject) -> PyResult<Py<PyDate>> {
unsafe {
let ptr = (PyDateTimeAPI.Date_FromTimestamp)(PyDateTimeAPI.DateType, args.as_ptr());
Py::from_owned_ptr_or_err(py, ptr)
}
}
}
impl PyDateAccess for PyDate {
fn get_year(&self) -> i32 {
unsafe { PyDateTime_GET_YEAR(self.as_ptr()) as i32 }
}
fn get_month(&self) -> u8 {
unsafe { PyDateTime_GET_MONTH(self.as_ptr()) as u8 }
}
fn get_day(&self) -> u8 {
unsafe { PyDateTime_GET_DAY(self.as_ptr()) as u8 }
}
}
// datetime.datetime bindings
pub struct PyDateTime(PyObject);
pyobject_native_type!(PyDateTime, PyDateTime_DateTimeType, PyDateTime_Check);
impl PyDateTime {
pub fn new(
py: Python,
year: i32,
month: u8,
day: u8,
hour: u8,
minute: u8,
second: u8,
microsecond: u32,
tzinfo: Option<&PyObject>,
) -> PyResult<Py<PyDateTime>> {
unsafe {
let ptr = (PyDateTimeAPI.DateTime_FromDateAndTime)(
year as c_int,
month as c_int,
day as c_int,
hour as c_int,
minute as c_int,
second as c_int,
microsecond as c_int,
opt_to_pyobj(py, tzinfo),
PyDateTimeAPI.DateTimeType,
);
Py::from_owned_ptr_or_err(py, ptr)
}
}
pub fn from_timestamp(
py: Python,
args: &PyObject,
kwargs: &PyObject,
) -> PyResult<Py<PyDateTime>> {
unsafe {
let ptr = (PyDateTimeAPI.DateTime_FromTimestamp)(
PyDateTimeAPI.DateTimeType,
args.as_ptr(),
kwargs.as_ptr(),
);
Py::from_owned_ptr_or_err(py, ptr)
}
}
}
impl PyDateAccess for PyDateTime {
fn get_year(&self) -> i32 {
unsafe { PyDateTime_GET_YEAR(self.as_ptr()) as i32 }
}
fn get_month(&self) -> u8 {
unsafe { PyDateTime_GET_MONTH(self.as_ptr()) as u8 }
}
fn get_day(&self) -> u8 {
unsafe { PyDateTime_GET_DAY(self.as_ptr()) as u8 }
}
}
impl PyTimeAccess for PyDateTime {
fn get_hour(&self) -> u8 {
unsafe { PyDateTime_DATE_GET_HOUR(self.as_ptr()) as u8 }
}
fn get_minute(&self) -> u8 {
unsafe { PyDateTime_DATE_GET_MINUTE(self.as_ptr()) as u8 }
}
fn get_second(&self) -> u8 {
unsafe { PyDateTime_DATE_GET_SECOND(self.as_ptr()) as u8 }
}
fn get_microsecond(&self) -> u32 {
unsafe { PyDateTime_DATE_GET_MICROSECOND(self.as_ptr()) as u32 }
}
#[cfg(Py_3_6)]
fn get_fold(&self) -> u8 {
unsafe { PyDateTime_DATE_GET_FOLD(self.as_ptr()) as u8 }
}
}
// datetime.time
pub struct PyTime(PyObject);
pyobject_native_type!(PyTime, PyDateTime_TimeType, PyTime_Check);
impl PyTime {
pub fn new(
py: Python,
hour: u8,
minute: u8,
second: u8,
microsecond: u32,
tzinfo: Option<&PyObject>,
) -> PyResult<Py<PyTime>> {
unsafe {
let ptr = (PyDateTimeAPI.Time_FromTime)(
hour as c_int,
minute as c_int,
second as c_int,
microsecond as c_int,
opt_to_pyobj(py, tzinfo),
PyDateTimeAPI.TimeType,
);
Py::from_owned_ptr_or_err(py, ptr)
}
}
#[cfg(Py_3_6)]
pub fn new_with_fold(
py: Python,
hour: u8,
minute: u8,
second: u8,
microsecond: u32,
tzinfo: Option<&PyObject>,
fold: bool,
) -> PyResult<Py<PyTime>> {
unsafe {
let ptr = (PyDateTimeAPI.Time_FromTimeAndFold)(
hour as c_int,
minute as c_int,
second as c_int,
microsecond as c_int,
opt_to_pyobj(py, tzinfo),
fold as c_int,
PyDateTimeAPI.TimeType,
);
Py::from_owned_ptr_or_err(py, ptr)
}
}
}
impl PyTimeAccess for PyTime {
fn get_hour(&self) -> u8 {
unsafe { PyDateTime_TIME_GET_HOUR(self.as_ptr()) as u8 }
}
fn get_minute(&self) -> u8 {
unsafe { PyDateTime_TIME_GET_MINUTE(self.as_ptr()) as u8 }
}
fn get_second(&self) -> u8 {
unsafe { PyDateTime_TIME_GET_SECOND(self.as_ptr()) as u8 }
}
fn get_microsecond(&self) -> u32 {
unsafe { PyDateTime_TIME_GET_MICROSECOND(self.as_ptr()) as u32 }
}
#[cfg(Py_3_6)]
fn get_fold(&self) -> u8 {
unsafe { PyDateTime_TIME_GET_FOLD(self.as_ptr()) as u8 }
}
}
// datetime.tzinfo bindings
pub struct PyTzInfo(PyObject);
pyobject_native_type!(PyTzInfo, PyDateTime_TZInfoType, PyTZInfo_Check);
// datetime.timedelta bindings
pub struct PyDelta(PyObject);
pyobject_native_type!(PyDelta, PyDateTime_DeltaType, PyDelta_Check);
impl PyDelta {
pub fn new(
py: Python,
days: i32,
seconds: i32,
microseconds: i32,
normalize: bool,
) -> PyResult<Py<PyDelta>> {
unsafe {
let ptr = (PyDateTimeAPI.Delta_FromDelta)(
days as c_int,
seconds as c_int,
microseconds as c_int,
normalize as c_int,
PyDateTimeAPI.DeltaType,
);
Py::from_owned_ptr_or_err(py, ptr)
}
}
}
impl PyDeltaAccess for PyDelta {
fn get_days(&self) -> i32 {
unsafe { PyDateTime_DELTA_GET_DAYS(self.as_ptr()) as i32 }
}
fn get_seconds(&self) -> i32 {
unsafe { PyDateTime_DELTA_GET_SECONDS(self.as_ptr()) as i32 }
}
fn get_microseconds(&self) -> i32 {
unsafe { PyDateTime_DELTA_GET_MICROSECONDS(self.as_ptr()) as i32 }
}
}
// Utility function
unsafe fn opt_to_pyobj(py: Python, opt: Option<&PyObject>) -> *mut ffi::PyObject {
// Convenience function for unpacking Options to either an Object or None
match opt {
Some(tzi) => tzi.as_ptr(),
None => py.None().as_ptr(),
}
}

View File

@ -68,7 +68,7 @@ macro_rules! import_exception {
}
impl $crate::typeob::PyTypeObject for $name {
#[inline(always)]
#[inline]
fn init_type() {}
#[inline]

View File

@ -2,6 +2,9 @@
pub use self::boolobject::PyBool;
pub use self::bytearray::PyByteArray;
pub use self::datetime::PyDeltaAccess;
pub use self::datetime::{PyDate, PyDateTime, PyDelta, PyTime, PyTzInfo};
pub use self::datetime::{PyDateAccess, PyTimeAccess};
pub use self::dict::PyDict;
pub use self::floatob::PyFloat;
pub use self::iterator::PyIterator;
@ -63,7 +66,7 @@ macro_rules! pyobject_native_type_named (
}
impl<$($type_param,)*> $crate::PyObjectWithToken for $name {
#[inline(always)]
#[inline]
fn py(&self) -> $crate::Python {
unsafe { $crate::Python::assume_gil_acquired() }
}
@ -123,7 +126,7 @@ macro_rules! pyobject_native_type_convert(
}
impl<$($type_param,)*> $crate::typeob::PyTypeObject for $name {
#[inline(always)]
#[inline]
fn init_type() {}
#[inline]
@ -180,6 +183,7 @@ pyobject_native_type_convert!(PyObjectRef, ffi::PyBaseObject_Type, ffi::PyObject
mod boolobject;
mod bytearray;
mod datetime;
mod dict;
pub mod exc;
mod floatob;

View File

@ -204,7 +204,7 @@ impl IntoPyPointer for PyRawObject {
}
impl PyObjectWithToken for PyRawObject {
#[inline(always)]
#[inline]
fn py(&self) -> Python {
unsafe { Python::assume_gil_acquired() }
}

211
tests/test_datetime.rs Normal file
View File

@ -0,0 +1,211 @@
#![feature(concat_idents)]
extern crate pyo3;
use std::iter;
use pyo3::ffi::*;
use pyo3::prelude::*;
fn _get_subclasses<'p>(
py: &'p Python,
py_type: &str,
args: &str,
) -> PyResult<(&'p PyObjectRef, &'p PyObjectRef, &'p PyObjectRef)> {
// Import the class from Python and create some subclasses
let datetime = py.import("datetime")?;
let locals = PyDict::new(*py);
locals.set_item(py_type, datetime.get(py_type)?).unwrap();
let make_subclass_py = format!("class Subklass({}):\n pass", py_type);
let make_sub_subclass_py = "class SubSubklass(Subklass):\n pass";
py.run(&make_subclass_py, None, Some(&locals))?;
py.run(&make_sub_subclass_py, None, Some(&locals))?;
// Construct an instance of the base class
let obj = py.eval(&format!("{}({})", py_type, args), None, Some(&locals))?;
// Construct an instance of the subclass
let sub_obj = py.eval(&format!("Subklass({})", args), None, Some(&locals))?;
// Construct an instance of the sub-subclass
let sub_sub_obj = py.eval(&format!("SubSubklass({})", args), None, Some(&locals))?;
Ok((obj, sub_obj, sub_sub_obj))
}
macro_rules! assert_check_exact {
($check_func:ident, $obj: expr) => {
unsafe {
assert!($check_func(($obj).as_ptr()) != 0);
assert!(concat_idents!($check_func, Exact)(($obj).as_ptr()) != 0);
}
};
}
macro_rules! assert_check_only {
($check_func:ident, $obj: expr) => {
unsafe {
assert!($check_func(($obj).as_ptr()) != 0);
assert!(concat_idents!($check_func, Exact)(($obj).as_ptr()) == 0);
}
};
}
#[test]
fn test_date_check() {
let gil = Python::acquire_gil();
let py = gil.python();
let (obj, sub_obj, sub_sub_obj) = _get_subclasses(&py, "date", "2018, 1, 1").unwrap();
assert_check_exact!(PyDate_Check, obj);
assert_check_only!(PyDate_Check, sub_obj);
assert_check_only!(PyDate_Check, sub_sub_obj);
}
#[test]
fn test_time_check() {
let gil = Python::acquire_gil();
let py = gil.python();
let (obj, sub_obj, sub_sub_obj) = _get_subclasses(&py, "time", "12, 30, 15").unwrap();
assert_check_exact!(PyTime_Check, obj);
assert_check_only!(PyTime_Check, sub_obj);
assert_check_only!(PyTime_Check, sub_sub_obj);
}
#[test]
fn test_datetime_check() {
let gil = Python::acquire_gil();
let py = gil.python();
let (obj, sub_obj, sub_sub_obj) =
_get_subclasses(&py, "datetime", "2018, 1, 1, 13, 30, 15").unwrap();
assert_check_only!(PyDate_Check, obj);
assert_check_exact!(PyDateTime_Check, obj);
assert_check_only!(PyDateTime_Check, sub_obj);
assert_check_only!(PyDateTime_Check, sub_sub_obj);
}
#[test]
fn test_delta_check() {
let gil = Python::acquire_gil();
let py = gil.python();
let (obj, sub_obj, sub_sub_obj) = _get_subclasses(&py, "timedelta", "1, -3").unwrap();
assert_check_exact!(PyDelta_Check, obj);
assert_check_only!(PyDelta_Check, sub_obj);
assert_check_only!(PyDelta_Check, sub_sub_obj);
}
#[test]
#[cfg(Py_3)]
fn test_datetime_utc() {
let gil = Python::acquire_gil();
let py = gil.python();
let datetime = py.import("datetime").map_err(|e| e.print(py)).unwrap();
let timezone = datetime.get("timezone").unwrap();
let utc = timezone.getattr("utc").unwrap().to_object(py);
let dt = PyDateTime::new(py, 2018, 1, 1, 0, 0, 0, 0, Some(&utc)).unwrap();
let locals = PyDict::new(py);
locals.set_item("dt", dt).unwrap();
let offset: f32 = py
.eval("dt.utcoffset().total_seconds()", None, Some(locals))
.unwrap()
.extract()
.unwrap();
assert_eq!(offset, 0f32);
}
static INVALID_DATES: &'static [(i32, u8, u8)] = &[
(-1, 1, 1),
(0, 1, 1),
(10000, 1, 1),
(2 << 30, 1, 1),
(2018, 0, 1),
(2018, 13, 1),
(2018, 1, 0),
(2017, 2, 29),
(2018, 1, 32),
];
static INVALID_TIMES: &'static [(u8, u8, u8, u32)] =
&[(25, 0, 0, 0), (255, 0, 0, 0), (0, 60, 0, 0), (0, 0, 61, 0)];
#[cfg(Py_3_6)]
#[test]
fn test_pydate_out_of_bounds() {
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
let gil = Python::acquire_gil();
let py = gil.python();
for val in INVALID_DATES.into_iter() {
let (year, month, day) = val;
let dt = PyDate::new(py, *year, *month, *day);
let msg = format!("Should have raised an error: {:#?}", val);
match dt {
Ok(_) => assert!(false, msg),
Err(_) => assert!(true),
}
}
}
#[cfg(Py_3_6)]
#[test]
fn test_pytime_out_of_bounds() {
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
let gil = Python::acquire_gil();
let py = gil.python();
for val in INVALID_TIMES.into_iter() {
let (hour, minute, second, microsecond) = val;
let dt = PyTime::new(py, *hour, *minute, *second, *microsecond, None);
let msg = format!("Should have raised an error: {:#?}", val);
match dt {
Ok(_) => assert!(false, msg),
Err(_) => assert!(true),
}
}
}
#[cfg(Py_3_6)]
#[test]
fn test_pydatetime_out_of_bounds() {
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
let gil = Python::acquire_gil();
let py = gil.python();
let valid_time = (0, 0, 0, 0);
let valid_date = (2018, 1, 1);
let invalid_dates = INVALID_DATES.into_iter().zip(iter::repeat(&valid_time));
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(
py,
*year,
*month,
*day,
*hour,
*minute,
*second,
*microsecond,
None,
);
let msg = format!("Should have raised an error: {:#?}", val);
match dt {
Ok(_) => assert!(false, msg),
Err(_) => assert!(true),
}
}
}