Programmatically importing module via importlib - __path__ not set?

14,831

This is an old question, but since it was bumped, the other answer is totally wrong, and this is a common problem:

You're probably doing this.

python oopsd/oopsd.py

Don't do this. :)

Specifically, NEVER try to directly run a file that's part of a parent package. When you run python FILENAME, Python adds the file's containing directory to sys.path, and DOESN'T add the current directory. So you have oopsd/ in your path, and every module in oopsd/ just became a top-level module. Python has no way of even knowing that any of them are supposed to have an oopsd. prefix, because the parent directory doesn't exist anywhere in sys.path.

If you want to execute a module directly, do this:

python -m oopsd.oopsd

This puts the current directory in sys.path and ensures that imports of your source tree work as you'd expect them to.

Alex Z's answer is wrong because it doesn't actually fix this problem, and it's not a relative import — implicit relative imports no longer exist in Python 3.

Share:
14,831
The Compiler
Author by

The Compiler

Full-time geek. LaTeX fetishist. Perfectionist sometimes. Loves: Linux, PCs, Hacking, 8-bit, Demoscene, Electronics, Android

Updated on June 12, 2022

Comments

  • The Compiler
    The Compiler almost 2 years

    I'm trying to import a sub-module programmatically. My file tree looks like this:

    oopsd/__init__.py
    oopsd/oopsd.py
    oopsd/driver/__init__.py
    oopsd/driver/optiups.py
    

    The optiups.py simply prints "Hello World".

    The oopsd.py looks like this:

    import importlib
    importlib.import_module('oopsd.driver.optiups')
    

    Now with this, I'm getting this exception:

    Traceback (most recent call last):
      File "<frozen importlib._bootstrap>", line 1521, in _find_and_load_unlocked
    AttributeError: 'module' object has no attribute '__path__'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "oopsd/oopsd.py", line 29, in <module>
        sys.exit(main())
      File "oopsd/oopsd.py", line 23, in main
        loaddriver()
      File "oopsd/oopsd.py", line 26, in loaddriver
        importlib.import_module('oopsd.driver.optiups')
      File "/usr/lib/python3.3/importlib/__init__.py", line 90, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
      File "<frozen importlib._bootstrap>", line 1586, in _gcd_import
      File "<frozen importlib._bootstrap>", line 1567, in _find_and_load
      File "<frozen importlib._bootstrap>", line 1514, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 313, in _call_with_frames_removed
      File "<frozen importlib._bootstrap>", line 1586, in _gcd_import
      File "<frozen importlib._bootstrap>", line 1567, in _find_and_load
      File "<frozen importlib._bootstrap>", line 1524, in _find_and_load_unlocked
    ImportError: No module named 'oopsd.driver'; oopsd is not a package
    

    Does __path__ even still exist in Python 3?

    I also tried importing .driver.optiups instead, but this yields:

    TypeError: relative imports require the 'package' argument
    

    __package__ seems unset, so I'm lost.

    How do I do this the right way?

  • The Compiler
    The Compiler almost 10 years
    I also learned more about modules and packages since asking the question, and completely forgot about that project in the meantime :D After using -m and adjusting some import so they actually import with the full dotted path, everything works!