Reputation: 403
This question is in context of python 2.7 and relative imports. I have gone through related questions and things are still not working for me. I don't know what am I missing here?
Following is my dir hierarchy
.
|-> wrapper.py
|-> __init__.py
|-> util
| |-> hello.py
| |-> __init__.py
|-> src
| |-> wrapper.py
| |-> __init__.py
All __init__.py are blank files only to "treat the directories as containing packages"
Following is how ./util/hello.py reads. This has its own main function and can run of its own.
#!/usr/bin/python
# This is hello.py.
import sys
# Define a main() function that prints a little greeting.
def main():
print "Hello World!!!"
# Standard boilerplate that calls the main() function.
if __name__ == '__main__':
main()
Following is how ./wrapper.py reads. This also has its own main function and uses ./util/hello.py to achieve its goal.
#!/usr/bin/python
# This is wrapper.py.
import sys
from util import hello
# Define a main() function that prints a little greeting.
def main():
hello.main() # This prints "Hello World!!!"
# Standard boilerplate that calls the main() function.
if __name__ == '__main__':
main()
Following is how ./src/wrapper.py reads.
#!/usr/bin/python
# This is wrapper.py.
import sys
from ..util import hello
# Define a main() function that prints a little greeting.
def main():
hello.main() # This prints "Hello World!!!"
# Standard boilerplate that calls the main() function.
if __name__ == '__main__':
main()
As you see, It's almost exact copy of ./wrapper.py with minimal changes to make it run (changes in import). All __init__.py are present too. However any attempt to run it gives following error.
Traceback (most recent call last):
File "wrapper.py", line 8, in <module>
from ..util import hello
ValueError: Attempted relative import in non-package
However, if I import hello.py as following it works:
import os
sys.path.append(os.path.abspath("../util/"))
import hello
Two Questions:
Q1. What am I doing wrong or what is missing my attention?
Q2. How can I code ./src/__init__.py such that just "import hello" works in ./src/wrapper.py?
Upvotes: 2
Views: 183
Reputation: 517
The simple answer is that you need to have a parent package for all your code. You can't just put __init__.py
in the root directory and expect it to behave as a package.
I'll split your options into good and bad, starting with the bad:
Bad - relative imports:
What you should do is put all your code (aka .
) in a package named appropriately (src
is a bad name for a package btw). Say mypackage
. Then you'll be able to import src.wrapper
only as mypackage.src.wrapper
, from places where it is available on the python path, like a python interpreter open in the directory containing mypackage
. Installing the package also makes it available on the path.
For more information on relative imports and why they are bad:
Good - non-relative imports:
The better approach is import through the package in an absolute manner. You still have to create a parent package mypackage
, but this time you get rid of the relative imports and use import mypackage.util.hello
from inside wrapper.py
. For this to work you have to set the python path to include the directory containing mypackage
.
The recommended way to do this is create a setup.py
file and install your package. For development you should use python setup.py develop
or pip install -e .
More on python packaging: https://packaging.python.org/distributing/
Edit:
for your Q2, if you use absolute imports you can use import mypackage.util.hello as hello
or from mypackage.util import hello
. Both are the same.
In some special cases you may be interested in writing import util.hello as hello
inside /mypackage/__init__.py
, and then you could use from mypackage import hello
etc.
Upvotes: 1