How to Import a Python Module from a Sibling Folder

How to import a Python module from a sibling folder?

This is happening because A and B are independent, unrelated, packages as far as Python is concerned.

Create a __init__.py in the same directory as Driver.py and everything should work as expected.

Sibling package imports

Seven years after

Since I wrote the answer below, modifying sys.path is still a quick-and-dirty trick that works well for private scripts, but there has been several improvements

  • Installing the package (in a virtualenv or not) will give you what you want, though I would suggest using pip to do it rather than using setuptools directly (and using setup.cfg to store the metadata)
  • Using the -m flag and running as a package works too (but will turn out a bit awkward if you want to convert your working directory into an installable package).
  • For the tests, specifically, pytest is able to find the api package in this situation and takes care of the sys.path hacks for you

So it really depends on what you want to do. In your case, though, since it seems that your goal is to make a proper package at some point, installing through pip -e is probably your best bet, even if it is not perfect yet.

Old answer

As already stated elsewhere, the awful truth is that you have to do ugly hacks to allow imports from siblings modules or parents package from a __main__ module. The issue is detailed in PEP 366. PEP 3122 attempted to handle imports in a more rational way but Guido has rejected it one the account of

The only use case seems to be running scripts that happen
to be living inside a module's directory, which I've always seen as an
antipattern.

(here)

Though, I use this pattern on a regular basis with

# Ugly hack to allow absolute import from the root folder
# whatever its name is. Please forgive the heresy.
if __name__ == "__main__" and __package__ is None:
from sys import path
from os.path import dirname as dir

path.append(dir(path[0]))
__package__ = "examples"

import api

Here path[0] is your running script's parent folder and dir(path[0]) your top level folder.

I have still not been able to use relative imports with this, though, but it does allow absolute imports from the top level (in your example api's parent folder).

How to import python modules from sibling directory?

Since there are already many answers on SO for this*, I will focus on question (2). About what is a better code organization:

|- setup.py
|- top_pkg_name
|- __init__.py
|- pkg1
|- __init__.py
|- pkg2
|- __init__.py

The (relative) import is done as follows, from inside module_2:

from ..pkg1 import module1 as m1

Alternatively, you can use absolute imports, which refer to the top package name:

from top_pkg_name.pkg1 import module1 as m1

In such an organization, when you want to run any module as a script, you have to use the -m flag:

python -m top_pkg_name.pkg1.module1

For question (3), I'm not sure but it looks like the unittest module adds the folder to path, allowing the imports to happen directly.

*Refer:

  1. How do I import a Python script from a sibling directory?
  2. Python import module from sibling folder

Python3 import module from sibling directory

I found out, that I could work with sys.path.append & os.path.abspath. So the solution is like this:

directory stucture:

Root
-- main.py
-- __init__.py

-- folder1
----- __init__.py
----- a.py

-- folder2
----- __init__.py
----- b.py

To use testFunction from folder1/a.py in folder2/b.py the code in b.py should be like this:

import sys
import os

sys.path.append(os.path.abspath('../Root/folder1'))
from a import testFunction

Import from sibling directory - Python 3.7

Relative imports only work within the root of each library path and you cannot use relative import to reach the parent of the root of a library path. In the case of importing modules from your own project the root path of the library is where the interpreter is run, so in order to import utils/utilsFile.py you have to run extractionFile.py from framework instead of extraction.

If you do want to be able to run extractionFile.py from extraction, however, an easy solution would be to add .. to the library path by appending it to the sys.path list, so that the parent directory of extraction would be one of the library paths, and so that you can import from utils.utilsFile directly:

import sys
sys.path.append('..')
from utils.utilsFile import functionName


Related Topics



Leave a reply



Submit