relative reference in python - python

am beginner in python and working on multi folder structure and struggling to refer the files using relative path. tried in different ways to refer the files in other folders but ended up in error "attempted relative import with no known parent package". Can somebody explain how the relative paths will work in python?
here is the example what am trying to achieve..
folder structure
Main
source
Function1
inputs
1.py
2.py
uts
test_1.py
code_1.py
code_2.py
Now inside test_1.py am trying to refer code_1 using relative path like
from ..code_1 import Code
from .code_1 import Code
but, ended up in error..
some where I found that we need to have init.py in each folder to use relative path and I created empty init.py in each folder but, no use..
I may get the answer but more importantly need to know how this relative path works in python.
Thanks in advance

I've also had issues with relative imports in Python and thus I've created an experimental, new import library: ultraimport
It gives you more control over your imports and lets you do file system based imports.
You could then write in your test_1.py:
import ultraimport
Code = ultraimport('__dir__/code_1.py', 'Code')
This would import code_1.py from the same directory as test_1.py.
This will always work, no matter how you run your code.

Related

Why does error occurs when importing from same *sub*directory?

Consider this folder structure:
main.py
module_a/
aa.py
bb.py
__init__.py
In main.py, I import aa as:
from module_a import aa
aa.yyy()
Then in aa.py, I import bb and include its functions as:
import bb
bb.xxx()
However, when I run main.py, python says "No module named 'bb'".
May I know why this happens. What is the correct way to import bb.
Thanks!!!
I have tried to write aa.py as:
import .bb
bb.xxx()
But it still does not work.
why this happens
Because the aa folder is not a place that Python is searching for modules.
Python's imports are absolute by default. They only look in specific places determined by sys.path. In main.py, import module_a.aa works because the root folder of the project happens to be on the sys.path; that folder contains a module_a folder; and that folder contains aa.py.
What is the correct way to import bb.
Please use relative imports between files in your package. In this case, the necessary import in aa.py looks like:
from . import bb
Absolute imports are error-prone; a project that uses two packages whose contents have overlapping names will run into namespace collisions. (Sadly, the standard library uses absolute imports in most places, such that projects need to ban certain module names for safety.) Relative imports will also require much less maintenance, should you later rename a sub-package.
The only thing relative imports require is that the package gets loaded, which typically will happen automatically with the first (yes, absolute) import of any of the package contents. When the package is loaded, it automatically sets a __package__ attribute on the modules in that package, which Python can use to resolve the relative imports. It's important to note that relative imports are relative to the package hierarchy, not the directory structure, which is why this is necessary; imports like from .. import example do not work by figuring out the current file location and then going up a level in the directory hierarchy. Instead, they check the __package__ to figure out what the containing package is, then check the file/folder location for that, and work from there.
If the "driver" script is within the package, run it as a module, using the -m switch for Python. For example, from the root folder, if module_a/aa.py is the driver, use python -m module_a.aa. This instructs Python that module_a is the containing package for aa.py, and ensures it gets loaded even though no import in the code has loaded it.
Contrary to what many people will wrongly tell you, it is almost never required to manipulate sys.path; there are popular Python projects on GitHub, running hundreds of thousands of lines of code, which either do not use it at all or use it only once in an ancillary role (perhaps because of a special requirement for a documentation tool). Just don't do it.
Also contrary to what many people will wrongly tell you, __init__.py files are not required to create packages in Python. They are simply a place where additional code can be placed for package initialization - for example, to create aliases for sub-package contents, or to limit what will be imported with a *-import (by setting __all__).
import .bb
This is just invalid. Relative imports only use the from syntax. See above for the correct syntax.
Suppose the same file structure as stated in OP, and:
main.py:
import module_a.aa
module_a.aa.thisFile()
module_a.aa.module_a.bb.thisFile()
aa.py:
import module_a.bb
def thisFile():
print("aa")
bb.py:
def thisFile():
print("bb")
Then, this will print
aa
bb
like you would expect. The main difference here, is that bb.py is imported in aa.py via module_a.bb. Running main.py gives no problem, however, running aa.py does not work in this way. That is why you might want to add folders to your path, such that you can call a function from a different file without this trouble. This is done via:
import os, inspect, sys
current_folder = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parent_folder = os.path.dirname(current_folder)
sys.path.insert(0,parent_folder)
Then you can import your files such as import file. If you consider this option, I would suggest to do some reading about how this works. Tip: make sure you avoid cyclic import problems.

ImportError: attempted relative import with no known parent package STILL NO SOLUTION

I have looked at I think 5 different answers to this problem, yet none of them have worked for me yet. For reference, I've looked through all of these posts:
Relative imports for the billionth time
Attempted relative import with no known parent package
"Attempted relative import with no known parent package"
From what I've gathered, there are two solutions to this problem:
Move the .py file you're trying to import functions from into the same directory as the script you're trying to run (this works, but it is not a good solution, I should be able to import from a parent directory without this error)
Create a __init__.py file in the directory of the .py file you're trying to import from, and use import package_name to it. (I have tried this, but same issue)
Here is my project's structure:
I'm trying to run the test.py script, which (attempts) to import the function add_technical_indicators from the add_technical_indicators.py file. My import statement looks like this:
from ..utils.add_technical_indicators import add_technical_indicators
Looking at the folder structure again, I have to go UP one directory, then into the utils folder to bring in the add_technical_indicators .py file, and finally the function add_technical_indicators.
Here's what I have tried so far:
from ..utils.add_technical_indicators import add_technical_indicators
from .utils.add_technical_indicators import add_technical_indicators
from utils.add_technical_indicators import add_technical_indicators (this doesn't work of course because add_technical_indicators is not in the same folder as the script being run)
Created an __init__.py file in the utils folder that reads import add_technical_indicators
Created an __init__.py file in the misc folder that reads import test
None of it works. I need a concise and actionable answer as to why this is still not working. I'm running Python 3.7.9, Windows 10, and VS code in case that matters.
I have looked through previous, repeat answers but none of them have worked for me, so although this IS a duplicate question, please do not close it until I have a solution because linking to the already "answered" questions didn't help me.
short solution
In test.py import as from utils.add_technical_indicators import add_technical_indicators
and run as python -m misc.test (not test.py) in parent directory(in STOCK_PEAKS_ADN_THROUGHS_2)
explained
python cannot import files from upper directory of your working directory unless you add them to PATH, so from ..utils.add_technical_indicators import add_technical_indicators won't work.
python finds files starting from your working directory, so from utils.add_technical_indicators import add_technical_indicators in test.py can find utils/add_technical_indicators.py if you run script at parent directory.
python -m misc.test will run misc/test.py in parent directory. Note that python misc/test.py will run script in misc directory and will give you same error.
You did the right thing here: from ..utils.add_technical_indicators import add_technical_indicators
The main issue must be in the imports of utils/add_technical_indicators.py file
Did you try importing stuffs inside add_technical_indicators.py relative to itself (if so, those imports only work when add_technical_indicators.py is run instead of test.py)
In contrast to what minolee has said Python actually can import files from upper directories. Python has a built-in SourceFileLoader that can load Python code from any file in the file system, also from any upper directory of your working directory.
It requires some boilerplate code, so I have decided to wrap this approach into an experimental import library: ultraimport
ultraimport can do file system based imports. In your test.py you could then write:
import ultraimport
add_technical_indicators = ultraimport('__dir__/../utils/add_technical_indicators.py')
This will always work, no matter what is your current working directory and no matter what is your current sys.path. You don't need to create __init__.py files and it also works if you run the code as a script or as a module.
One caveat when importing files like this is if the imported code contains further relative imports. ultraimport has a built-in preprocessor to automatically rewrite subsequent relative imports so they continue to work.

Why is the relative import not working in my project?

I am working on a python project which consist of several packages and modules. Hence I need to import modules from different packages. However, when importing these modules I am getting import errors. The folder structure is as follows:
Image of folder structure
Within the module Stage0.py I use the relative import: "from ..data.Datapipe import DataFactory" to import the class DataFactory. However when I execute the script I get an error message: "ModuleNotFoundError: No module named 'MT'"
I would appreciate any feedback as I'm becoming desperate
I'm not 100% sure I've understood this correctly, but by the looks of it when you run the Stage0.py it will set the root python path to the app directory, the problem is that python's use of relative imports only allows to find files within that root directory, this site explains it a bit better to be honest
See here
Note that for relative imports, the dots . can go up only up to (but not including) the directory containing the script run from the command line
Anyway, it to fix it you could create a __main__.py file within the mt folder which calls the Stage0.py script, this will set that mt folder as the root of the project giving access to the other directories.
As a simple solution, I recommend that you put Stage0.py in the same location as the requirements.txt and execute it from there
as follows:
-data/
-__init__.py
-Datapipe.py
-graph/
-__init__.py
-s0.py
-stage0.py
stage0.py
from data.Datapipe import DataFactory

Multiple relative imports in python 2.7 packages

I understand there are many SO questions on relative imports. I will document the extent I have tried the solutions therein, but I am still unable to solve my problem.
I have the following directory structure. It's not mine by design but I'm game for modifying things as necessary (forked repo).
exp
main_Exp.py
kaffe
__init__.py
tensorflow
__init__.py
network_shape.py
ResNet
__init__.py (*)
ThreeDMM_shape.py
To run the model in this repo, I am to use
python main_Exp.py input_file.csv
Inside main_Exp.py:
sys.path.append('./kaffe')
sys.path.append('./ResNet')
from ThreeDMM_shape import ResNet_101 as resnet101_shape
from ThreeDMM_expr import ResNet_101 as resnet101_expr
Inside ResNet/ThreeDMM_shape.py:
sys.path.append('/home/usc/Desktop/Research/FG18/ExpNet_Code_Release/kaffe/tensorflow')
from network_shape import Network_Shape
Ok, so obviously I need to change this hard-coded absolute path. I'd like to do it the right way and not use my own specific path that I happened to install these files to.
So I try
from ..kaffee.tensorflow import Network_Shape
>>> ValueError: Attempted relative import in non-package
(1) I added __init__.py file in the ResNet folder (shown with the (*))
(2) I tried running the file as a module: python -m main_Exp input_file.csv
(3) I also tried adding __init__.py to the top level folder (exp), though I believe doing so is nonsense.
(4) Given that the first import was happening using the kaffe path that was appended to sys.path, I tried changing import to from .tensorflow.network_shape import Network_Shape
Same error after all steps.
So I'm not understanding the rules around relative imports and how to reference files in a sane way. I would really appreciate a pointer that helps me understand how to do this, and how to think about such imports in general!
exp is indeed not a package and won't be made to a package even if you add an init file to it, cause that won't magically add it to the paths python looks for packages. If you do add the __init__.py you can then run as python -m exp.main_Exp input_file.csv (from ../exp). This would make python recognize exp as a package and kaffe/ResNet as subpackages. You would need to change imports to from ResNet.ThreeDMM_shape import ResNet_101 as resnet101_shape etc.
Edit in response to comment:
Running from the parent dir using the m switch is the recommended way of running the script see for instance https://stackoverflow.com/a/23540051/281545 (that's for python 3 however it should still apply). If you want to avoid it (it would break hardcoded relative paths for one) you should add exp to sys path (once maybe is enough) then change the imports to absolute ones as in:
# main_Exp.py
sys.path.append(os.path.abspath(os.path.dirname(__file__))) # the exp folder
from ResNet.ThreeDMM_shape import ResNet_101 as resnet101_shape
from ResNet.ThreeDMM_expr import ResNet_101 as resnet101_expr
# ResNet/ThreeDMM_shape.py
from kaffee.tensorflow import Network_Shape

How do I make relative importing work in Python using Eclipse with PyDev?

So I am working on a Python project that was here before me in an SVN repo. When I first pulled it, the structure was a bit odd due to the fact that it was similar to:
Proj\
src\
tags\
trunk\
And then everything is inside src\ are the python module files except src\ turns out to just be a logical folder with no overall package inside. There isn't a __init__.py in the project anywhere. So I want to restructure it at least so I can use relative imports through my project. I also want to set it up so it looks more like this.
Proj\
src\
model\
controller\
view\
test\
tags\
trunk\
However, I tried setting this up and no matter what I seem to do, it cannot resolve the relative import the moment I have to traverse packages. I placed a __init__.py file in each level package including one inside the src\ folder with all of them having __all__ defined. However, when I try to make a unit test in my test\ package and do an import saying:
from ..model.foo import Foo
to attempt to import the Foo class from module foo.py located inside of the model package, it doesn't resolve. Just in case it was a problem specifically with unit tests, I also tried this with a module in the controller package that was dependent on a class in the model package and vice versa. None of them worked. How do I resolve this?
Have you added the root folder to your system path?
import sys
sys.path.append(<place the Proj dir here>)
then you could import as follows:
from src.model.somefile import Something
If you don't know the absolute path for Proj, you can always use combinations such as
os.path.dirname(os.getcwd())

Categories

Resources