2

I try to understand how to split up python files belonging to the same project in different directories. If I understood it right I need to use packages as described here in the documentation.

So my structure looks like this:

.
├── A
│   ├── fileA.py
│   └── __init__.py
├── B
│   ├── fileB.py
│   └── __init__.py
└── __init__.py

with empty __init__.py files and

$ cat A/fileA.py 
def funA():
    print("hello from A")

$ cat B/fileB.py 
from A.fileA import funA

if __name__ == "__main__":
    funA()

Now I expect that when I execute B/fileB.py I get "Hello from A", but instead I get the following error:

ModuleNotFoundError: No module named 'A'

What am I doing wrong?

Nick
  • 2,862
  • 5
  • 34
  • 68
Natjo
  • 2,005
  • 29
  • 75

2 Answers2

3

Your problem is the same as: Relative imports for the billionth time

TL;DR: you can't do relative imports from the file you execute since main module is not a part of a package.

As main:

python B/fileB.py

Output:

Traceback (most recent call last):
  File "p2/m2.py", line 1, in <module>
    from p1.m1 import funA
ImportError: No module named p1.m1

As a module (not main):

python -m B.fileB

Output:

hello from A
madjaoue
  • 5,104
  • 2
  • 19
  • 31
  • I'm not sure if I exactly understand what you mean with *main* module. But when I run python with the `-m` parameter I get this error: `/usr/bin/python: Error while finding module specification for 'B/fileB.py' (ModuleNotFoundError: No module named 'B/fileB')` – Natjo Jul 23 '18 at 14:38
  • My bad, it's a typo. You can run it as `python -m B.fileB`. – madjaoue Jul 23 '18 at 14:39
  • Thank you, that works. Only if you have the time, could you add some details about how (and why) this works? Or just some links to a helpful documentation? I didn't read much about this when I was looking through the official documentation. – Natjo Jul 23 '18 at 14:41
  • ok sorry, I didn't notice you have already added another link. Thank you! – Natjo Jul 23 '18 at 14:41
  • 1
    I just edited my post to a very detailed explanation. Hope it's clearer ;) – madjaoue Jul 23 '18 at 14:42
2

One way to solve this is to add module A into the path of fileB.py by adding

import sys
sys.path.insert(0, 'absolute/path/to/A/')

to the top of fileB.py.

Fabian Ying
  • 1,216
  • 1
  • 10
  • 15
  • Then I would have to add this line to every file that references to code in other directories? Is this the standard way in python? – Natjo Jul 23 '18 at 14:29
  • But yes, your approach works :) But doesn't seem like a good solution for bigger projects – Natjo Jul 23 '18 at 14:31
  • In bigger projects, you would have both `A` and `B` being submodules of some module `module`, and then change the import statement to `from module.A.fileA import funA`. Then you only need to add `module` into the path of any script you want to run (so only in `fileB.py`, in your example). You do not need to add it in any other files, as long as you don't execute them as the `__main__` script. – Fabian Ying Aug 09 '18 at 19:54