I recently decided to code some in Python after coding in Java using lombok for quite some time. However, I got bit real hard when I forgot to implement __eq__
, since Lombok normally does it for you.
I decided to try to implement something similar to Lombok's @EqualsAndHashCode
, which I called eqhash
. Then, I added a similar way to generate a __repr__
method.
How well did I follow python style? I developed this using TDD, so I would like to know how my tests are as well.
genmethods.py
def eqhash(cls: type):
"""Adds __eq__, __ne__, and __hash__ methods to the class"""
class NewCls(cls):
def __eq__(self, other):
if self is other: return True
if not isinstance(other, NewCls): return False
svars = vars(self)
ovars = vars(other)
return svars == ovars
def __ne__(self, other):
return not (self == other)
def __hash__(self):
return hash(vars(self).values())
return _pass_attrs(NewCls, cls)
def repr_(cls: type):
"""Adds a __repr__ method to the class"""
class NewCls(cls):
def __repr__(self):
return '{clsname}({variables})'.format(
clsname=cls.__name__,
variables=', '.join(repr(o) for o in vars(self).values())
)
return _pass_attrs(NewCls, cls)
def _pass_attrs(new_cls, cls):
new_cls.__name__ = cls.__name__
new_cls.__qualname__ = cls.__qualname__
for attr, value in vars(cls).items():
try:
setattr(new_cls, attr, value)
except AttributeError:
pass
return new_cls
test_genmethods.py
import unittest
import genmethods
class SData:
def __init__(self, value):
self._value = value
def test(self):
return self._value
def ensure_not_mangled(self: unittest.TestCase, cls: type, name: str):
self.assertEqual((1, 2), cls((1, 2)).test())
self.assertEqual(name, cls.__name__)
class EqHashTest(unittest.TestCase):
@genmethods.eqhash
class Data(SData):
pass
def test_eq_genned(self):
self.assertEqual(EqHashTest.Data((1, 2)), EqHashTest.Data((1, 2)))
self.assertNotEqual(EqHashTest.Data((1, 2)), EqHashTest.Data((1, 4)))
def test_hash_genned(self):
v1 = EqHashTest.Data(1)
v2 = EqHashTest.Data(1)
self.assertEqual(hash(v1), hash(v2))
def test_not_mangled(self):
ensure_not_mangled(self, EqHashTest.Data, "Data")
class ReprTest(unittest.TestCase):
@genmethods.repr_
class Data(SData):
pass
def test_repr_genned(self):
self.assertEqual('Data(1)', repr(ReprTest.Data(1)))
def test_not_mangled(self):
ensure_not_mangled(self, EqHashTest.Data, "Data")
class ReprEqHashTest(unittest.TestCase):
@genmethods.repr_
@genmethods.eqhash
class Data(SData):
pass
def test_eq_genned(self):
self.assertEqual(ReprEqHashTest.Data((1, 2)), ReprEqHashTest.Data((1, 2)))
self.assertNotEqual(ReprEqHashTest.Data((1, 2)), ReprEqHashTest.Data((1, 4)))
def test_hash_genned(self):
v1 = ReprEqHashTest.Data(1)
v2 = ReprEqHashTest.Data(1)
self.assertEqual(hash(v1), hash(v2))
def test_repr_genned(self):
self.assertEqual('Data(1)', repr(ReprEqHashTest.Data(1)))
def test_not_mangled(self):
ensure_not_mangled(self, EqHashTest.Data, "Data")
class EqHashReprTest(unittest.TestCase):
@genmethods.eqhash
@genmethods.repr_
class Data(SData):
pass
def test_eq_genned(self):
self.assertEqual(ReprEqHashTest.Data((1, 2)), ReprEqHashTest.Data((1, 2)))
self.assertNotEqual(ReprEqHashTest.Data((1, 2)), ReprEqHashTest.Data((1, 4)))
def test_hash_genned(self):
v1 = ReprEqHashTest.Data(1)
v2 = ReprEqHashTest.Data(1)
self.assertEqual(hash(v1), hash(v2))
def test_repr_genned(self):
self.assertEqual('Data(1)', repr(ReprEqHashTest.Data(1)))
def test_not_mangled(self):
ensure_not_mangled(self, EqHashTest.Data, "Data")