Skip to content

Commit 4b962b8

Browse files
makarchukyouknowone
authored andcommitted
Implement some __ne__ methods (#1446)
* Implement some __ne__ methods Added test snippets from `__ne__` methods * Fix incompatability in str.__eq__ befaviour Previously "".__eq__(1) returned "False", which is not the case in cpython. Not it's returning 'NotImplemented', as it should
1 parent 0ac9cb8 commit 4b962b8

10 files changed

Lines changed: 101 additions & 11 deletions

File tree

tests/snippets/dict.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,6 @@ def __eq__(self, other):
251251
assert isinstance(c, set)
252252
assert c == {'bla', 'c', 'd', 'f'}
253253

254+
assert not {}.__ne__({})
255+
assert {}.__ne__({'a':'b'})
256+
assert {}.__ne__(1) == NotImplemented

tests/snippets/list.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,11 @@ def bad_iter_assign():
489489
x = list(range(10))
490490
del x[-5:-1:-1]
491491

492+
assert [1, 2].__ne__([])
493+
assert [2, 1].__ne__([1, 2])
494+
assert not [1, 2].__ne__([1, 2])
495+
assert [1, 2].__ne__(1) == NotImplemented
496+
492497
# list gt, ge, lt, le
493498
assert_raises(TypeError, lambda: [0, []] < [0, 0])
494499
assert_raises(TypeError, lambda: [0, []] <= [0, 0])

tests/snippets/set.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,13 @@ def __hash__(self):
327327
assert x == (EqObject(x) == EqObject(x))
328328
s = {EqObject(x)}
329329
assert EqObject(x) in s
330+
331+
assert set([1, 2]).__ne__(set())
332+
assert not set([1, 2]).__ne__(set([2, 1]))
333+
assert set().__ne__(1) == NotImplemented
334+
335+
assert frozenset([1, 2]).__ne__(set())
336+
assert frozenset([1, 2]).__ne__(frozenset())
337+
assert not frozenset([1, 2]).__ne__(set([2, 1]))
338+
assert not frozenset([1, 2]).__ne__(frozenset([2, 1]))
339+
assert frozenset().__ne__(1) == NotImplemented

tests/snippets/strings.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from testutils import assert_raises
22

3+
assert "".__eq__(1) == NotImplemented
34
assert "a" == 'a'
45
assert """a""" == "a"
56
assert len(""" " "" " "" """) == 11
@@ -311,3 +312,9 @@ def try_mutate_str():
311312
assert index_str[-1] == 'n'
312313

313314
assert_raises(TypeError, lambda: index_str['a'])
315+
316+
317+
assert "a".__ne__("b")
318+
assert not "a".__ne__("a")
319+
assert not "".__ne__("")
320+
assert "".__ne__(1) == NotImplemented

tests/snippets/tuple.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ def __eq__(self, x):
5050
b = ()
5151
assert a is b
5252

53+
assert (1,).__ne__((2,))
54+
assert not (1,).__ne__((1,))
55+
5356
# tuple gt, ge, lt, le
5457
assert_raises(TypeError, lambda: (0, ()) < (0, 0))
5558
assert_raises(TypeError, lambda: (0, ()) <= (0, 0))
@@ -87,4 +90,4 @@ def __eq__(self, x):
8790
assert (float('inf'), float('inf')) <= (float('inf'), float('inf'))
8891
assert (float('inf'), float('inf')) >= (float('inf'), float('inf'))
8992
assert not (float('inf'), float('inf')) < (float('inf'), float('inf'))
90-
assert not (float('inf'), float('inf')) > (float('inf'), float('inf'))
93+
assert not (float('inf'), float('inf')) > (float('inf'), float('inf'))

vm/src/obj/objdict.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,15 @@ impl PyDictRef {
146146
}
147147
}
148148

149+
fn ne(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
150+
if let Some(other) = other.payload::<PyDict>() {
151+
let neq = !self.inner_eq(other, vm)?;
152+
Ok(vm.ctx.new_bool(neq))
153+
} else {
154+
Ok(vm.ctx.not_implemented())
155+
}
156+
}
157+
149158
fn len(self, _vm: &VirtualMachine) -> usize {
150159
self.entries.borrow().len()
151160
}
@@ -575,6 +584,7 @@ pub fn init(context: &PyContext) {
575584
"__contains__" => context.new_rustfunc(PyDictRef::contains),
576585
"__delitem__" => context.new_rustfunc(PyDictRef::inner_delitem),
577586
"__eq__" => context.new_rustfunc(PyDictRef::eq),
587+
"__ne__" => context.new_rustfunc(PyDictRef::ne),
578588
"__getitem__" => context.new_rustfunc(PyDictRef::inner_getitem),
579589
"__iter__" => context.new_rustfunc(PyDictRef::iter),
580590
(slot new) => PyDictRef::new,

vm/src/obj/objlist.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -508,17 +508,30 @@ impl PyListRef {
508508
if self.as_object().is(&other) {
509509
return Ok(vm.new_bool(true));
510510
}
511+
if objtype::isinstance(&other, &vm.ctx.list_type()) {
512+
Ok(vm.new_bool(self.inner_eq(&other, vm)?))
513+
} else {
514+
Ok(vm.ctx.not_implemented())
515+
}
516+
}
511517

518+
fn ne(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
519+
if self.as_object().is(&other) {
520+
return Ok(vm.new_bool(false));
521+
}
512522
if objtype::isinstance(&other, &vm.ctx.list_type()) {
513-
let zelf = self.elements.borrow();
514-
let other = get_elements_list(&other);
515-
let res = seq_equal(vm, &zelf.as_slice(), &other.as_slice())?;
516-
Ok(vm.new_bool(res))
523+
Ok(vm.new_bool(!self.inner_eq(&other, vm)?))
517524
} else {
518525
Ok(vm.ctx.not_implemented())
519526
}
520527
}
521528

529+
fn inner_eq(self, other: &PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
530+
let zelf = self.elements.borrow();
531+
let other = get_elements_list(other);
532+
seq_equal(vm, &zelf.as_slice(), &other.as_slice())
533+
}
534+
522535
fn lt(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
523536
if objtype::isinstance(&other, &vm.ctx.list_type()) {
524537
let zelf = self.elements.borrow();
@@ -869,6 +882,7 @@ pub fn init(context: &PyContext) {
869882
"__contains__" => context.new_rustfunc(PyListRef::contains),
870883
"__delitem__" => context.new_rustfunc(PyListRef::delitem),
871884
"__eq__" => context.new_rustfunc(PyListRef::eq),
885+
"__ne__" => context.new_rustfunc(PyListRef::ne),
872886
"__lt__" => context.new_rustfunc(PyListRef::lt),
873887
"__gt__" => context.new_rustfunc(PyListRef::gt),
874888
"__le__" => context.new_rustfunc(PyListRef::le),

vm/src/obj/objset.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* Builtin set type with a sequence of unique items.
33
*/
44

5+
use std::borrow::Borrow;
56
use std::cell::{Cell, RefCell};
67
use std::fmt;
78

@@ -13,6 +14,7 @@ use crate::pyobject::{
1314
};
1415
use crate::vm::{ReprGuard, VirtualMachine};
1516

17+
use super::objbool;
1618
use super::objlist::PyListIterator;
1719
use super::objtype;
1820
use super::objtype::PyClassRef;
@@ -133,6 +135,11 @@ impl PySetInner {
133135
)
134136
}
135137

138+
fn ne(&self, other: &PySetInner, vm: &VirtualMachine) -> PyResult {
139+
let eq = objbool::get_value(self.eq(other, vm)?.borrow());
140+
Ok(vm.new_bool(!eq))
141+
}
142+
136143
fn ge(&self, other: &PySetInner, vm: &VirtualMachine) -> PyResult {
137144
self._compare_inner(
138145
other,
@@ -358,6 +365,11 @@ impl PySet {
358365
try_set_inner!(vm, other, |other| self.inner.borrow().eq(other, vm))
359366
}
360367

368+
#[pymethod(name = "__ne__")]
369+
fn ne(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
370+
try_set_inner!(vm, other, |other| self.inner.borrow().ne(other, vm))
371+
}
372+
361373
#[pymethod(name = "__ge__")]
362374
fn ge(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
363375
try_set_inner!(vm, other, |other| self.inner.borrow().ge(other, vm))
@@ -604,6 +616,11 @@ impl PyFrozenSet {
604616
try_set_inner!(vm, other, |other| self.inner.eq(other, vm))
605617
}
606618

619+
#[pymethod(name = "__ne__")]
620+
fn ne(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
621+
try_set_inner!(vm, other, |other| self.inner.ne(other, vm))
622+
}
623+
607624
#[pymethod(name = "__ge__")]
608625
fn ge(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
609626
try_set_inner!(vm, other, |other| self.inner.ge(other, vm))

vm/src/obj/objstr.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,20 @@ impl PyString {
207207
}
208208

209209
#[pymethod(name = "__eq__")]
210-
fn eq(&self, rhs: PyObjectRef, vm: &VirtualMachine) -> bool {
210+
fn eq(&self, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
211211
if objtype::isinstance(&rhs, &vm.ctx.str_type()) {
212-
self.value == get_value(&rhs)
212+
vm.new_bool(self.value == get_value(&rhs))
213213
} else {
214-
false
214+
vm.ctx.not_implemented()
215+
}
216+
}
217+
218+
#[pymethod(name = "__ne__")]
219+
fn ne(&self, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
220+
if objtype::isinstance(&rhs, &vm.ctx.str_type()) {
221+
vm.new_bool(self.value != get_value(&rhs))
222+
} else {
223+
vm.ctx.not_implemented()
215224
}
216225
}
217226

vm/src/obj/objtuple.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,25 @@ impl PyTupleRef {
144144

145145
fn eq(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
146146
if objtype::isinstance(&other, &vm.ctx.tuple_type()) {
147-
let other = get_elements_tuple(&other);
148-
let res = seq_equal(vm, &self.elements.as_slice(), &other.as_slice())?;
149-
Ok(vm.new_bool(res))
147+
Ok(vm.new_bool(self.inner_eq(&other, vm)?))
148+
} else {
149+
Ok(vm.ctx.not_implemented())
150+
}
151+
}
152+
153+
fn ne(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
154+
if objtype::isinstance(&other, &vm.ctx.tuple_type()) {
155+
Ok(vm.new_bool(!self.inner_eq(&other, vm)?))
150156
} else {
151157
Ok(vm.ctx.not_implemented())
152158
}
153159
}
154160

161+
fn inner_eq(&self, other: &PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
162+
let other = get_elements_tuple(other);
163+
seq_equal(vm, &self.elements.as_slice(), &other.as_slice())
164+
}
165+
155166
fn hash(self, vm: &VirtualMachine) -> PyResult<pyhash::PyHash> {
156167
pyhash::hash_iter(self.elements.iter(), vm)
157168
}
@@ -285,6 +296,7 @@ If the argument is a tuple, the return value is the same object.";
285296
"__add__" => context.new_rustfunc(PyTupleRef::add),
286297
"__bool__" => context.new_rustfunc(PyTupleRef::bool),
287298
"__eq__" => context.new_rustfunc(PyTupleRef::eq),
299+
"__ne__" => context.new_rustfunc(PyTupleRef::ne),
288300
"__contains__" => context.new_rustfunc(PyTupleRef::contains),
289301
"__getitem__" => context.new_rustfunc(PyTupleRef::getitem),
290302
"__hash__" => context.new_rustfunc(PyTupleRef::hash),

0 commit comments

Comments
 (0)