1

I have a structure like the following one:

/src
    __init__.py
    module1.py
    module2.py
/tests
    __init__.py
    test_module1.py
    test_module2.py
/notebooks
    __init__.py   
    exploring.ipynb
main.py

I'd like to use the notebook 'exploring' to do some data exploration, and to do so I'd need to perform relative imports of module1 and module2. But if I try to run from ..src.module1 import funct1, I receive an ImportError: attempted relative import with no known parent package, which I understand is expected because I'm running the notebook as if it was a script and not as a module.

So as a workaround I have been mainly pulling the notebook outside its folder to the main.py level every time I need to use it, and then from src.module1 import funct1 works.

I know there are tons of threads already on relative imports, but I couldn't find a simpler solution so far of making this work without having to move the notebook every time. Is there any way to perform this relative import, given that the notebook when called is running "as a script"?

42piratas
  • 555
  • 1
  • 9
  • 26

1 Answers1

2

Scripts cannot do relative imports. Have you considered something like:

if __name__ == "__main__":
    sys.path.insert(0,
        os.path.abspath(os.path.join(os.getcwd(), '..')))
    from src.module1 import funct1
else:
    from ..src.module1 import funct1

Or using exceptions:

try:
    from ..src.module1 import funct1
except ImportError:
    sys.path.insert(0,
        os.path.abspath(os.path.join(os.getcwd(), '..')))
    from src.module1 import funct1

?

  • 1
    No, I haven't considered that. Thank you for sharing. – 42piratas Sep 11 '20 at 15:02
  • First: notebooks don't create the variable ````__file__````, as confirmed in a few other threads. I was able to workaround that though using ````os.getcwd()````, i.e. ````os.path.abspath(os.path.join(os.getcwd(), '..')))````. However, because the submodules that are involved in the process also perform relative imports themselves, it gets a mess as if the notebook path was always the root path requesting other relative imports – 42piratas Sep 13 '20 at 01:57
  • First, you're right about the `__file__` variable, I didn't tests it for the nb, corrected the answer. Second, it would be nice, if you said what's your error exactly, because it works fine for me, while I run nb as a script, and modules perform relative imports INSIDE their packages. Maybe, you get this error: "ValueError: attempted relative import beyond top-level package"? Then, it has nothing to do with nb. You could check this out https://stackoverflow.com/questions/6323860/sibling-package-imports. – Yelyzaveta Velizhanina Sep 13 '20 at 11:46
  • No, because everything works pretty well when I run the modules with the regular process (calling the modules from main.py level etc, and I have several sub- and sub-sub-folders). It runs fine even when I move the same notebooks to the main.py level, but not otherwise, when they are within any of the sub-levels. I'm aware of "Sibling package imports", also of that famous thread in particular, but there's something different with notebooks. – 42piratas Sep 15 '20 at 19:04