Have a question about python module import - python

Here is my project directory in Intellij
parent/
A/
test.py
In test.py, I have to import a module from parent level of parent folder.
import module_needed
but module_needed is in this structure:
parent_a/
parent_b/
py/
module_needed
application/
parent/
A/
test.py
I tried to add moduled_needed's path to sys.path in test.py. But still cannot find module.
Am I doing wrong? I am using Intellij, is this related to Intellij?

Python import system is quite straightforward. It looks for the packages in folders from sys.path. You have to add folder that contains module_needed in this case py (full path), not path to module_needed itself. If it's not there you can add the folder either from the code, directly appending to sys.path or with PYTHONPATH enviroment variable.
Also try printing sys.path, because Intellij might add project root to python path. Then the import statement would be:
import parent_a.parent_b.py.module_needed
without any modifications.
It might be useful to add the project root, then you won't have to add every single folder separately.

Related

Absolute import in conda env

I met with a problem with absolute import when using conda env. Here is the structure of my project.
project/
package_1/
__init__.py
file_1.py
subpackage_1/
run.py
In package_1.subpackage_1.run.py there is an absolute import import package_1.file_1. However, when I ran python package_1/subpackage_1/run.py in package folder, I got an error:
ModuleNotFoundError: No module named 'package_1'. I tried to print sys.path. project.package_1.subpackage_1 is in sys.path, but the folder from where I ran the command, project is not. I tried to add project in PATH or PYTHONPATH, but it doesn't work in conda env. Does anyone know how to fix this? Thanks!!!
One of the ways to do this is to add the directory to your sys.path with this code at the top of run.py
import sys
import os
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'package_1'))
And then change the line in run.py
import package_1.file_1
to
import file_1
Now python can import file1 directly since its directory is on the path.
Summary
You can accomplish what you want with relative imports, or with absolute imports if you restructure your project. Modifying your sys.path or PYTHONPATH should not be your go-to solution. If you really want global availability, you could install your local package with conda.
Option 1: Relative Imports
If you want to be able to run a file inside a sub-module directly (i.e. python package_1/subpackage_1/run.py) then you should consider using relative imports.
Example:
project/
package_1/
__init__.py
file_1.py
subpackage_1/
__init__.py
run.py
# run.py
import ..file_1
Option 2: Absolute Imports
If you want to use absolute imports, then your entry point (the script that you run) should be in the top level (package_1) instead of inside a sub-package.
Example:
project/
package_1/
__init__.py
run.py
file_1.py
subpackage_1/
__init__.py
stuff.py
# run.py
import package_1.subpackage_1.stuff
stuff.run()
# stuff.py
import package_1.file_1
Option 3: Installing your local package with conda
Once you configure your package correctly you should be able to simply run
conda install .
Which will install your local package as if it were a published package. This is likely overkill for your needs.
Why not modify PYTHONPATH or sys.path?
If you rely on having your local package path on PYTHONPATH, you every time you move the project or copy it onto a new computer.
Appending entries to sys.path in code often accomplishes a similar effect to what you can do with relative imports, but later import statements lose semantics.

Expanding sys.path via __init__.py

There're a lot of threads on importing modules from sibling directories, and majority recommends to either simply add init.py to source tree, or modify sys.path from inside those init files.
Suppose I have following project structure:
project_root/
__init__.py
wrappers/
__init__.py
wrapper1.py
wrapper2.py
samples/
__init__.py
sample1.py
sample2.py
All init.py files contain code which inserts absolute path to project_root/ directory into the sys.path. I get "No module names x", no matter how I'm trying to import wrapperX modules into sampleX. And when I try to print sys.path from sampleX, it appears that it does not contain path to project_root.
So how do I use init.py correctly to set up project environment variables?
Do not run sampleX.py directly, execute as module instead:
# (in project root directory)
python -m samples.sample1
This way you do not need to fiddle with sys.path at all (which is generally discouraged). It also makes it much easier to use the samples/ package as a library later on.
Oh, and init.py is not run because it only gets run/imported (which is more or less the same thing) if you import the samples package, not if you run an individual file as script.

Importing from parent directory gets error

The project structure on my local machine is setup like this:
python/
__init__.py
readText.py
testing/
__init__.py
removeDuplicates.py
In removeDuplicates.py I am trying to import as follows:
from python import readText
This gives: ImportError: No module name 'python'
My init.py in both folders are blank by the way.
You need the parent directory of your python subdirectory to be present in sys.path. If you execute your script from that directory, the import should work. But the easiest way to do this is to export the environment variable PYTHONPATH.
You want to import something from the parent directory, use
from .. import readText
see relative imports:
https://docs.python.org/2.5/whatsnew/pep-328.html

Add a folder to the Python library path, once for all (Windows)

I use
sys.path.append('D:/my_library_folder/')
import mymodule
in order to import some module.
How to add permanently this folder D:/my_library_folder/ to the Python library path, so that I will be able to use only
import mymodule
in the future?
(Even after a reboot, etc.)
just put the folder in site-packages directory. ie:
C:\PythonXY\Lib\site-packages
Note: you need to add an empty file __init__.py to the folder
Files named __init__.py are used to mark directories on disk as a Python package directories.
If you have the files:
C:\PythonXY\Lib\site-packages\<my_library_folder>\__init__.py
C:\PythonXY\Lib\site-packages\<my_library_folder>\module.py
you can import the code in module.py as:
from <my_library_folder> import module
If you remove the __init__.py file, Python will no longer look for submodules inside that directory, so attempts to import the module will fail.
If you have lots of folders, then create the empty __init__.py file in each folder. for eg:
C:\PythonXY\Lib\site-packages\<my_library_folder>\
__init__.py
module.py
subpackage\
__init__.py
submodule1.py
submodule2.py
Set PYTHONPATH environment variable to D:/my_library_folder/
If D:/my_library_folder is a project you're working on and has a setup script, you could also do python setup.py develop. Not entirely related to the question, but I also recommend using virtualenv.

Import file from parent directory?

I have the following directory structure:
application
tests
main.py
main.py
application/main.py contains some functions.
tests/main.py will contain my tests for these functions but I can't import the top level main.py. I get the following error:
ImportError: Import by filename is not supported.
I am attempting to import using the following syntax:
import main
What am I doing wrong?
If you'd like your script to be more portable, consider finding the parent directory automatically:
import os, sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# import ../db.py
import db
You must add the application dir to your path:
import sys
sys.path.append("/path/to/dir")
from app import object
Or from shell:
setenv PATH $PATH:"path/to/dir"
In case you use windows:
Adding variable to path in windows.
Or from the command line:
set PATH=%PATH%;C:\path\to\dir
Please mind the diff between PYTHONPATH, PATH, sys.path.
Late to the party - most other answers here are not correct unfortunately - apart LennartRegebro's (and BrenBarn's) which is incomplete. For the benefit of future readers - the OP should, first of all, add the __init__.py files as in
root
application
__init__.py
main.py
tests
__init__.py
main.py
then:
$ cd root
$ python -m application.tests.main
or
$ cd application
$ python -m tests.main
Running a script directly from inside its package is an antipattern - the correct way is running with the -m switch from the parent directory of the root package - this way all packages are detected and relative/absolute imports work as expected.
First of all you need to make your directories into packages, by adding __init__.py files:
application
tests
__init__.py
main.py
__init__.py
main.py
Then you should make sure that the directory above application is on sys.path. There are many ways to do that, like making the application infto a package and installing it, or just executing things in the right folder etc.
Then your imports will work.
You cannot import things from parent/sibling directories as such. You can only import things from directories on the system path, or the current directory, or subdirectories within a package. Since you have no __init__.py files, your files do not form a package, and you can only import them by placing them on the system path.
To import a file in a different subdirectory of the parent directory, try something like this:
sys.path.append(os.path.abspath('../other_sub_dir'))
import filename_without_py_extension
Edit: Missing closing bracket.
in python . exists for same directory, .. for parent directory
to import a file from parent directory you can use ..
from .. import filename (without .py extension)

Categories