Portable code: __import__ demands different string types between 2 and 3
Ben Finney
ben+python at benfinney.id.au
Mon Dec 15 02:29:19 EST 2014
Howdy all,
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’::
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
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?
If some kind of kludge is needed to make it work between versions, is
this a bug which should be fixed so “use Unicode for text” remains
applicable advice?
--
\ “I do not believe in immortality of the individual, and I |
`\ consider ethics to be an exclusively human concern with no |
_o__) superhuman authority behind it.” —Albert Einstein, letter, 1953 |
Ben Finney
More information about the Python-list
mailing list