Portable code: __import__ parameter string type between Python 2 and Python 3
Question: 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?


Answer: recall `str` works differently for python2 and python3 (see @BrenBarn's
comment), so:

    
    
    main_module = __import__(main_module_name, fromlist=[str('bar')])
    

or more generally

    
    
    main_module = __import__(main_module_name, fromlist=list(map(str, ['bar'])))
    

