2

I have truly tried my best to understand python imports, but it makes no sense to me. I know there's a million SO threads on this but none of them have helped me understand what's going on.

I have this simple structure:

project/
    run.py
    datasets/
        __init__.py
        config.py
        datasetA.py

datasetA.py:

from config import classes
dosomething()

run.py:

from datasets import datasetA

And when I execute run.py, I get ModuleNotFoundError: No module named 'config'. Why? I have tried to include

import datasetA
import config 

as well as

import .datasetA
import .config 

in __init__.py but it makes no difference. datasetA sees __package__ = datasets, so it I think it should see config. run.py sees __package__ = None. What am I missing?

tonyd629
  • 75
  • 7
  • In `datasetA.py`, you should have written `from datasets.config import classes`. Remember, `config.py` is inside a subdirectory, not on project root. – Carl HR Jun 22 '22 at 19:52
  • 1
    The importing will be totally different depending on what and how you are running the program. How do you execute `run.py` and how do you intend to execute it in the future – Iuri Guilherme Jun 22 '22 at 20:02
  • use `from .config import classes` in `datasetA.py` and run – sahasrara62 Jun 22 '22 at 20:13
  • If you're doing `python run.py` while in the `project` folder, then even in the file `datasetA.py` you need to use `from datasets.config import classes`. See my comments on isaa_ctaylor answer. If you look at the traceback you'll see that the ModuleImportError happens when you try to import config from the `datasetA.py` file, but since your top level module is `run.__main__`, config is really datasets.config in every file. – Iuri Guilherme Jun 22 '22 at 20:17

1 Answers1

2

Relative vs absolute imports

Your issue relates to the differences between relative and absolute imports. When you try to import config from datasetA, python looks in the root directory, in this case, project/. To fix this, what you want to do is use a relative import in datasetA. See the difference between the following:

# project/datasets/datasetA.py

# Absolute import
from config import classes

# Python checks for an available import at the root of the project
# (e.g. project/ in this case) and fails as it does not exist

# Relative import
from .config import classes

# Python checks in the current directory
# (e.g. project/datasets/) and succeeds

You can read more about relative and absolute imports here

isaa_ctaylor
  • 311
  • 1
  • 7
  • This will fail because the OP is probably running `python run.py` from the project's root folder, therefore config.classes is actually `from datasets.config import classes` or relative `from .datasets.config import classes`. What I mean is that the top level script is not `project` but `run.__main__` – Iuri Guilherme Jun 22 '22 at 20:04
  • I should have made it more clear, the imports shown are in `datasetA.py`. I will update my answer accordingly – isaa_ctaylor Jun 22 '22 at 20:07
  • Your answer is correct and clear, there's no need to edit it. My point is that the OP is not running the program as a package, in which case relative imports would work as expected because the import path is relative to the file that is importing. He seems to be running it as a script, in which case `__name__ == '__main__'`, and all relative imports are relative to the folder the script is being invoked from the interpreter. – Iuri Guilherme Jun 22 '22 at 20:09
  • This answer already explains in much details what I'm trying to say: https://stackoverflow.com/a/16985066/7839535 – Iuri Guilherme Jun 22 '22 at 20:12
  • The way (I'm assuming) the OP is running the code dictates that all imports should be absolute starting from the root folder, so in every file, regardless of where they reside, the import lines should be done as if the whole program were a single file in the root folder. So config.classes is, for every file in the project, `from datasets.config import classes`. When the program runs as a module or package, then everything changes. – Iuri Guilherme Jun 22 '22 at 20:15
  • Thank you! This has been enlightening. Seems like absolute imports are generally the way to go. – tonyd629 Jun 23 '22 at 13:10