0

Let me preface this by saying that I understand that imports are a frequently touched-upon/complained-about topic in the Python community. I only wish that a simple import system is developed but alas. Being as that is, I have referred a lot of places for potential solves already; please check in the below paras the links to other SO question threads which I've already been through.

Here's the directory structure for my project:

Directory structure

I wish to import file1.py from folder1 of the main_folder into my code in file2.py.

Hence the importing code in file2.py is:

from main_folder.folder1.file1 import some_func

I try to run file2.py normally from the application directory (python main_folder/folder2/file2.py)

I have also tried the following possible solves in the same conditions (all to no effect):

from application.main_folder.folder1.file1 import some_func # after adding init to application folder

and...

from folder1.file import some_func

and...

from .folder1.file1 import some_func

and...

from ..folder1.file1 import some_func

I have tried the answers suggested at this other question as well. The second-most popular answer seems to be the most pythonic way to do it and I am indeed trying that very approach above. However, that answer does not seem to work for a lot of people (and I) who have indicated this in the comments and have suggested opening another question regarding the same.

If this approach does not work, then what sys.path.append() command should I add at the top of file2.py to be able to from folder1.file1 import some_func? I understand that this sys.path.append method isn't the most pythonic way to do it but unfortunately we seemingly have no better solve until the guys developing Python set something in motion.

martineau
  • 119,623
  • 25
  • 170
  • 301

1 Answers1

0

You may be interested in reading documentation about the Python import system and the sys.path variable.

When your program starts, Python will initialize the sys.path variable based on the PYTHONPATH environment variable. It lists the directories into which it will search for packages (directories containing an __init__.py file) when you import something.

To prevent import conflicts (and for clarity), it is better to use your application name as top-level package. That's what you want to do, good !

But to make from application.main_folder.folder1.file1 import some_func work, Python has to find a package named application in one of the directories listed in its sys.path.

From there, either you can ensure that when your program gets called, the PYTHONPATH will contain the directory containing your application package, or you will have to add it yourself by mutating sys.path.

The first solution is generally simpler and saner, because it is how libraries are meant to work : put them in a directory where Python looks for, and you're done, it just works !

The second solution requires you to ensure that, whichever way any of your files gets called, it will result in your top-level package's parent directory being added to the sys.path (prepending or appending, in your case it does not matter much). Putting it in only once is cleaner. But it must be there before any import instruction gets executed. How to implement that depends on how your library is used.

You say :

I try to run file2.py normally from the application directory (python main_folder/folder2/file2.py)

The PYTHONPATH documentation mentions that :

An additional directory will be inserted in the search path in front of PYTHONPATH as described above under Interface options.

If you ask Python to run four file2.py which contains import sys; print(sys.path), you will see that it contains in the first position the path to folder2 (C:\PycharmProjects\StackOverflow\lib68213183\main_folder\folder2 for me).

Adding import pathlib; sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent.parent)) adds the application's parent directory to the search path (you can check by re-printing sys.path). Now you can import : from lib68213183.main_folder.folder1.file1 import say_hello; say_hello() works.

But if someone runs file1.py instead, the path is not changed (the code that does it is in file2.py, which you can not import because the parent's parent's parent's parent is not in the search path) so you have to do it there too. You will have to add your top-level package's parent directory to sys.path in each file that may get invoked from the command line. It is a bit cumbersome, but if you only have a few it may be OK.

The simpler solution is to add a __init__.py file into your application directory (making it a package), adding the application's parent directory in the PYTHONPATH and you're set ! And if you intend to distribute your code, it will simplify things too.

Lenormju
  • 4,078
  • 2
  • 8
  • 22