Import Sibling Directory (yet again) - python

I have the following directory structure:
src/
main/
somecode/
A.py
B.py
__init__.py
__init__.py
test/
somecode/
testA.py
testB.py
__init__.py
__init__.py
__init__.py
I was able to successfully add the following to the test modules:
import sys
sys.path.insert(0, "absolute path to src")
which allowed me to run nosetests from the src folder. But the problem is when other people use my code, this doesn't work because their absolute path doesn't is different.
So then I tried:
import sys, os
sys.path.append(os.path.abspath('../../../main/somecode')
from main.somecode import A
which worked great from src/test/somecode, but I can't run nosetests from the src folder since the relative path doesn't work from there.
I also tried to do from ...main.somecode import A but it doesn't like that even though they are all python packages.
So what do I do? This seems like a potential answer but he doesn't explain where to add the code.

Instead of using a relative path ("../../../main/somecode"), you
can do the same but using the __file__ global variable:
tests_dir = os.path.dirname(__file__)
sys.path.append(os.path.join(tests_dir, "..", "..", "..", "main", "somecode"))
I would put that in the __init__.py file under "test/somecode", instead
of adding it for each test module file.

Related

Importing from folders at the same hierarchy level

I've been looking around this site for how I can import a class stored in a folder at the same hierarchy level. What I found is that using .. should bring me up one folder. Or at least, that is how I read it as that assumption seems to be wrong.
src/
folderStrucutre1/
__init__.py
fileToImport.py <- contains A
folderStrucutre2/
someFile.py
__init__.py
abc.py
Having above folder structure in which fileToImport.py contains a class named A. How would I import A into someFile.py?
Due to how packages work in python, you need to move src and abc.py into a subfolder, and provide an __init__.py for it.
The directory structure should look like this after the changes:
package-name/
package-name/
folderStructure1/
__init__.py
fileToImport.py <- contains A
folderStructure2/
__init__.py
someFile.py
__init__.py
abc.py
Then, in someFile.py you can import A using a relative import from the parent package:
from ..folderStructure1.fileToImport import A
Lastly, you should open the topmost folder (parent to abc.py) for IDE intellisense to work
First, we need to create the absolute path to your src folder without hard-coding it in your script to make it portable.
Add this code in your someFile.py file.
import os
src_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
Now, let's add your folderStructure1 directory to the Python Search Path
import sys
sys.path.append(src_path + '/folderStructure1')
Now you can use the following:
from fileToImport import Class
object = Class()
You can add src to the python search path and then you can import A from fileToImport.py.
For this, you should write someFile.py like:
import sys
sys.path.append("..") # .. represente the father folder
from folderStrucutre1.fileToImport import A
instance_for_A = A()

Importing parent modules in complex directory structures?

How do I link the util.py file to the script.py file?
App
Module
__init__.py
util.py
Main
__init__.py
Dir1
script.py
__init__.py
Dir2
script.py
__init__.py
Take this directory layout of my app. It's a bit more complex for requirement reasons to keep the scripts easily separated while sharing the same module across each script. However, it's difficult to find the correct way to import that module to each script due to directory hierarchy.
Environment
Python 2.7, Windows 10, 64Bit
Just add the root directory to the PYTHONPATH. Then you can use absolute imports as well as the relative ones.
# script.py
form Module.util import _
You can put:
import sys
sys.path.insert(1, '.')
in your Module.__init__.py and then just import it in script.py with:
from Modules import util
Additionally you can define a __all__ = [] variable in your __init__ and then you can star import.

sys.path including py.test rootdir to make tests import relative to project root

I'm having problems with pytest not including my projects rootdir in sys.path list. Instead it is including the directory where the tests are located by default.
Here is my project structure.
proj/
setup.py
mypackage/
__init__.py
a.py
tests/
test_a.py
when running pytest with
py.test proj/mypackage/tests
it inserts proj/mypackage/tests into sys.path which is not good because now I cannot import a since its not relative to the tests directory.
I've noticed that py.test detects a rootdir, this is recognized as the root of my project which is the proj directory. This is what I want in sys.path during tests so all my code is relative to that directory. How do I ensure py.test includes (...)/proj/ in sys.path so that I can import mypackage.a in test_a.py.
I use a conftest.py that appends the package path (relative to the conftest.py file) to sys.path so the package can be imported. Something like this:
# contents of conftest.py
import sys
from os.path import abspath, dirname
package_path = abspath(dirname(dirname(__file__)))
sys.path.insert(0, package_path)
You would then put this file in the tests directory. The conftest.py file will get run before any thing else by default, so the other tests will be able to import mypackage.
Another, probably better, approach is to add a setup.py and follow the advice given here.

how to import nested module from nested module

Simple question, but could not find the answer.
I've following structure:
./lib1:
main.py
./lib2:
__init__.py utils.py
From the root diretory, I'm running:
python lib1/main.py
and in main.py I want to import lib2/utils.py.
adding import lib2/utils.py fails.
One solution I found is to add:
~/tmp/root$ cat lib1/main.py
import sys,os
sys.path.append(os.getcwd())
import lib2.utils
lib2.utils.foo()
which is good, but I wander if there is other solution. Thanks.
Are lib1 and lib2 separate modules? If yes, the comment by #BrenBarn applies: You need to add the top directory (containing lib1 and lib2 to the Python path (e.g using PYTHONPATH environment variable or appending to sys.path).
If both lib1 and lib2 are part of one module (i.e. there is a __init__.py file in the top directory) you can use relative imports (https://docs.python.org/2.5/whatsnew/pep-328.html).
Your problem is caused by using the wrong directory structure. The main.py script should be in the same top-level directory as the package that it needs to import. So the structure should look like this:
project /
lib2 /
__init__.py
utils.py
other.py
main.py
The directory of the main script will always be added to the start of sys.path, so this will guarantee that any packages in that directory can be always be directly imported, no matter where the script is executed from.
To import the utils module into main.py (or other.py), you should do:
from lib2 import utils

Python - Doing absolute imports from a subfolder

Basically I'm asking the same question as this guy: How to do relative imports in Python?
But no one gave him a correct answer. Given that you are inside a subfolder and you want to go up a directory and then into ANOTHER subfolder, doing what they suggested does not work (as the OP pointed out in his comments to their answers).
I know that you can do this by using sys.path, but I would prefer a cleaner method.
Example:
App
__init__.py
Package_A
--__init__.py
--Module_A.py
Package_B
--__init__.py
--Module_B.py
How would I import Module_A into Module_B?
main.py
setup.py
app/ ->
__init__.py
package_a/ ->
__init__.py
module_a.py
package_b/ ->
__init__.py
module_b.py
You run python main.py.
main.py does: import app.package_a.module_a
module_a.py does import app.package_b.module_b
Alternatively 2 or 3 could use: from app.package_a import module_a
That will work as long as you have app in your PYTHONPATH. main.py could be anywhere then.
So you write a setup.py to copy (install) the whole app package and subpackages to the target system's python folders, and main.py to target system's script folders.
If I'm reading correctly, in Python 2.5 or higher:
from ..Module_B import Module_B
I thought I was well-versed in Python but I had no idea that was possible in version 2.5.
If you are then importing Module_B in to App, you would
Module_B.py:
import ModuleA
App.py (which also imports ModuleA which is now by default in your Pythonpath)
import Module_B.Module_B
Another alternative, is to update __init__.py (the one in Module_A/App folder) to:
import os
import sys
sys.path.extend('%s../' % os.getcwd())
import ModuleA
Another alternative, is to add your folder to the PYTHONPATH environment var.

Categories