From 20a820eda61695808053d321d44bc9b3fc78dea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20V=C3=A1zquez=20Acosta?= Date: Tue, 28 Jul 2020 12:16:31 -0400 Subject: [PATCH] Add a (failing test) for issue #1064 RichComparisonToSelf expects to compare itself with objects of the same type, but they we shouldn't raise TypeError but return NotImplemented. --- Cargo.toml | 2 ++ tests/test_arithmetics.rs | 62 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 177e3482036..9c3df00494b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,8 @@ macros = ["ctor", "indoc", "inventory", "paste", "pyo3cls", "unindent"] # Optimizes PyObject to Vec conversion and so on. nightly = [] +no-return-notimplemented = [] + # this is no longer needed internally, but setuptools-rust assumes this feature python3 = [] diff --git a/tests/test_arithmetics.rs b/tests/test_arithmetics.rs index d86783aa64f..12046f3cc34 100644 --- a/tests/test_arithmetics.rs +++ b/tests/test_arithmetics.rs @@ -423,3 +423,65 @@ fn rich_comparisons_python_3_type_error() { py_expect_exception!(py, c2, "c2 >= 1", PyTypeError); py_expect_exception!(py, c2, "1 >= c2", PyTypeError); } + +#[cfg(not(feature = "no-return-notimplemented"))] +#[cfg(test)] +mod not_implemented { + use super::*; + + #[pyclass] + struct RichComparisonToSelf {} + + #[pyproto] + impl<'p> PyObjectProtocol<'p> for RichComparisonToSelf { + fn __repr__(&self) -> &'static str { + "RC_Self" + } + + fn __richcmp__(&self, other: PyRef<'p, Self>, _op: CompareOp) -> PyObject { + other.py().None() + } + } + + macro_rules! not_implemented_test { + ($dunder: ident, $operator: expr) => { + #[test] + fn $dunder() { + let gil = Python::acquire_gil(); + let py = gil.python(); + let c2 = PyCell::new(py, RichComparisonToSelf {}).unwrap(); + py_run!( + py, + c2, + &format!( + "\ +class Other: + def __{}__(self, other): + return True +assert c2 {} Other()", + stringify!($dunder), $operator + ) + ); + py_expect_exception!( + py, + c2, + &format!("class Other: pass; assert c2 {} Other()", $operator), + PyTypeError + ); + } + }; + + [$( ($dunder: ident, $operator: literal) ),*] => { + $(not_implemented_test!{$dunder, $operator})* + }; + } + + not_implemented_test![ + (eq, "=="), + (ne, "!="), + (lt, "<"), + (le, "<="), + (gt, ">"), + (ge, ">=") + ]; +}