0

I'm trying to import from a parent folder. The folder structure is (ignore the names)

experiments
    __init__.py
    poppy.py
    ostepop
        __ init__.py
        importio.py
   nopop
        __ init__.py
        loggio.py

I tried adding __init__.pyto every folder, but it didn't have any affect

import experiments.ostepop.loggiogives error message:

ModuleNotFoundError: No module named 'experiments'

and from ..experiments import poppy gives

ImportError: attempted relative import with no known parent package

Any tips on how to import poppy.py or loggio.py from importio.py?

Karoline
  • 9
  • 1
  • 3

3 Answers3

2
import os
import sys
# Append parent directory to import path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

After this you can import your modules as if they were at, or under, the same directory as your source file. So from importio.py you can

import poppy # noqa
import nopop.logio # noqa

The # noqa is there to suppress "PEP 8: E402 module level import not at top of file" warning.

The __init__.py files are unnecessary for this solution, but you may want to keep them (except the top level one), if you plan to convert your subdirectories to modules one day.

If you want to understand how this solution work, please run

print(__file__)
print(os.path.abspath(__file__))
print(os.path.dirname(os.path.abspath(__file__)))
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

It will print:

  • The current file name
  • The current file name, with absolute path
  • The current directory, with absolute path
  • And the parent directory, with absolute path

And sys.path.insert(0, ...) inserts this path to the beginning of the search path.

pintergabor
  • 428
  • 5
  • 8
0

They are plenty of posts already, but it's still a tricky stuff to me as well.

So, though I'm still not sure what's the best practice, anyway here is how I handled this problem.

In the module where you want to do the imports, add

import sys
import os
sys.path.append(os.path.join(sys.path[0], '..'))

sys.path[0] is the absolute path to the module without the file name. It works both when the module is and is not the top-level script. If you don't know what is top-level script and how is it related to import mechanism, read this.

os.path.join is used to probably handle system difference. Anyway, os.path.join(sys.path[0], '..') will point to the parent path.

sys.path.append add that parent path to the searching space.

So, in your case, add previous code to importio.py, then you can do

from nopop import loggio
import poppy

in importio.py as well.

__init__.py is not used at all in this solution. You can delete them. But I've seen many repos using __init__.py. So the best practice might involve using them.

jiyolla
  • 27
  • 6
0

If I understand you correctly, you want to import poppy.py from importio.py and debug with file model. Under this model, Python interpreter will not think of it as a package, so this code (import experiments.ostepop.loggio and from ..experiments import poppy) is invalid.

To solve this problem, you can debug this script with package model, which means run python -m experiments in terminal. It may be run correctly.

hobee
  • 1