Move __eq__ impl back to the mixin and fix test_rules.py test

This commit is contained in:
Thomas Krijnen
2026-08-01 13:16:51 +02:00
parent 6abeb459a2
commit 98ce2a1b46
2 changed files with 18 additions and 84 deletions
@@ -208,21 +208,27 @@ class entity_instance_mixin:
return value
# TODO: dead code? Since overridden by `__eq__` defined on `entity_instance`.
def __eq__(self, other: entity_instance_mixin) -> bool:
def __eq__(self, other: object) -> bool:
if not isinstance(other, entity_instance_mixin):
if not self.is_entity():
return self[0] == other
else:
return False
else:
raise NotImplementedError
return self[0] == other if not self.is_entity() else False
def __ne__(self, other: entity_instance_mixin) -> bool:
if other is None or not isinstance(other, entity_instance_mixin):
if self.identity() == other.identity():
return True
else:
raise NotImplementedError
if self.is_a(True) != other.is_a(True):
return False
if self.file != other.file or not self.is_entity():
return self.get_info(
recursive=True, include_identifier=False
) == other.get_info(
recursive=True, include_identifier=False
)
return False
def __ne__(self, other: object) -> bool:
return not self == other
def is_entity(self) -> bool:
"""Tests whether the instance is an entity type as opposed to a simple data type.
-72
View File
@@ -410,66 +410,6 @@ private:
%}
}
%{
// Shared by __eq__/__ne__ below - %extend methods can't call each other directly.
// Initially was added as __eq__, but swig doesn't allow calling one extended method from another.
static bool express_Base_equals(const express::Base* self, const express::Base* other) {
// This logic is not perfect and is not fully consistent with __hash__
if (!other) {
return false;
} else if (self->identity() == other->identity()) {
return true;
} else if (&self->declaration() != &other->declaration()) {
return false;
} else if ((self->file() != other->file()) || (self->declaration().as_entity() == nullptr)) {
// PyGILState_STATE gil = PyGILState_Ensure();
// @todo get_info is actually implemented in C++, so we try to call it directly
bool result = false;
PyObject *py_self = SWIG_NewPointerObj(SWIG_as_voidptr(self),
SWIGTYPE_p_express__Base, 0);
PyObject *py_other = SWIG_NewPointerObj(SWIG_as_voidptr(other),
SWIGTYPE_p_express__Base, 0);
if (py_self && py_other) {
PyObject *args = PyTuple_New(0);
PyObject *kwargs = PyDict_New();
PyDict_SetItemString(kwargs, "recursive", Py_True);
PyDict_SetItemString(kwargs, "include_identifier", Py_False);
PyObject *m1 = PyObject_GetAttrString(py_self, "get_info");
PyObject *m2 = PyObject_GetAttrString(py_other, "get_info");
PyObject *i1 = (m1 ? PyObject_Call(m1, args, kwargs) : nullptr);
PyObject *i2 = (m2 ? PyObject_Call(m2, args, kwargs) : nullptr);
if (i1 && i2) {
int eq = PyObject_RichCompareBool(i1, i2, Py_EQ);
result = (eq == 1);
} else {
// get_info missing or threw; treat as not equal (and clear Python error).
PyErr_Clear();
}
Py_XDECREF(i1);
Py_XDECREF(i2);
Py_XDECREF(m1);
Py_XDECREF(m2);
Py_DECREF(kwargs);
Py_DECREF(args);
} else {
PyErr_Clear();
}
Py_XDECREF(py_self);
Py_XDECREF(py_other);
// PyGILState_Release(gil);
return result;
} else {
return false;
}
}
%}
%extend express::Base {
// 0 = not found
@@ -589,18 +529,6 @@ static bool express_Base_equals(const express::Base* self, const express::Base*
return $self->get_attribute_value((unsigned)i);
}
// `other` is a pointer, not a reference, so Python `None` converts to
// nullptr instead of SWIG raising a null-reference error before this
// body runs.
bool __eq__(const express::Base* other) const {
return express_Base_equals($self, other);
}
// Override operator!= to support None or other data types in `other`.
bool __ne__(const express::Base* other) const {
return !express_Base_equals($self, other);
}
size_t __hash__() const {
return std::hash<uint32_t>{}(self->identity());
}