1

Suppose I have a module package containing the following files. An empty file C:\codes\package\__init__.py and some non-trivial files:

One located in C:\codes\package\first.py

def f():
    print 'a'

Another located in C:\codes\package\second.py

def f():
    print 'b'

There is also a third file: C:\codes\package\general.py with the following code

def myPrint(module_name):
    module = __import__(module_name)
    module.f()

if __name__ == '__main__':
    myPrint('first')
    myPrint('second')

When I run the latter file, everything goes fine. However, if I try to execute the file C:\codes\test.py containing

if __name__ == '__main__':
    from package import general
    general.myPrint('first')
    general.myPrint('second')

I get the import error ImportError: No module named first. How to resolve this issue?

Ulysses
  • 357
  • 1
  • 13
  • http://stackoverflow.com/questions/17344561/python-perform-relative-import-when-using-import – tynn May 05 '15 at 07:45

3 Answers3

4

First, I suspect you forgot to metion you have a (possibly empty) file package\__init__.py which makes package a package. Otherwise, from package import general wouldn't work.

The second case differs from the first in so far as you are in a package. From inside a package, you wouldn't do import first, but import .first. The equivalent to the latter is described here where you either add level=1 as a parameter or (but I am not sure about that) you put .first into the string and set level to -1 (if it isn't the default nevertheless, that's not clear from the documentation).

Additionally, you have to provide at least globals(), so the right line is

module = __import__(module_name, globals(), level=1)

I have found this solution here.

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • I don't think OP forgot to add `__init__.py ` because `from package import general ` works for him – Daniil Ryzhkov May 05 '15 at 07:09
  • 1
    As I said: he just forgot to mention the file. – glglgl May 05 '15 at 07:09
  • 1
    @Daniil: as glglgl rightfully noticed, indeed I've added it but forgot to mention. – Ulysses May 05 '15 at 07:11
  • Thanks for the answer, so in __import__ I shall do `__import('.' + moduleName)`? – Ulysses May 05 '15 at 07:12
  • 1
    @Ulysses Try it - but probably `__import__(modulename, level=1)` will work better. – glglgl May 05 '15 at 07:13
  • The '.' solution returns `ValueError: Empty module name`. The solution `__import__('first', level = 1)` did not work - same error as in the OP. Although I have not tried it exactly in the described setting, so my `package` folder is quite far away (I can still import `general.py` and anything inside it with no issues, so only relative import issues). – Ulysses May 05 '15 at 07:27
  • To be honest, even if I implement the whole setting as described, I can't make it work even from `general.py` – Ulysses May 05 '15 at 07:34
  • More to that, even if I just try to do `import .first` I get syntax error. I did put `from __future__ import absolute_import` since I'm using Python 2.6 – Ulysses May 05 '15 at 07:40
  • @Ulysses Ok, but `absolute_import` shouldn't affect the `__import__()` function's behaviour... I'll work more on that. – glglgl May 05 '15 at 07:45
  • @Ulysses I just updated my answer - this way I got it work under 2.7 and I hope it works under 2.6 as well. – glglgl May 05 '15 at 07:51
  • Thanks, I'll try it - but now I can't even import `package` at all. That's pretty strange. I'll try to make it work, and then get back – Ulysses May 05 '15 at 08:00
0

In your case, you should import your module_name from package. Use fromlist argument:

getattr(__import__("package", fromlist=[module_name]), module_name)
Daniil Ryzhkov
  • 7,416
  • 2
  • 41
  • 58
0

Assuming, you're using Python 3, that's just because this version dropped the support for implicit relative imports. With Python 2 it would be working just fine.

So either you'd need to use relative imports in C:\codes\package\general.py, which would result in erroneous call to it, or add your package to the path. A little dirty, but working hack would be:

def myPrint(module_name):
    pkg = os.path.dirname(__file__)
    sys.path.insert(0, pkg)
    try:
        module = __import__(module_name)
    except:
        raise
    finally:
        sys.path.remove(pkg)
    module.f()

Maybe you can achieve a cleaner implementation with the importlib module.

tynn
  • 38,113
  • 8
  • 108
  • 143