From a9b05711b06bfa7c0f047ea58115c686867c851d Mon Sep 17 00:00:00 2001 From: konstin Date: Sun, 11 Nov 2018 12:24:24 +0100 Subject: [PATCH] Add test to fix #220 --- examples/rustapi_module/setup.py | 5 +- examples/rustapi_module/src/datetime.rs | 230 +++++++++++++++++ examples/rustapi_module/src/lib.rs | 234 +----------------- examples/rustapi_module/src/subclassing.rs | 21 ++ .../rustapi_module/tests/test_subclassing.py | 9 + 5 files changed, 268 insertions(+), 231 deletions(-) create mode 100644 examples/rustapi_module/src/datetime.rs create mode 100644 examples/rustapi_module/src/subclassing.rs create mode 100644 examples/rustapi_module/tests/test_subclassing.py diff --git a/examples/rustapi_module/setup.py b/examples/rustapi_module/setup.py index 50eb51e7..2c59059e 100644 --- a/examples/rustapi_module/setup.py +++ b/examples/rustapi_module/setup.py @@ -25,11 +25,12 @@ def get_py_version_cfgs(): py3_min = 5 out_cfg = [] - for minor in range(py3_min, version[1]+1): + 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'] @@ -49,6 +50,8 @@ setup( rust_extensions=[RustExtension('rustapi_module.othermod', 'Cargo.toml', rustc_flags=get_py_version_cfgs()), RustExtension('rustapi_module.datetime', 'Cargo.toml', + rustc_flags=get_py_version_cfgs()), + RustExtension('rustapi_module.subclassing', 'Cargo.toml', rustc_flags=get_py_version_cfgs())], install_requires=install_requires, tests_require=tests_require, diff --git a/examples/rustapi_module/src/datetime.rs b/examples/rustapi_module/src/datetime.rs new file mode 100644 index 00000000..b3c55713 --- /dev/null +++ b/examples/rustapi_module/src/datetime.rs @@ -0,0 +1,230 @@ +use pyo3::prelude::*; +use pyo3::types::{ + PyDate, PyDateAccess, PyDateTime, PyDelta, PyDeltaAccess, PyTime, PyTimeAccess, + PyTuple, PyTzInfo, +}; + +#[pyfunction] +fn make_date(py: Python, year: i32, month: u8, day: u8) -> PyResult> { + PyDate::new(py, year, month, day) +} + +#[pyfunction] +fn get_date_tuple(py: Python, d: &PyDate) -> Py { + PyTuple::new( + py, + &[d.get_year(), d.get_month() as i32, d.get_day() as i32], + ) +} + +#[pyfunction] +fn date_from_timestamp(py: Python, timestamp: i64) -> PyResult> { + PyDate::from_timestamp(py, timestamp) +} + +#[pyfunction] +fn make_time( + py: Python, + hour: u8, + minute: u8, + second: u8, + microsecond: u32, + tzinfo: Option<&PyTzInfo>, +) -> PyResult> { + 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> { + 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::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::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> { + PyDelta::new(py, days, seconds, microseconds, true) +} + +#[pyfunction] +fn get_delta_tuple(py: Python, delta: &PyDelta) -> Py { + 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> { + 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::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::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> { + PyDateTime::from_timestamp(py, ts, tz) +} + +#[pyfunction] +fn issue_219() -> PyResult<()> { + let gil = Python::acquire_gil(); + let _py = gil.python(); + Ok(()) +} + +#[pyclass(extends=PyTzInfo)] +pub struct TzClass {} + +#[pymethods] +impl TzClass { + #[new] + fn __new__(obj: &PyRawObject) -> PyResult<()> { + obj.init(|_| TzClass {}) + } + + fn utcoffset(&self, py: Python, _dt: &PyDateTime) -> PyResult> { + PyDelta::new(py, 0, 3600, 0, true) + } + + fn tzname(&self, _py: Python, _dt: &PyDateTime) -> PyResult { + Ok(String::from("+01:00")) + } + + fn dst(&self, _py: Python, _dt: &PyDateTime) -> PyResult> { + Ok(None) + } +} + +#[pymodinit] +fn datetime(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_function(wrap_function!(make_date))?; + 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))?; + } + + m.add_function(wrap_function!(issue_219))?; + + m.add_class::()?; + Ok(()) +} diff --git a/examples/rustapi_module/src/lib.rs b/examples/rustapi_module/src/lib.rs index d160a3a9..d0d356f1 100644 --- a/examples/rustapi_module/src/lib.rs +++ b/examples/rustapi_module/src/lib.rs @@ -3,235 +3,9 @@ #[macro_use] extern crate pyo3; -pub mod othermod; - use pyo3::prelude::*; -use pyo3::types::{ - PyDate, PyDateAccess, PyDateTime, PyDelta, PyDeltaAccess, PyDict, PyTime, PyTimeAccess, - PyTuple, PyTzInfo, -}; +use subclassing::Subclassable; -#[pyfunction] -fn make_date(py: Python, year: i32, month: u8, day: u8) -> PyResult> { - PyDate::new(py, year, month, day) -} - -#[pyfunction] -fn get_date_tuple(py: Python, d: &PyDate) -> Py { - PyTuple::new( - py, - &[d.get_year(), d.get_month() as i32, d.get_day() as i32], - ) -} - -#[pyfunction] -fn date_from_timestamp(py: Python, timestamp: i64) -> PyResult> { - PyDate::from_timestamp(py, timestamp) -} - -#[pyfunction] -fn make_time( - py: Python, - hour: u8, - minute: u8, - second: u8, - microsecond: u32, - tzinfo: Option<&PyTzInfo>, -) -> PyResult> { - 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> { - 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::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::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> { - PyDelta::new(py, days, seconds, microseconds, true) -} - -#[pyfunction] -fn get_delta_tuple(py: Python, delta: &PyDelta) -> Py { - 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> { - 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::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::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> { - PyDateTime::from_timestamp(py, ts, tz) -} - -#[pyfunction] -fn issue_219() -> PyResult<()> { - let gil = Python::acquire_gil(); - let _py = gil.python(); - Ok(()) -} - -#[pyclass(extends=PyTzInfo)] -pub struct TzClass {} - -#[pymethods] -impl TzClass { - #[new] - fn __new__(obj: &PyRawObject) -> PyResult<()> { - obj.init(|_| TzClass {}) - } - - fn utcoffset(&self, py: Python, dt: &PyDateTime) -> PyResult> { - PyDelta::new(py, 0, 3600, 0, true) - } - - fn tzname(&self, py: Python, dt: &PyDateTime) -> PyResult { - Ok(String::from("+01:00")) - } - - fn dst(&self, py: Python, dt: &PyDateTime) -> PyResult> { - Ok(None) - } -} - -#[pymodinit] -fn datetime(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_function(wrap_function!(make_date))?; - 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))?; - } - - m.add_function(wrap_function!(issue_219))?; - - m.add_class::()?; - Ok(()) -} +pub mod othermod; +pub mod subclassing; +pub mod datetime; diff --git a/examples/rustapi_module/src/subclassing.rs b/examples/rustapi_module/src/subclassing.rs new file mode 100644 index 00000000..7cc795e7 --- /dev/null +++ b/examples/rustapi_module/src/subclassing.rs @@ -0,0 +1,21 @@ +//! Test for [#220](https://github.com/PyO3/pyo3/issues/220) + +use pyo3::prelude::*; + +#[pyclass(subclass)] +pub struct Subclassable {} + +#[pymethods] +impl Subclassable { + #[new] + fn __new__(obj: &PyRawObject) -> PyResult<()> { + obj.init(|_| Subclassable {}) + } +} + +#[pymodinit] +fn subclassing(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + Ok(()) +} + diff --git a/examples/rustapi_module/tests/test_subclassing.py b/examples/rustapi_module/tests/test_subclassing.py new file mode 100644 index 00000000..8c086b75 --- /dev/null +++ b/examples/rustapi_module/tests/test_subclassing.py @@ -0,0 +1,9 @@ +from rustapi_module.subclassing import Subclassable + + +class SomeSubClass(Subclassable): + pass + + +a = SomeSubClass() +_b = str(a) + repr(a)