This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: ImportError using __import__ and relative level 1
Type: Stage:
Components: Interpreter Core Versions: Python 2.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: brett.cannon, eric.snow, jaraco, ncoghlan
Priority: normal Keywords:

Created on 2012-01-30 17:00 by jaraco, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (12)
msg152331 - (view) Author: Jason R. Coombs (jaraco) * (Python committer) Date: 2012-01-30 17:00
The Python 2.7.2 docs say this about __import__:

    Positive values for level indicate the number of parent directories to search relative to the directory of the module calling __import__().

But I find that even when setting level=1, the parent directory is not searched.

I've created this project tree to replicate the issue:

    jaraco@devjaraco:~$ tree master
    master
    ├── __init__.py
    ├── pkgA
    │   ├── foo.py
    │   └── __init__.py
    └── pkgB
        ├── bar.py
        └── __init.py

    2 directories, 5 files
    jaraco@devjaraco:~$ cat master/pkgA/foo.py

    bar = __import__('pkgB', level=1).bar
    jaraco@devjaraco:~$ cat master/pkgB/bar.py
    var = "success"

It fails as so with python 2.7.2:

    jaraco@devjaraco:~$ python2.7 -c "import master.pkgA.foo"
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "master/pkgA/foo.py", line 2, in <module>
        bar = __import__('pkgB', level=1).bar
    ImportError: No module named pkgB


It's conceivable I'm not using this correctly, but if so, I'm unable to find my mistake. I've confirmed that foo.__name__ is 'master.pkgA.foo'. I've tried using level=2 (in case I was off by one, but that wasn't the case).
msg152336 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2012-01-30 17:35
what value do you see for __package__ in pkgA?
msg152341 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2012-01-30 18:05
You have a typo in a filename: it should be pkgB/__init__.py (not the missing trailing underscores).
msg152342 - (view) Author: Jason R. Coombs (jaraco) * (Python committer) Date: 2012-01-30 19:31
Sorry for the mistake.

I corrected the pkgB package, but the result is the same:

    jaraco@devjaraco:~$ tree master
    master
    ├── __init__.py
    ├── __init__.pyc
    ├── pkgA
    │   ├── foo.py
    │   ├── foo.pyc
    │   ├── __init__.py
    │   └── __init__.pyc
    └── pkgB
        ├── bar.py
        └── __init__.py

    2 directories, 8 files
    jaraco@devjaraco:~$ python2.7 -c 'import master.pkgA; print("pkgA.__package__ is {}".format(master.pkgA.__package__)); import master.pkgA.foo'
    pkgA.__package__ is None
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "master/pkgA/foo.py", line 2, in <module>
        bar = __import__('pkgB', level=1).bar
    ImportError: No module named pkgB

As you can see, __package__ for pkgA is None. Same is true for master.__package__.
msg152354 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2012-01-30 22:42
I see your mistake now: you need to call it as __import__('pkgB', globals(), index=1), else __import__ has no clue how to anchor your import in the relative package space.

Try that and let me know if it makes it work.

And why exactly are you trying to call __import__ directly? You should be using importlib.import_module() for programmatic imports.
msg152357 - (view) Author: Jason R. Coombs (jaraco) * (Python committer) Date: 2012-01-30 23:05
Thanks for the tip Brent. Still, no luck.

    jaraco@devjaraco:~$ python2.7 -c 'import master.pkgA; print("pkgA.__package__ is {}".format(master.pkgA.__package__)); import master.pkgA.foo'
    pkgA.__package__ is None
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "master/pkgA/foo.py", line 2, in <module>
        bar = __import__('pkgB', globals(), level=1).bar
    ImportError: No module named pkgB

I considered importlib, but it is only included for Python 2.7+ and I have to support Python 2.6. I'm using programmatic imports for a few  reasons:

1) I'm importing the modules for the side effects, so I don't need or want the name in the namespace.
2) If I import it naturally, I get pyflakes warnings that it's an used imports.
3) The order of imports is important. If I place it too early in the imports, it doesn't have the state it needs and fails.
4) By placing it in the top of the file with other imports, it's not obvious why it's being imported, so requires comments.
5) The most appropriate place to invoke this functionality is in a specific function, "run_app".

I see now that there is an importlib backport in the cheeseshop for earlier versions of Python. Given your recommendation, I'll give that a try.
msg152361 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2012-01-30 23:33
Jason: just a warning.  importlib_backport is a relatively naive tool for generating the backport from the py3k source.  It's also relatively fragile and at this point probably doesn't work with the default branch.
msg152365 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2012-01-31 01:46
The problem is your level is off and the name is incomplete.  master.pkgA.foo.py should have the following:

__import__('pkgB.bar', master.pkgA.__dict__, level=2).bar

or 

__import__('pkgB.bar', master.pkgA.__dict__, fromlist=['-'], level=2)
msg152375 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2012-01-31 12:02
It sounds like you may want runpy.run_module [1], rather than using imports at all. If you know how many levels up you want to go, it isn't hard to do your own munging of __name__ to create absolute module references to pass to runpy.

The signature of __import__ is known to be unintuitive to the point of being insane - it's really designed for the convenience of the compiler and the interpreter, not for direct use by humans.

[1] http://docs.python.org/release/2.6.7/library/runpy#runpy.run_module
msg152391 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2012-01-31 16:01
On Mon, Jan 30, 2012 at 18:33, Eric Snow <report@bugs.python.org> wrote:

>
> Eric Snow <ericsnowcurrently@gmail.com> added the comment:
>
> Jason: just a warning.  importlib_backport is a relatively naive tool for
> generating the backport from the py3k source.  It's also relatively fragile
> and at this point probably doesn't work with the default branch.
>

I think Jason was thinking of http://pypi.python.org/pypi/importlib/ which
is my personal backport of importlib from Python 2.7 all the way back to
Python 2.3.
msg175263 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2012-11-10 05:42
Are you okay on this, Jason?
msg175288 - (view) Author: Jason R. Coombs (jaraco) * (Python committer) Date: 2012-11-10 16:44
Yes. Since Nick's comment , I've been using importlib for all programmatic imports with great success.
History
Date User Action Args
2022-04-11 14:57:26adminsetgithub: 58120
2012-11-10 16:44:45jaracosetstatus: pending -> closed
resolution: not a bug
messages: + msg175288
2012-11-10 05:42:56eric.snowsetstatus: open -> pending

messages: + msg175263
2012-01-31 16:01:04brett.cannonsetmessages: + msg152391
2012-01-31 12:02:07ncoghlansetnosy: + ncoghlan
messages: + msg152375
2012-01-31 01:46:53eric.snowsetmessages: + msg152365
2012-01-30 23:33:30eric.snowsetmessages: + msg152361
2012-01-30 23:05:30jaracosetmessages: + msg152357
2012-01-30 22:42:25brett.cannonsetmessages: + msg152354
2012-01-30 19:31:05jaracosetstatus: closed -> open
resolution: not a bug -> (no value)
messages: + msg152342
2012-01-30 18:05:06brett.cannonsetstatus: open -> closed

nosy: + brett.cannon
messages: + msg152341

resolution: not a bug
2012-01-30 17:35:25eric.snowsetnosy: + eric.snow
messages: + msg152336
2012-01-30 17:00:47jaracocreate