Reputation: 1638
I have the following directory structure:
root
/src
file1.py
file2.py
/libs
__init__.py
package.so
I wish to import package.so
within file1.py
.
I've tried the following import statements to no avail:
from .libs.package import func
from libs.package import func
from .libs import package
from libs import package
I want to avoid having to set PYTHONPATH
/ sys.path
.
Is there a simple way to do this? I assume the issue is due to the package being a shared object and not just a Python file - I don't have access to the source code for it.
Thanks, Adam
Upvotes: 6
Views: 1414
Reputation: 26901
In order to import a file from the directory above, you should use ..
In your case, you need to import using one of the following lines:
from ..libs.package import func
from ..libs import package
from root.libs.package import func
from root.libs import package
Keep in mind that according to the python documentation, using a full path instead of ..
is preferred, thus from root.libs
is a better choice.
Regarding not being able to traverse up: If your main script is file1.py
you should start it from the directory containing root
like so:
python -m root.src.file1 args
This way python will treat your root as a package.
Last but not least: As you're using Python 2, you'll need to put __init__.py
in every directory, including src
and root
.
Upvotes: 0
Reputation: 3988
You can use relative import as described in python docs:-here
Also it only works well for directories under package which will not ask for beyond import. If so will happen then this error will occur:-
valueError: attempted relative import beyond top-level package
You can refer this question too for same:- value error for relative import
Upvotes: 0
Reputation: 1916
If you are intent on not using sys.path.append
to import the file, I was able to do it using the following snippet in file1.py
:
import imp
import os
file = os.sep+os.path.join(*os.path.realpath(__file__).split(os.sep)[:-1]+['..','libs','package.so'])
package = imp.load_source('root.libs.package', file)
print package.a()
Which prints <root.libs.package.a instance at 0x101845518>
. Note that my package.so file is just a python file that defines a dummy class a
so that I could test importing it. From what I have read, I believe that replacing imp.load_source
with imp.load_dynamic
may be what you want.
Breaking it down:
os.path.realpath(__file__).split(os.sep)[:-1]
gets you the path to the directory the currently-running script is in, as a list of strings.
+['..','libs','package.so']
concatenates a list containing the parent directory (..
), the libs
directory, and your filename to that list, so that os.path.join will build the full path to the package.so
file.
os.path.join(*[that list])
unpacks the list elements into arguments to os.path.join
, and joins the strings with os.sep
. I also add a leading os.sep
since it is an absolute path.
imp.load_source
returns a module with the name root.libs.package
loaded from the file path.
This source was useful for writing this answer, and here are the docs for the imp
module, which you might also find useful.
Upvotes: 4