Pycharm cannot import module from Parent folder name - python

I have project defined in below way:
project/
__init__.py
dog.py
cat.py
In my dog.py, I'm calling:
import project.cat
which gives me this error:
ModuleNotFoundError: No module named 'project'
However, I have setup PYTHONPATH to the parent of project directory, which if I run dog.py outside of Pycharm (for example on the command line) it works well without exceptions.
Now even if I added project folder as Source Root, Pycharm still labels my import statement as wrong (red color) and also doesn't allow me to run it inside Pycharm for dog.py program. This is so confusing. Can anyone help?
*PS: I don't want to use relative imports in dog.py like 'from .cat import *' because I have if name == main statement in dog.py, which python doesn't allow me to run the relative imports inside dog.py.
===============
Adding more information:
I noticed if I made the src folder under project to make the structure like:
project/
__init__.py
src/
__init__.py
dog.py
cat.py
then I can call this in dog.py:
import src.cat
But this way, I am still troubling myself because when I run program in Pycharm, I have to use this way:
import src.cat
when I run program in ipython notebook, I have to import like:
import project.src.cat
This cause me constantly switch my code when I have to run in different places.
=====================
If I simply do this in dog.py
import cat
It will work in Pycharm. But when I call in command line, it's going wrong there now:
In [10]: import project.dog
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
<ipython-input-10-be5ebc05b4b0> in <module>
----> 1 import project.dog
~/PycharmProjects/project/dog.py in <module>
2 import pandas as pd
3 import numpy as np
----> 4 import cat
5 from datetime import datetime
6
ModuleNotFoundError: No module named 'cat'

Issue resolved by making my parent folder of my project as the root folder and make root as Source Root.
parent-folder\
project\
__init__.py
dog.py
cat.py
Now it works well on both command line and Pycharm by simply adding one line in .bashrc:
export PYTHONPATH=$PYTHONPATH:~/project

Related

Trouble importing a module that itself imports another module in Python

Python version: 3.8.5
File structure
MainDir
|
| Utils --|
| | module1.py
| | module2.py
|
| Tests --|
| test.py
module1.py imports module2.py
test.py imports module1.py
When I run python Tests/test.py I get the following error:
Traceback (most recent call last):
File "test.py", line 5, in <module>
import Utils.module1
File "<abspath>/MainDir/Utils/module1.py", line 16, in <module>
import module2
ModuleNotFoundError: No module named 'module2'
I've tried the following:
1.) Python - Module Not Found
2.)
$export PYTHONPATH="$PWD"
3.) I've tried putting the test.py file at the same level as the Utils directory.
4.)
import sys
sys.path.append("../MainDir")
And several variations thereof.
They all failed.
The only thing that worked was just putting test.py in the Utils directory and running it from there. But I know there has to be a way to get it to work when it's in its own directory.
What am I missing?
UPDATE
The selected answer worked when trying to run test.py, but it broke when trying to run module1.py.
After some more research, running it with the -m flag and package syntax worked; in my case:
python -m Utils.module1
Hope this helps anyone else who runs into this problem.
You may want to use relative imports.
So perhaps something like :
# in module1.py
import .module2
Relative imports mean that you are not trying to import from the __main__ file but from the current file (in your case module1.py).
Edit :
Just realised I am stupid. This works for modules, not individual files.
Please try again with from . import module2
if you structure your project like here you can use this. Also it is recommended to use relative import inside your packages
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

Why do I have to use a relative import in a package's __init__.py?

Setup
test/
main.py
pkg/
a.py
__init__.py
main.py contains:
import pkg
pkg.a
__init__.py contains:
from . import a
main.py can be run without errors.
Question
Changing the content of __init__.py to
import a
gives the following error when running main.py:
Traceback (most recent call last):
File "C:/Users/me/PycharmProjects/test/main.py", line 1, in <module>
import pkg
File "C:\Users\me\PycharmProjects\test\pkg\__init__.py", line 1, in <module>
import a
ModuleNotFoundError: No module named 'a'
Interestingly, __init__.py can be executed directly with python __init__.py without errors.
What's going on?
When you run a python script, it's parent folder is added to sys.path
run main.py: sys.path[0] = '../test'
run init.py: sys.path[0] = '../test/pkg'
Your case: You try to "absolute-like" import a in __init__.py but the parent folder of a.py - which is '../test/pkg' - is not in the sys.path when you run main.py. This is why you get an error. However, your absolute import is incomplete as it should always start at the top level folder, e.g.
from test.pkg import a
Final answer to your question: You don't have to use relative imports!
See: PEP-8: Absolute imports are recommended, as they are usually more readable and tend to be better behaved (or at least give better error messages) if the import system is incorrectly configured (such as when a directory inside a package ends up on sys.path).
And keep in mind that relative imports don't work in a top-level-script when __name__ = "__main__", but from imported modules only.
You can learn more about absolute and relative imports here:
Absolute vs. explicit relative import of Python module
https://realpython.com/absolute-vs-relative-python-imports/
I suppose you are using Pycharm? Then that's one of the confusion cause.
For example, let's say your directory looks like this
project1
p1.py
test/
__init__.py
main.py
pkg/
a.py
__init__.py
If you run (F10) the main.py your default working directory will be project1/test, which does not contain the a.py so import a will not find anything.
But if you run (F10) the pkg/__init__.py your working directory will be project1/test/pkg which has the a.py, and it works like what you tested.
So in these situation, if you use from . import a it will look for the directory that file is, project1/test/pkg in this case, which will always work regardless your working directory.

Import error with unit tests: "No module named ..." from local libary

I'm new to Python (JS developer) and am trying to run a testing suite. My project folder structure is as such:
project/
__init__.py
libs/
__init__.py
s3panda.py
tests
__init__.py
tests_s3panda.py
In terminal, I'm running python tests_s3panda.py.
I don't understand how it's unable to find a local module:
Traceback (most recent call last): File "tests_s3panda.py", line 7,
in
from libs.s3panda import S3Panda ImportError: No module named libs.s3panda
tests_s3panda.py snippet:
from __future__ import absolute_import
import unittest
import pandas as pd
from libs.s3panda import S3Panda
class TestS3Panda(unittest.TestCase):
...
Doing from ..libs.s3panda import S3Panda for relative path, I get:
ValueError: Attempted relative import in non-package
I believe the fact that there is no init.py in the top-level folder means that Python is not aware that libs and tests are both part of the same module called project.
Try adding an __init__.py to your project folder, then write the import statement as from project.libs.s3panda import S3Panda. In general, you want to specify absolute imports rather than relative imports (When to use absolute imports).

how to import file.py from main folder if you are working in a subfolder python3

I have a structure such has:
/mainfolder
file.py
//subfolder
test.py
I am trying to import file.py in test.py. for some reason I just can't.
I tried
from .file import *
returning :
Traceback (most recent call last):
ModuleNotFoundError: No module named '__main__.file'; '__main__' is not a package
also tried to add path to sys.path:
import sys
import os
sys.path.extend([os.getcwd()])
doesnt work either
Looks like you're running test.py with python test.py and as such the test module is being treated as a top level module.
You should first make your folders Python packages if they are not by adding __init__.py files:
/mainfolder
__init__.py
file.py
/subfolder
__init__.py
test.py
Then you can append the outer mainfolder to sys.path:
import sys
import os
sys.path.append(os.path.join(os.getcwd(), '..'))
After which from file import someobject without relative import works. Be wary of wild card imports.
See ModuleNotFoundError: What does it mean __main__ is not a package? and How to do relative imports in Python? for more on why your current approach does not work.
What IDE are you using? I am using Pycharm Community IDE with Python 3 and it works with from file import * or from file import some_function (I wanted to comment but I can't since I don't have 50 reputation yet)

Relative imports - ModuleNotFoundError: No module named x

This is the first time I've really sat down and tried python 3, and seem to be failing miserably. I have the following two files:
test.py
config.py
config.py has a few functions defined in it as well as a few variables. I've stripped it down to the following:
config.py
debug = True
test.py
import config
print (config.debug)
I also have an __init__.py
However, I'm getting the following error:
ModuleNotFoundError: No module named 'config'
I'm aware that the py3 convention is to use absolute imports:
from . import config
However, this leads to the following error:
ImportError: cannot import name 'config'
So I'm at a loss as to what to do here... Any help is greatly appreciated. :)
TL;DR: You can't do relative imports from the file you execute since __main__ module is not a part of a package.
Absolute imports - import something available on sys.path
Relative imports - import something relative to the current module, must be a part of a package
If you're running both variants in exactly the same way, one of them should work. Here is an example that should help you understand what's going on. Let's add another main.py file with the overall directory structure like this:
.
./main.py
./ryan/__init__.py
./ryan/config.py
./ryan/test.py
And let's update test.py to see what's going on:
# config.py
debug = True
# test.py
print(__name__)
try:
# Trying to find module in the parent package
from . import config
print(config.debug)
del config
except ImportError:
print('Relative import failed')
try:
# Trying to find module on sys.path
import config
print(config.debug)
except ModuleNotFoundError:
print('Absolute import failed')
# main.py
import ryan.test
Let's run test.py first:
$ python ryan/test.py
__main__
Relative import failed
True
Here "test" is the __main__ module and doesn't know anything about belonging to a package. However import config should work, since the ryan folder will be added to sys.path.
Let's run main.py instead:
$ python main.py
ryan.test
True
Absolute import failed
And here test is inside of the "ryan" package and can perform relative imports. import config fails since implicit relative imports are not allowed in Python 3.
Hope this helped.
P.S.: If you're sticking with Python 3 there is no more need for __init__.py files.
You have to append your project's path to PYTHONPATH and make sure to use absolute imports.
For UNIX (Linux, OSX, ...)
export PYTHONPATH="${PYTHONPATH}:/path/to/your/project/"
For Windows
set PYTHONPATH=%PYTHONPATH%;C:\path\to\your\project\
Absolute imports
Assuming that we have the following project structure,
└── myproject
├── mypackage
│ ├── __init__.py
│ ├── a.py
└── anotherpackage
├── __init__.py
├── b.py
├── c.py
└── mysubpackage
├── __init__.py
└── d.py
just make sure to reference each import starting from the project's root directory. For instance,
# in module a.py
import anotherpackage.mysubpackage.d
# in module b
import anotherpackage.c
import mypackage.a
For a more comprehensive explanation, refer to the article How to fix ModuleNotFoundError and ImportError
I figured it out. Very frustrating, especially coming from python2.
You have to add a . to the module, regardless of whether or not it is relative or absolute.
I created the directory setup as follows.
/main.py
--/lib
--/__init__.py
--/mody.py
--/modx.py
modx.py
def does_something():
return "I gave you this string."
mody.py
from modx import does_something
def loaded():
string = does_something()
print(string)
main.py
from lib import mody
mody.loaded()
when I execute main, this is what happens
$ python main.py
Traceback (most recent call last):
File "main.py", line 2, in <module>
from lib import mody
File "/mnt/c/Users/Austin/Dropbox/Source/Python/virtualenviron/mock/package/lib/mody.py", line 1, in <module>
from modx import does_something
ImportError: No module named 'modx'
I ran 2to3, and the core output was this
RefactoringTool: Refactored lib/mody.py
--- lib/mody.py (original)
+++ lib/mody.py (refactored)
## -1,4 +1,4 ##
-from modx import does_something
+from .modx import does_something
def loaded():
string = does_something()
RefactoringTool: Files that need to be modified:
RefactoringTool: lib/modx.py
RefactoringTool: lib/mody.py
I had to modify mody.py's import statement to fix it
try:
from modx import does_something
except ImportError:
from .modx import does_something
def loaded():
string = does_something()
print(string)
Then I ran main.py again and got the expected output
$ python main.py
I gave you this string.
Lastly, just to clean it up and make it portable between 2 and 3.
from __future__ import absolute_import
from .modx import does_something
Setting PYTHONPATH can also help with this problem.
Here is how it can be done on Windows
set PYTHONPATH=.
You can simply add following file to your tests directory, and then python will run it before the tests
__init__.py file
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
Set PYTHONPATH environment variable in root project directory.
Considering UNIX-like:
export PYTHONPATH=.
Tried your example
from . import config
got the following SystemError:
/usr/bin/python3.4 test.py
Traceback (most recent call last):
File "test.py", line 1, in
from . import config
SystemError: Parent module '' not loaded, cannot perform relative import
This will work for me:
import config
print('debug=%s'%config.debug)
>>>debug=True
Tested with Python:3.4.2 - PyCharm 2016.3.2
Beside this PyCharm offers you to Import this name.
You hav to click on config and a help icon appears.
If you are using python 3+ then try adding below lines
import os, sys
dir_path = os.path.dirname(os.path.realpath(__file__))
parent_dir_path = os.path.abspath(os.path.join(dir_path, os.pardir))
sys.path.insert(0, parent_dir_path)
Declare correct sys.path list before you call module:
import os, sys
#'/home/user/example/parent/child'
current_path = os.path.abspath('.')
#'/home/user/example/parent'
parent_path = os.path.dirname(current_path)
sys.path.append(parent_path)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'child.settings')
I am working in a Linux machine. I had the same issue when I run python my_module/__main__.py.
The error is fixed, if you run the command export PYTHONPATH=. before your run your script.
export PYTHONPATH=.
python my_module/__main__.py
Try
from . import config
What that does is import from the same folder level. If you directly try to import it assumes it's a subordinate
This example works on Python 3.6.
I suggest going to Run -> Edit Configurations in PyCharm, deleting any entries there, and trying to run the code through PyCharm again.
If that doesn't work, check your project interpreter (Settings -> Project Interpreter) and run configuration defaults (Run -> Edit Configurations...).
As was stated in the comments to the original post, this seemed to be an issue with the python interpreter I was using for whatever reason, and not something wrong with the python scripts. I switched over from the WinPython bundle to the official python 3.6 from python.org and it worked just fine. thanks for the help everyone :)
You may use these statements to set the working directory, which worked for me with python3
import os
import sys
sys.path.insert(1, os.getcwd())
For me, simply adding the current directory worked.
Using the following structure:
└── myproject
├── a.py
└── b.py
a.py:
from b import some_object
# returns ModuleNotFound error
from myproject.b import some_object
# works
In my experience, PYTHONPATH environment variable does not work everytime.
In my case, my pytest only worked when I added the absolute path:
sys.path.insert(
0, "/Users/bob/project/repo/lambda"
)
I see many answers importing sys and os. Here's a not mentioned yet shorter one that GitHub Copilot gave me:
import sys
sys.path.append(__file__.rsplit("/", 1)[0])
Adding this to the top of my python script solved the problem as well.
To have Bash automatically recognise the project dir you're in:
sudo nano ~/.bashrc
OR
sudo nano ~/.bash_profile
At the bottom of the bash file:
function set_pythonpath {
export PYTHONPATH="$(pwd):$PYTHONPATH"
}
PROMPT_COMMAND=set_pythonpath
To save and exit:
Ctrl + X
Y
Test your changes by:
cat ~/.bashrc

Categories

Resources