Python 3 Unitesting: "ModuleNotFoundError" when executing in console in unix - python-3.x

if I have written a unittest, that passes, if I run my tests.py in IDE Pycharm. If I use the console (in unix) however and start the unittest with:
python3 tests/tests.py
I get the following error:
ModuleNotFoundError: No module named 'helpermodule'
My folder structure looks like this:
folder structure
The files look like the following:
Mytest.py:
def add(x,y):
return x+y
tests.py:
from helpermodule import Mytest
import unittest
What am I missing here? I have read several posts concerning the problem, but I could not find a solution that worked.

If anyone has the same problem, the simple solution is to call the test.py with right parameters:
python3 -m unittest tests/tests.py
see also:
https://docs.python.org/3/library/unittest.html#command-line-interface

Related

How do I import from a great-great-grandparent directory in Python?

I feel a little embarrassed for not knowing this already but it's something I've always struggled with. I have a directory like this:
marketing-reports/
utils.py
Reporting/
Adhoc/
for_sales/
salesperson1/
current.py
I want to import utils.py from current.py but every suggestion I have seen so far does not work.
I have seen two main suggestions. The first involves using sys.path. I have tried that as below:
import sys
sys.path.insert(1, 'C:\\marketing-reports\\Reporting')
from Reporting import utils
... result is:
Exception has occurred: ModuleNotFoundError
No module named 'Reporting'
I have also tried another suggestion I got from this article like
import path
import sys
# directory reach
directory = path.path(__file__).abspath()
# setting path
sys.path.append(directory.parent.parent)
# importing
from Reporting import utils
... but this solution is kind of a non-starter since VSCode tells me "Import "path" could not be resolved by Pylance". I tried to fix this by running py -m pip install path, but that still didn't fix anything because I got Exception has occurred: AttributeError: module 'path' has no attribute 'path'. Then I changed path to Path which VSCode seemed to like better, but after all that I got right back to where I started with the No Module named 'Reporting' error.
What's going on here? What's the best way to import this? I feel like I'm making this a lot harder than I need to.
According to your directory tree, utils is not located inside Reporting.
First solution fixed:
import sys
sys.path.insert(1, 'C:\\marketing-reports')
import utils
Optional solution, depending on your way of running the code:
from ..... import utils
I do believe you might need to repackage utils.py somewhere else, but for simple uses these solutions will work.

How to import files from other folders

Introduction
I am using Python 3.9. I have seen quite a few answers online but I am struggling to make it work for me.
I saw that you can set default PYTHONPATH (PYTHONPATH=. python app/models/TestModel.py) but it sounds very hacky and I don't see how that would work should other devs try to use the code...
As someone who comes from a world of composer and node, I was expecting files to be pulled from a route dir but there seem to be some magic in the background that I am missing.
Issue
I have the following dir structure:
/app/models/TestModel.py
/modules/commons/models/BaseModel.py
Within BaseModel.py I print hello world:
print("Hello World")
Within TestModel.py I am trying to import my BaseModel
import modules.commons.models.BaseModel
The output if I am to call TestModel.py via CLI is below:
import modules.commons.models.BaseModel
ModuleNotFoundError: No module named 'modules'
Try python -m app.models.TestModel from the top of your package. In this case, python adds the current directory to the sys.path.
When you run python app/models/TestModel.py, python assumes app/models is the top of your package and adds ./app/models to sys.path.
Alternatively, you can put all your main entry points at the top level.

Python giving import errors

I have some code with the following structure:
+main-folder
+Foo-folder/
+foo
+bar
-file1.py
-file2.py
+bar-folder
+bars
I'm trying to do a simple import like so:
#Some module in +foo
from foo-folder.file1 import some-module
so in Pycharm it works fine but when I run it from the command line. I get moduleNotFoundError.
I'm using python 3.7 so I have no init.py files in them. Any idea about this?
Thanks,
When some module import works from PyCharm but not from the command line, it's usually because PyCharm automatically adds your project files to the Pythonpath.
In any case, also check your run configuration in PyCharm. What does it say is your working directory? Which directory are you starting it from when running from the command line?

ImportError with from . import x on simple python files

I wanted to port some code from python 2 to python 3 and it failed on an import error. So I tried to get rid of the porting itself and focus on the import by creating 2 basic python files to test with. However I can't even get those to work.
So I have 2 files
test.py:
print('Test works')
and test2.py:
from . import test
The result however is this error in Pycharm:
ImportError: cannot import name 'test' from '__main__'
(C:/Users/Username/test2.py)
In Ubuntu Shell:
Traceback (most recent call last): File "test2.py", line 1, in
from . import test1 SystemError: Parent module '' not loaded, cannot perform relative import
How can I solve it?
This "folder structure matters" is a large problem in python3. Your folder structure should NOT matter when coding, but should be referenced properly.
I've just resorted to using if/else depending on if ran locally or as part of a module:
if __name__ == "__main__": # Local Run
import test
else: # Module Run, When going production - delete if/else
from . import test
In Python3
test2.py:
import test
test.py:
if __name__ == "__main__":
print('Test works')
If you want to print "Test works" in other file
test2.py:
import test
test.main()
test.py:
def main():
print('Test works')
if __name__ == "__main__":
main()
The folder structure matters. You didn't name your module; I will call it foo. Put things in the right place:
$ mkdir foo
$ touch foo/__init__.py
$ mv /some/place/{test1,test2}.py foo/
Notice that python -c 'import test' works already, even before you wrote your test.py file. To avoid confusion I recommend naming your file test1.py.
The way you call your code matters. Verify that . dot is in sys.path:
$ export PYTHONPATH=.
$ python -m foo.test1
Alternatively this should work, if you prefer:
$ python foo/test1.py
EDIT:
I answered question #1, and OP now asks question #2, about this diagnostic:
ImportError: cannot import name 'test' from 'main' (C:/Users/Username/test2.py)
Please organize your files in the proper structure. You need to put test2.py within a foo/ directory (or whatever you care to call it). You need to create an empty foo/__init__.py file, as that is important for the import machinery.
Also, the PYTHONPATH env var in the calling environment matters. In addition to the command line environment, you have now introduced a PyCharm environment. Take care to configure PyCharm correctly for your project. Click on Preferences -> Project Structure and ensure that foo shows up as a Source Folder. You can debug this in either environment by executing these lines:
import sys
import pprint
pprint.pprint(sys.path)
Since import test would succeed even without your project being in place, I recommend you rename to test1.py and use import test1 so you can be sure you're pulling in your code.
I had the same problem, and ended up removing the "from . " that was added from the 2to3 conversion script.

ModuleNotFoundError: No module named '__main__.xxxx'; '__main__' is not a package

Currently trying to work in Python3 and use absolute imports to import one module into another but I get the error ModuleNotFoundError: No module named '__main__.moduleB'; '__main__' is not a package. Consider this project structure:
proj
__init__.py3 (empty)
moduleA.py3
moduleB.py3
moduleA.py3
from .moduleB import ModuleB
ModuleB.hello()
moduleB.py3
class ModuleB:
def hello():
print("hello world")
Then running python3 moduleA.py3 gives the error. What needs to be changed here?
.moduleB is a relative import. Relative only works when the parent module is imported or loaded first. That means you need to have proj imported somewhere in your current runtime environment. When you are are using command python3 moduleA.py3, it is getting no chance to import parent module. You can:
from proj.moduleB import moduleB OR
You can create another script, let's say run.py, to invoke from proj import moduleA
Good luck with your journey to the awesome land of Python.
Foreword
I'm developing a project which in fact is a Python package that can be installed through pip, but it also exposes a command line interface. I don't have problems running my project after installing it with pip install ., but hey, who does this every time after changing something in one of the project files? I needed to run the whole thing through simple python mypackage/main.py.
/my-project
- README.md
- setup.py
/mypackage
- __init__.py
- main.py
- common.py
The different faces of the same problem
I tried importing a few functions in main.py from my common.py module. I tried different configurations that gave different errors, and I want to share with you with my observations and leave a quick note for future me as well.
Relative import
The first what I tried was a relative import:
from .common import my_func
I ran my application with simple: python mypackage/main.py. Unfortunately this gave the following error:
ModuleNotFoundError: No module named '__main__.common'; '__main__' is not a package
The cause of this problem is that the main.py was executed directly by python command, thus becoming the main module named __main__. If we connect this information with the relative import we used, we get what we have in the error message: __main__.common. This is explained in the Python documentation:
Note that relative imports are based on the name of the current module. Since the name of the main module is always __main__, modules intended for use as the main module of a Python application must always use absolute imports.
When I installed my package with pip install . and then ran it, it worked perfectly fine. I was also able to import mypackage.main module in a Python console. So it looks like there's a problem only with running it directly.
Absolute import
Let's follow the advise from the documentation and change the import statement to something different:
from common import my_func
If we now try to run this as before: python mypackage/main.py, then it works as expected! But, there's a caveat when you, like me, develop something that need to work as a standalone command line tool after installing it with pip. I installed my package with pip install . and then tried to run it...
ModuleNotFoundError: No module named 'common'
What's worse, when I opened a Python console, and tried to import the main module manually (import mypackage.main), then I got the same error as above. The reason for that is simple: common is no longer a relative import, so Python tries to find it in installed packages. We don't have such package, that's why it fails.
The solution with an absolute import works well only when you create a typical Python app that is executed with a python command.
Import with a package name
There is also a third possibility to import the common module:
from mypackage.common import my_func
This is not very different from the relative import approach, as long as we do it from the context of mypackage. And again, trying to run this with python mypackage/main.py ends similar:
ModuleNotFoundError: No module named 'mypackage'
How irritating that could be, the interpreter is right, you don't have such package installed.
The solution
For simple Python apps
Just use absolute imports (without the dot), and everything will be fine.
For installable Python apps in development
Use relative imports, or imports with a package name on the beginning, because you need them like this when your app is installed. When it comes to running such module in development, Python can be executed with the -m option:
-m mod : run library module as a script (terminates option list)
So instead of python mypackage/main.py, do it like this: python -m mypackage.main.
In addition to md-sabuj-sarker's answer, there is a really good example in the Python modules documentation.
This is what the docs say about intra-package-references:
Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.
If you run python3 moduleA.py3, moduleA is used as the main module, so using the absolute import looks like the right thing to do.
However, beware that this absolute import (from package.module import something) fails if, for some reason, the package contains a module file with the same name as the package (at least, on my Python 3.7). So, for example, it would fail if you have (using the OP's example):
proj/
__init__.py (empty)
proj.py (same name as package)
moduleA.py
moduleB.py
in which case you would get:
ModuleNotFoundError: No module named 'proj.moduleB'; 'proj' is not a package
Alternatively, you could remove the . in from .moduleB import, as suggested here and here, which seems to work, although my PyCharm (2018.2.4) marks this as an "Unresolved reference" and fails to autocomplete.
Maybe you can do this before importing the moduleļ¼š
moduleA.py3
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from moduleB import ModuleB
ModuleB.hello()
Add the current directory to the environment directory
Just rename the file from where you run the app to main.py:
from app import app
if __name__ == '__main__':
app.run()
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
will solve the issue of import path issue.

Resources