Reputation: 91
I have the following file structure
├── test.py
└── sub
├── foo.py
└── bar.py
With test.py:
# test.py
from sub import foo
foo.test()
And foo.py:
# foo.py
from . import bar
def test():
bar.test()
And bar.py:
# bar.py
def test():
print('This is a test')
This works fine when invoking test.py from the command line.
home/$ python test.py
This is a test
Now I want to additionally be able to call foo.py directly from command line. So I change foo.py to:
# foo.py
from . import bar
def test():
bar.test()
if __name__ == '__main__':
test()
But when I call this it does not work
/home$ cd sub
/home/sub$ python bar.py
Traceback (most recent call last):
File "foo.py", line 1, in <module>
from . import bar
ImportError: cannot import name 'bar' from '__main__' (foo.py)
This makes sense since the python documentation states
Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.
So I can change the import statement in foo.py to
# foo.py
import bar
But then calling test.py does not work anymore.
/home$ python test.py
Traceback (most recent call last):
File "test.py", line 1, in <module>
from sub import foo
File "/home/chr/code/import/sub/foo.py", line 1, in <module>
import bar
ModuleNotFoundError: No module named 'bar'
Is there any way around this or is it simply not possible to use bar.py from two different mains?
Edit: One solution could be
if __name__ == '__main__':
import bar
else:
from . import bar
But this looks pretty ugly
Upvotes: 6
Views: 3066
Reputation: 5945
The solution you provided in the question is definitely one of them.
I'm afraid the other solution I have to offer isn't pretty either. But since it's another solution, I'm writing an answer.
Make these few changes and it should work.
# bar.py
import bar # use an absolute import
def test():
bar.test()
if __name__ == '__main__':
test()
Add these two lines to test.py
. Adding a path to sys.path
will make that location (module) available for imports. You can simply import the module after that.
import sys
sys.path.append('./sub')
import foo
foo.test()
This is my structure, same as yours.
.
├── sub
│ ├── bar.py
│ └── foo.py
└── test.py
Running both the files work.
$ python3 test.py
This is a test
$ python3 sub/foo.py
This is a test
Upvotes: 1