10

I'm trying to write a forward compatible program and I was wondering what the "best" way to handle the case where you need different imports.

In my specific case, I am using ConfigParser.SafeConfigParser() from Python2 which becomes configparser.ConfigParser() in Python3.

So far I have made it work either by using a try-except on the import or by using a conditional on the version of Python (using sys). Both work, but I was wondering if there was a recommended solution (maybe one I haven't tried yet).

ETA: Thanks everyone. I used six.moves with no issues.

Ruby Tuesday
  • 101
  • 1
  • 6
  • There are all sorts of reasons apart from the python version why an import might throw an exception! So conditionalizing on sys.version_info must be the better of the two ideas. – nigel222 Sep 10 '15 at 17:09
  • 3
    @nigel222 imports from the stdlib shouldn't throw exceptions; if they do you have much bigger problems. Version-checking is more brittle and doesn't get you anything. – tzaman Sep 10 '15 at 17:11
  • It wasn't explicitly concerned only with stdlib rather than conditional importing in general. Also "Bigger problems" are more common than you might think, if the system is a desktop maintained by someone with no IT background (hobbyist, university researcher, etc.) I'd prefer to know about them directly rather than having to debug a wrong import that "used to work"! – nigel222 Sep 15 '15 at 10:55

3 Answers3

14

Use six! It's a python compatibility module that irons out the differences between python3 and python2. The documentation available here will help you with this problem as well as any other issues you're having..

Specifically for your case you can just

from six.moves import configparser
import six

if six.PY2:
  ConfigParser = configparser.SafeConfigParser
else:
  ConfigParser = configparser.ConfigParser

and you'll be good to go.

Chad S.
  • 6,252
  • 15
  • 25
  • That looks...nice, but why isn't the assignment to `ConfigParser` handled by the `import` statement? I would have expected that to be the point of the `six.moves` module. – Kyle Strand Sep 10 '15 at 17:35
  • 1
    ...oh, I see that the `import` statement *is* handling the `ConfigParser => configparser` module-name change. Got it. – Kyle Strand Sep 10 '15 at 17:37
  • This is the solution that I used and, yes, six is handling the assignment. – Ruby Tuesday Sep 11 '15 at 17:55
11

This pattern is pretty standard:

try:
    from configparser import ConfigParser
except ImportError:
    from ConfigParser import SafeConfigParser as ConfigParser
tzaman
  • 46,925
  • 11
  • 90
  • 115
1

You can also do this:

import sys
if sys.version[:1] == '2':
    from configparser import ConfigParser
else:
    from ConfigParser import SafeConfigParser as ConfigParser

Read more Here.

Community
  • 1
  • 1
Ben Morris
  • 606
  • 5
  • 24
  • As stated in my question, I had already found *how* to do this but I was looking for the best practices solution and from what I've learned this is the last choice. – Ruby Tuesday Sep 11 '15 at 17:58