What is the most pythonic way to support unittest2

2019-07-11 20:48发布

问题:

I can think of two ways to ensure that I can use modern features from the unittest library across a wide range of Python versions:

try:
    from unittest2 import TestCase
except ImportError:
    from unittest import TestCase

or

import sys
if sys.verson_info.major>=2 and sys.version_info.minor>=7:
    from unittest import TestCase
else:
    from unittest2 import TestCase

Which one of these is more Pythonic?

回答1:

i'd use the try statement. It's an often used idiom. Also your sys version is wrong for python3.3:

>>> if sys.version_info.major>=2 and sys.version_info.minor>=7:
...     from unittest import TestCase
... else:
...     from unittest2 import TestCase
... 
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
ImportError: No module named 'unittest2'

While it should be:

>>> import sys
>>> major, minor = sys.version_info.major, sys.version_info.minor
>>> if (major >= 2 and minor >= 7) or (major >= 3 and minor >= 2):
...     from unittest import TestCase
... else:
...     from unittest2 import TestCase
... 
>>> 

This shows also that the try version is more robust across python's versions.

I often use the try variant when I have an "accelerated" version of the module written in C, at the end of the file I put a:

try:
    from _accelerated import *
except ImportError:
    pass

to overwrite the python implementation with the accellerated one.



回答2:

I don't like the fact that in the second version we have to import another module (sys) so my preference is for the first version:

try:
    from unittest2 import TestCase
except ImportError:
    from unittest import TestCase

EDIT:

It turns out that pyflakes and flake8 are not happy with the version above and will report a "redefinition of unused 'import' from line ... " error or "W402 'TestCase' imported but unused" error. They seem to prefer it to be written as follows:

try:
    import unittest2
    TestCase = unittest2.TestCase
except ImportError:
    import unittest
    TestCase = unittest.TestCase


回答3:

For those of us who avoid the from ... import ... idiom, this imports the right unittest in a manner transparent to the rest of the code:

import sys
if sys.version_info < (2, 7):
    import unittest2 as unittest
else:
    import unittest