pythonpython-importimporterrorrelative-import

How to fix ImportError: attempted relative import with no known parent package


I was working on a "hoop detection" program for FRC, and I wanted to organize the structure. I created the __init__.pys, rearranged the imports and updated the paths. Then I ran my code which is in misc/calibration/. After all, I got the error: ImportError: attempted relative import with no known parent package. I tried some stuff but none of them worked.

Here is my project tree:

├── cascade.xml
├── images
│   ├── ref-pic.jpeg
│   └── ref-pic-post.jpeg
├── LICENSE
├── misc
│   ├── bash
│   │   ├── install_os_dependencies.sh
│   │   ├── pip_install.sh
│   │   └── set_camera.sh
│   ├── calibration
│   │   ├── __init__.py
│   │   ├── pixel-calculator.py
│   │   └── shoot-a-photo.py (This is the one I'm trying to run.)
│   ├── functions
│   │   ├── fix_camera.py
│   │   ├── __init__.py
│   │   └── set_camera.py
│   ├── __init__.py
│   └── viewer.py
├── requirements.txt
├── settings.ini
├── settings.ini.template
└── vision.py

5 directories, 19 files

And here is my import statement:

from ..functions import set_camera

And the full error message:

Traceback (most recent call last):
  File "/home/egeakman/repos/vision-2021/misc/calibration/shoot-a-photo.py", line 7, in <module>
    from ..functions import set_camera
ImportError: attempted relative import with no known parent package

This is the project repository if it makes any good: https://github.com/Scorpions-Robotics/vision-2021

Should I import it differently or is there another way? Thanks in advance, have a good day.


Solution

  • Should I import it differently or is there another way?

    No, the import is alright. It instructs python to go to the parent package (of the package the file you are running is in) there it will find another package called functions, then from there import set_camera. But as the error message says:

    attempted relative import with no known parent package

    python can't find the parent package to do the relative import. That parent package is not (and for technical reasons, like import hooks, can not be) the parent directory of the file you are running. For one, python would have to scan the whole filesystem to find possible packages. Instead, python scans the directory it's run from, in this case calibration finds no parent package (or indeed any package structure) and boom. So yes there is another way - give python the fully qualified name of the module you want to run. To do so you need to first rename the shoot-a-photo.py file to be a valid module name shoot_a_photo.py. Then cd to the parent directory of misc and use the -m switch:

    $ cd ../..
    $ ls
    cascade.xml images LICENSE misc ...
    $ python -m misc.calibration.shoot_a_photo # note no py
    

    This tells python to run the module (not file) shoot_a_photo who is part of package misc.calibration. Package misc will be detected alright as a direct child of the working dir, containing an __init__.py file, and its subpackages will be indexed.

    The -m switch is the canonical way of running a python script that is part of a package