I'd like to create a class which has abc.ABCMeta
as a metaclass and is compatible both with Python 2.7 and Python 3.5. Until now, I only succeeded doing this either on 2.7 or on 3.5 - but never on both versions simultaneously. Could someone give me a hand?
Python 2.7:
import abc
class SomeAbstractClass(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def do_something(self):
pass
Python 3.5:
import abc
class SomeAbstractClass(metaclass=abc.ABCMeta):
@abc.abstractmethod
def do_something(self):
pass
If we run the following test using the suitable version of the Python interpreter (Python 2.7 -> Example 1, Python 3.5 -> Example 2), it succeeds in both scenarios:
import unittest
class SomeAbstractClassTestCase(unittest.TestCase):
def test_do_something_raises_exception(self):
with self.assertRaises(TypeError) as error:
processor = SomeAbstractClass()
msg = str(error.exception)
expected_msg = "Can't instantiate abstract class SomeAbstractClass with abstract methods do_something"
self.assertEqual(msg, expected_msg)
While running the test using Python 3.5, the expected behavior doesn't happen (TypeError
is not raised while instantiating SomeAbstractClass
):
======================================================================
FAIL: test_do_something_raises_exception (__main__.SomeAbstractClassTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/tati/sample_abc.py", line 22, in test_do_something_raises_exception
processor = SomeAbstractClass()
AssertionError: TypeError not raised
----------------------------------------------------------------------
Whereas running the test using Python 2.7 raises a SyntaxError
:
Python 2.7 incompatible
Raises exception:
File "/home/tati/sample_abc.py", line 24
class SomeAbstractClass(metaclass=abc.ABCMeta):
^
SyntaxError: invalid syntax
You could use six.add_metaclass
or six.with_metaclass
:
import abc, six
@six.add_metaclass(abc.ABCMeta)
class SomeAbstractClass():
@abc.abstractmethod
def do_something(self):
pass
six
is a Python 2 and 3 compatibility library. You can install it by running pip install six
or by downloading the latest version of six.py
to your project directory.
For those of you who prefer future
over six
, the relevant function is future.utils.with_metaclass
.