TimF TimF - 9 days ago 5
Python Question

How to import a python file from another folder in Python 3.5 on OSX?

I use Python 3.5 and my project structure is like this:

Project/
App/
myApp.py
Libraries/
myLibA.py
myLibB.py


I want to import
myLibA.py
in
myApp.py


If I simply write
from Libraries import myLibA
I end up with this error :


ImportError: No module named Libraries.


I found the Q/A Importing files from different folder in Python, from which I adapted my own solution, adding this at the beginning of
myApp.py
in order to add my
Project
folder to the Python Path :

import sys
sys.path.insert(0, sys.path[0] + "..")


This worked well on Windows, but when I run
myApp.py
from the same project on OSX (10.9) I see the same error message, my module is not found.

To reproduce my issue it's very simple. Just fill the Python files like this :

myApp.py :

import sys
sys.path.insert(0, sys.path[0] + "..")

from Libraries import myLibA

if __name__ == '__main__':
myLibA.print_hello()


myLibA.py :

def print_hello():
print("Hello")


I don't understand why the Python Path method doesn't work here. Anyway, I'm looking for a solution that keeps the Python file compatible with Windows and that is contained in the sources (in the Python files). I've seen a few console hooks but I'm not satisfied with that because I want to be able to clone the project on any OSX/Windows PC with Python 3.5, and just run myApp.py. I'm looking for a solution that doesn't involve any library not natively present in Python 3.5.

Is there another way to achieve this ?

(If not, is it because it is somehow not pythonic to organize a project like this? As a C developer I might have the wrong approach)

Answer

Add __init__.py to your Libraries directory. That file can be empty, and it magically turns the Libraries directory into a package. Now:

import sys
import os.path
libdir = os.path.dirname(__file__)
sys.path.append(os.path.split(libdir)[0])   

from Libraries import myLibA

if __name__ == '__main__':
    myLibA.print_hello()

The __file__ special variable gives the filename of the current script. os.path.dirname() gives the directory it resides in, and os.path.split(libdir)[0] gives its parent directory. This should work wherever the script is called from.

I am using append rather than insert. It is generally advised that user directories are searched last, and also append is more efficient than insert in the C Python implementation.