What should I do, in a world where all text literals are Unicode by default, to make __import__ work in both Python 2 and 3?
I'm slowly learning about making Python code that will run under both Python 2 (version 2.6 or above) and Python 3 (version 3.2 or above).
This entails, I believe, the admonition to ensure text literals are Unicode by default:
from __future__ import unicode_literals
and to specify bytes literals explicitly with b'wibble' if needed.
The __import__ built-in function, though, is tripping up.
A contrived, trivial project layout:
$ mkdir fooproject/
$ cd fooproject/
$ mkdir foo/
$ printf "" > foo/__init__.py
$ mkdir foo/bar/
$ printf "" > foo/bar/__init__.py
Here's a simple fooproject/setup.py for that project:
from __future__ import unicode_literals
main_module_name = 'foo'
main_module = __import__(main_module_name, fromlist=['bar'])
assert main_module.bar
That fails under Python 2, but runs fine under Python 3:
$ python2 ./setup.py
Traceback (most recent call last):
File "./setup.py", line 4, in <module>
main_module = __import__(main_module_name, fromlist=['bar'])
TypeError: Item in ``from list'' not a string
$ python3 ./setup.py
We've deliberately made unadorned strings Unicode by default. By “not a string”, I presume Python 2 means “not a ‘bytes’ object”.
Okay, so we'll explicitly set that to a bytes literal:
from __future__ import unicode_literals
main_module_name = 'foo'
main_module = __import__(main_module_name, fromlist=[b'bar'])
assert main_module.bar
Now Python 2 is satisfied, but Python 3 complains:
$ python2 ./setup.py
$ python3 ./setup.py
Traceback (most recent call last):
File "./setup.py", line 4, in <module>
main_module = __import__(main_module_name, fromlist=[b'bar'])
File "<frozen importlib._bootstrap>", line 2281, in
_handle_fromlist
TypeError: hasattr(): attribute name must be string
So I've deliberately set unadorned strings to be Unicode by default, just as I'm supposed to; but that's apparently breaking the expectations of __import__ between Python 2 and Python 3.
How can I get that __import__ call, complete with its fromlist parameter, working correctly under both Python 2 and Python 3, keeping the unicode_literals setting?
str()behaves!