Recently started a new Python project.
I am resolving a import module error where I am trying to import modules from the same directory.
I was following the solutions here but my situation is slightly different and as a result my script cannot run.
My project directory is as follows:
dir-parent
->dir-child-1
->dir-child-2
->dir-child-3
->__init__.py (to let python now that I can import modules from here)
->module1
->module2
->module3
->module4
->main.py
In my main.py script I am importing these module in the same directory as follows:
from dir-parent.module1 import class1
When I run the script using this method it throws a import error saying that there is no module named dir-parent.module1 (which is wrong because it exists).
I then change the import statement to:
from module1 import class1
and this seemed to resolve the error, however, the code I am working on has been in use for over 2.5 years and it has always imported modules via this method, plus in the code it refers to the dir-parent directory.
I was just wondering if there is something I am missing or need to do to resolve this without changing these import statements and legacy code?
EDIT: I am using PyCharm and am running off PyCharm
If you want to keep the code unchanged, I think you will have to add dir-parent to PYTHONPATH. For exemple, add the following on top of your main.py :
import os, sys
parent_dir = os.path.abspath(os.path.dirname(__file__)) # get parent_dir path
sys.path.append(parent_dir)
Python's import and pathing are a pain. This is what I do for modules that have a main. I don't know if pythonic at all.
# Add the parent directory to the path
CURRENTDIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
if CURRENTDIR not in sys.path:
sys.path.append(CURRENTDIR)
Related
Not a python developer and I am clearly missing something fundamental here. Using Python 3.10.7 and i am getting an error:
from ..class_one import ClassOne
ImportError: attempted relative import beyond top-level package
when attempting to execute python run_me.py script in the example below
I have the following structure with following import statements
\Project
\data_processor
data_process.py
from ..class_one import ClassOne <--getting an error here
run_me.py
from data_processor.data_process import DataProcess
class_one.py
interesting that when i type a line from ..class_one import ClassOne in data_process.py my IDE thinks its completely legit and intellisence works, suggesting that i import ClassOne.
Most of the solutions imply Python earlier than v3.3 (changed the way packages are handled), which isn't the case here.
Python does not allow relative imports beyond the top-level package. This is why you are seeing the ImportError: attempted relative import beyond top-level package error...
Try to use absolute import, like this:
from Project.class_one import ClassOne
You can also move the class_one module to a package within the current project, you can create a new package and move the class_one module to it. Then, you can use a relative import to import the ClassOne module:
\Project
\data_processor
data_process.py
from my_package.class_one import ClassOne
run_me.py
from data_processor.data_process import DataProcess
\my_package
class_one.py
Finally, it's not recommended (complexity, cause confusion and difficulty to read the code) but I think you can try to use a 'sys.path' to add the parent directory to the Python path. I think it will allow you to use a relative import:
import sys
sys.path.insert(0, '..')
from class_one import ClassOne
Why you get that error?
Remember relative imports are resolved using __package__ variable(I'm talking about ..class_one). Add a simple print statement in your data_process.py to see the value of this variable:
print(__package__)
You're in Project folder and you run python run_me.py, so this variable must be: 'data_processor'. So you can't go beyond "one" level up. (It follows the dots as we see next).
When you can go one level up?
In run_me.py change your import statement from:
from data_processor.data_process import DataProcess
to
from Project.data_processor.data_process import DataProcess
Before running your script, we need to tell Python where to find Project folder. It doesn't know right now! We are in Project directory and there is no Project directory in where we are. So just add it to the sys.path in run_me.py:
import sys
sys.path.insert(0, PATH TO PARENT OF Project DIRECTORY)
Now run your command -> python run_me.py. Every thing works fine.
Did you notice the value of __package__? It's now 'Project.data_processor'. We went one level down, so we can go one level up .( As I said, it follows the dots.)
That was the reason. But what you can do now?
I think the most simple solution is to just stick with absolute imports. If you know in which directory you are and check the records in sys.path(Add to the paths if necessary), you won't get into problems.
You can manually hack __package__ which I do not recommend. To do so, add:
__package__ = "Project.data_processor"
at the top in your data_process.py file. Then add this to the run_me.py
import sys
sys.path.insert(0, PATH TO PARENT OF Project DIRECTORY)
This way you don't need to change your original import statement. That from data_processor.data_process import DataProcess just works.
For this option, you don't need to hack __package__ nor adding any path to the sys.path. Just change your import statement from:
from data_processor.data_process import DataProcess
to
from Project.data_processor.data_process import DataProcess
But for executing your command, you should go to the parent directory and run your script like:
python -m Project.run_me
I have a repository with the following directory structure:
repo_folder\
----src\
----__init__.py
----src1.py
----src2.py
----src3.py
----testing\
----specific_test.py
----requirements.txt
specific_test.py has on it's first lines:
import os
import sys
sys.path.insert(0, os.path.dirname(os.getcwd()))
import src.src1
import src.src2
import src.src3
# lots of asserts
When I run specific_test.py from within testing folder or from repo_folder folder it works, but only on my local machine.
The problem is that when I try to run this from my codeship account, it gives me an Import Error.
The error looks like this:
ImportError while importing test module
ERROR collecting testing/specific_test.py
No module named src.src1
Make sure your test modules/packages have valid Python names.
Do you know what would the problem be?
Do you have suggestions for better alternatives?
This seems to be a pathing issue. What seems to be happening on your local machine is you insert into your path your CWD, which is most likely returning as repo_folder\. from there, you can import your src files via src.src1 because src is containe. On your codeship account, the cwd (current working directory) is not correct, thus is cannot find the src. part of src.src1. Check what the line sys.path.insert(0, os.path.dirname(os.getcwd())) returns, more importantly os.path.dirname(os.getcwd()) and verify that it is leading to repo_folder\
I am trying to import from relative path in my python program.
the class i would like to import is in
home/foo/bar/model.py
However, my current python script is in
home/best/user/test.py
i have tried to use
from ../../foo/bar import class
But it throws up a syntax error
When importing modules, python looks in the current working directory and in the paths in sys.path. You can add the directory of the script you would like to import to sys.path:
import sys
sys.path.append('home/foo/bar')
import model # imports home/foo/bar/model.py
You can't do that. You can't import from an explicitly specified path (without awful trickery). All Python imports are based on the systemwide import paths (in sys,path). You can't import anything that isn't reachable from sys,path (i.e., it's either on sys.path itself or it's inside a package that's on sys.path). The documenation has the details. If you want to be able to import from that file, you need to somehow add its directory (or the directory of its topmost containing package) to the path.
I know that there are other questions like this, none of them worked for me. I've been creating a simple python app and decided to organize it (instead of having the app and test.py in the same directory. I tried to set it up like this:
C:\Dev\project\module\test
- project
- __init__.py
- module
- __init__.py
- module.py
- test
- __init__.py
- test_module.py
Now I've tried everything i can think of to import module.py to test_module.py
import module
import project.module
import module.module
import project.module.module
from project import module
from project.module import module
None of these work. It fails with:
ImportError: No module named 'whatever i put in above'
It's driving me nuts, shouldn't this be simple? What am i missing? I added a test that shows my PYTHONPATH using import sys print sys.path. The first item in the list is C:\Dev\project\module\test
EDIT:
I tried adding init to the top level as well and that didn't help. I know I could force edit the sys.path as many of the answers suggest.
What is the right way to do it? As in, what is the standard or sensible way to build a project to avoid this issue?
If you only need to reach the parent directory, you can use:
import sys
sys.path.insert(0, '..')
import module
This should work on both Windows and Linux.
Messing with the python path programmatically isn't usually considered great style, but it has its uses. I find it's a nice, quick way to do what you're doing (writing tests below/inside a module). Of course the easy way is to simply put your tests outside of the module. Barring that, however, just do this:
import sys
sys.path.insert(0, r'C:\Dev\project') # Add the directory containing your module.
import module
This way, you ensure that the first directory on the path is the directory that contains the module you want to import. You could also avoid hard-coding the module path (e.g. if you want to be able to move your project someplace else) by using a path that's relative to your testing script:
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(__file__, '..', '..', '..')))
import module
This will work no matter where you run the script from, and cross-platform.
At I beginning of most of my python scripts, I always put the following:
# Path hack.
# http://stackoverflow.com/questions/6323860/sibling-package-imports
import os, sys
sys.path.insert(0, os.path.abspath('.'))
I think packaging is a bit screwed in python, yet this is a standard way for me to make it work :)
When executing my script, I always use the root directory as the working dir:
cd C:\Dev\project
python3 .\module\test\test_module.py
When importing submodules, I also always start the path from the root:
import module.module
or
from module.module import some_identifier
I have a python script that is trying to import another script somewhere in the file-system (path is only known at runtime).
To my understanding I need to use the imp module and this might work, but when loading the module I get an error that modules used by the imported module are not found.
Heres the code:
importer.py:
import imp
imp.load_compiled("my_module","full_path_to_my_module\\my_module.pyc")
my_module.py:
import sys
import another_module
When I run importer.py I get htis error message:
ImportError: No module named another_module
Whats going wrong here ?
I suspect that when 'importer.py' is loading 'my_module.pyc' hes also trying to load 'another_module' (thats good) but is looking in the wrong place (eg not 'full_path_to_my_module')
EDIT:
I tried adding 'full_path_to_my_module' to the system path:
import imp
import sys
sys.path.append(full_path_to_my_module)
imp.load_compiled("my_module",full_path_to_my_module+my_module)
But I still get the same error
Maybe I do something thats not necessary - Here's my goal:
I want to be able to use all functionality of 'my_module.pyc' inside 'importer.py'. But the location of 'my_module.pyc' is given as a parameter to 'importer.py'.
imp.load_compiled returns the compiled module object, it is different to the import statement which also binds the module to a name
import imp
my_module = imp.load_compiled("my_module", "full_path_to_my_module/my_module.pyc")
Then you can do something like:
my_module.yayfunctions('a')
Complete example session:
$ cat /tmp/my_module.py
def yayfunctions(a):
print a
$ python -m compileall /tmp/my_module.py
$ ls /tmp/my_module.py*
my_module.py my_module.pyc
$ python
>>> import imp
>>> my_module = imp.load_compiled("my_module", "/tmp/my_module.pyc")
>>> my_module.yayfunctions('a')
a
Edit regarding comment (ImportError: No module named another_module), I assume the error is caused by the code in my_module.pyc, and the another_module.py lives in the same directory
In that case, as others have suggested, it's simpler to just add the directory containing my_module to sys.path and use the regular import mechanism, specifically __import__
Here's a function which should do what you want:
import os
def load_path(filepath):
"""Given a path like /path/to/my_module.pyc (or .py) imports the
module and returns it
"""
path, fname = os.path.split(filepath)
modulename, _ = os.path.splitext(fname)
if path not in sys.path:
sys.path.insert(0, path)
return __import__(modulename)
if __name__ == '__main__':
# Example usage
my_module = load_path('/tmp/my_module.py')
my_module.yayfunctions('test')
It is since at the scope of import another_module your "full_path_to_my_module" isn't known.
Have you tried to add the path to known paths instead, i.e.:
import sys
sys.path.append("full_path_to_my_module")
You don't actually need to use the imp module to load pyc modules.
An easy way to try it out is to make two python modules, one importing from the other and run it. Delete then the imported .py file so you only get the .pyc file left: when running the script the import will work just fine.
But, for importing py files from random directories, you may want to add that directory to the python path first before importing it.
For instance:
import sys
sys.path.insert(0, "/home/user/myrandomdirectory")
Loading pyc files works the exact same way as loading a py file except it doesn't do a compile step. Thus just using import mymodule will work as long as the version number of the pyc is the same as the python you're running. Otherwise you'll get a magic number error.
If you module isn't in your path you'll need to add that to sys -- or if its a subdirectory, add a __init__.py file to that directory..