-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mixin class for equality and equivalence #133
Conversation
@psomhorst, in 30efe49, you say:
However, I think that as a static method (the way you did it for What's your opinion on this? |
Consider renaming |
Then it should not be a static method but a normal method with |
I agree that this is a better name. If |
81ab152
to
a4515dd
Compare
df95c03
to
a8464f1
Compare
e216214
to
6dc006b
Compare
a8464f1
to
627296f
Compare
241f054
to
6cb6b48
Compare
d09c862
to
24ccf75
Compare
220dd2b
to
7ba4d40
Compare
@@ -51,6 +51,9 @@ class VariantCollection(dict, Generic[V]): | |||
|
|||
variant_type: type[V] | |||
|
|||
def __eq__(self, other): | |||
return Equivalence.__eq__(self, other) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return Equivalence.__eq__(self, other) | |
return self.variant_type == other.variant_type and super().__eq__(other) |
f"Variant types don't match: {self.variant_type}, {other.variant_type}": self.variant_type == other.variant_type, | ||
f"VariantCollections do not contain the same variants: {self.keys()=}, {other.keys()=}": set(self.keys()) == set(other.keys()), | ||
} | ||
for key in self.keys(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This raises a KeyError if self contains keys that other does not. The second check in the dictionary above does check for this, but that does not result in an actually throws exception, just the value being False. So this code is being evaluated, even if set(self.keys()) != set(other.keys()).
for key in self.keys(): | |
for key in set(self.keys()) & set(other.keys()): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even more problematic is that self
and other
both can be objects that do not implement keys()
. This method raises AttributeError if other
is not a VariantCollection
, just like the lines above.
) -> bool: | ||
# fmt: off | ||
checks = { | ||
f"Variant types don't match: {self.variant_type}, {other.variant_type}": self.variant_type == other.variant_type, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check leads to issues. This check runs regardless of the type of other
(or even self
, as it can be called as a class method). When testing this with other
as something different from a VariantCollection
, this raises an AttributeError
because other.variant_type
does not exist. These checks should ideally run after isequivalent()
checks whether the type of other
equals the type of self
.
Elsewhere I proposed to make a separate method that performs these checks, which is called from isequivalent()
. This method can be called after isequivalent()
makes sure the type matches.
Alternatively, this check should first check whether other has a variant type.
f"Variant types don't match: {self.variant_type}, {other.variant_type}": self.variant_type == other.variant_type, | |
f"Variant types don't match: {self.variant_type}, {other.variant_type if hasattr(other, "variant_type") else ""}": hasattr(other, "variant_type") and self.variant_type == other.variant_type, |
This becomes quite verbose quite quickly. Error messages do not properly convey the issue at hand.
# fmt: off | ||
checks = { | ||
f"Variant types don't match: {self.variant_type}, {other.variant_type}": self.variant_type == other.variant_type, | ||
f"VariantCollections do not contain the same variants: {self.keys()=}, {other.keys()=}": set(self.keys()) == set(other.keys()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line has the same problem as above.
f"VariantCollections do not contain the same variants: {self.keys()=}, {other.keys()=}": set(self.keys()) == set(other.keys()), | |
f"VariantCollections do not contain the same variants: {self.keys()=}, {other.keys() if hasattr(other, 'keys') else ''=}": hasattr(self, "keys") and hasattr(other, "keys") and set(self.keys()) == set(other.keys()), |
@psomhorst , I've implemented a few of the changes you suggested, mainly on the core workings of the To me, the main objective of this PR is to create a structure/class that can be used generically for testing equality and equivalence. I think I re-coded all the separate checks that previously were written per subclass into this structure. Currently it is a bit hard for me to judge exactly how each class will work and what needs to be checked for each of them, and it might also still be a bit fluent. I suggest that in this PR, we focus on the core of the |
40bd023
to
8509079
Compare
8509079
to
44c5504
Compare
Note that these are not functional for the `_Variant`-type classes, as these will likely be dropped.
These are not functional and will need to be overwritten when implementing real tests for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks good! I have not looked at testing this extensively, but we'll run into problems when implementing classes using Equivalence anyway.
self._check_equivalence: list[str] | ||
for attr in self._check_equivalence: | ||
if (s := getattr(self, attr)) != (o := getattr(other, attr)): | ||
raise f"{attr.capitalize()}s don't match: {s}, {o}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise f"{attr.capitalize()}s don't match: {s}, {o}" | |
msg = f"{attr.capitalize()}s don't match: {s}, {o}" | |
raise EquivalenceError(msg) |
a443a81
to
fee1ddf
Compare
Since your review, I've rebased the entire branch to make the commits more self-sufficient, but functionally nothing has changed. I will merge as is. As to your suggestion for the error message, I agree, but will do it in #143, as it is part of the ruff formatting, and will immediately tackle all existing error messages as well. |
This PR does the following:
__eq__
function for alive data structuresisequivalent
function for alive data structuresisequivalent
throughout