diff --git a/easybuild/framework/easyconfig/easyconfig.py b/easybuild/framework/easyconfig/easyconfig.py index 047d819bd0..14a6dad48a 100644 --- a/easybuild/framework/easyconfig/easyconfig.py +++ b/easybuild/framework/easyconfig/easyconfig.py @@ -722,10 +722,16 @@ def get(self, key, default=None): else: return default + # *both* __eq__ and __ne__ must be implemented for == and != comparisons to work correctly + # see also https://docs.python.org/2/reference/datamodel.html#object.__eq__ def __eq__(self, ec): """Is this EasyConfig instance equivalent to the provided one?""" return self.asdict() == ec.asdict() + def __ne__(self, ec): + """Is this EasyConfig instance equivalent to the provided one?""" + return self.asdict() != ec.asdict() + def __hash__(self): """Return hash value for a hashable representation of this EasyConfig instance.""" def make_hashable(val): @@ -736,11 +742,12 @@ def make_hashable(val): val = tuple([(key, make_hashable(val)) for (key, val) in sorted(val.items())]) return val - tup = () + lst = [] for (key, val) in sorted(self.asdict().items()): - tup += (key, make_hashable(val)) + lst.append((key, make_hashable(val))) - return hash(tup) + # a list is not hashable, but a tuple is + return hash(tuple(lst)) def asdict(self): """ diff --git a/test/framework/easyconfig.py b/test/framework/easyconfig.py index 35a8e99851..e8ac20fa8c 100644 --- a/test/framework/easyconfig.py +++ b/test/framework/easyconfig.py @@ -1535,6 +1535,26 @@ def test_param_value_type_checking(self): error_msg_pattern = "Type checking of easyconfig parameter values failed: .*'name'.*'version'.*" self.assertErrorRegex(EasyBuildError, error_msg_pattern, EasyConfig, ec_file) + def test_eq_hash(self): + """Test comparing two EasyConfig instances.""" + test_easyconfigs = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'easyconfigs') + ec1 = EasyConfig(os.path.join(test_easyconfigs, 'toy-0.0.eb')) + ec2 = EasyConfig(os.path.join(test_easyconfigs, 'toy-0.0.eb')) + + # different instances, same parsed easyconfig + self.assertFalse(ec1 is ec2) + self.assertEqual(ec1, ec2) + self.assertTrue(ec1 == ec2) + self.assertFalse(ec1 != ec2) + + # hashes should also be identical + self.assertEqual(hash(ec1), hash(ec2)) + + # other parsed easyconfig is not equal + ec3 = EasyConfig(os.path.join(test_easyconfigs, 'gzip-1.4.eb')) + self.assertFalse(ec1 == ec3) + self.assertTrue(ec1 != ec3) + def suite(): """ returns all the testcases in this module """