amitchone
amitchone

Reputation: 1638

Import binary package from different directory

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

Answers (3)

Bharel
Bharel

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

Vicrobot
Vicrobot

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

MoxieBall
MoxieBall

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

Related Questions