Python unittest with test/ and src/ not finding src modules - python

I have a simple directory structure:
proj/
src/
__init__.py
foo.py
bar.py
test/
__init__.py
test_foo.py
test_foo.py
import unittest
import sys
sys.path.append('../src')
from src import foo
class TestFoo(unittest.TestCase):
def test_foo(self):
foo.start()
if __name__ == '__main__':
unittest.main()
foo.py
import bar
def start():
bar.do_stuff()
When running my test (I'm using vscode), I get the following error:
Failed to import test module: test_foo
Traceback (most recent call last):
File "~/.pyenv/versions/3.8.6/lib/python3.8/unittest/loader.py", line 436, in _find_test_path
module = self._get_module_from_name(name)
File "~/.pyenv/versions/3.8.6/lib/python3.8/unittest/loader.py", line 377, in _get_module_from_name
__import__(name)
File "~/proj/test/test_foo.py", line 6, in <module>
from src import foo
File "~/proj/src/foo.py", line 1, in <module>
import bar
ModuleNotFoundError: No module named 'bar'
I'm not sure why the test can't discover the src/bar when importing src/foo

Instead of import bar try from src import bar.
from src import bar
def start():
bar.do_stuff()
Notice
Keep in mind, that you only adjusted the path in the test. You do not want the tests to work, but the application to fail because you forgot to adjust the path in the application at some point.

What is in your bar.py file? Just the do_stuff() function? Or is the do_stuff() function a method of object bar?
Depending on the answer to the question above, try doing something like this in your foo.py file:
from proj.src.bar import [name of function you're testing here]
In your specific case, it would be like this if do_stuff() is a standalone function:
from proj.src.bar import do_stuff
and then your foo.py file would be:
from proj.src.bar import do_stuff
def stuff():
do_stuff()
However, if do_stuff() is a method of the bar object, it would probably be something like this, although it's hard to tell without knowing the contents of the bar.py file:
from proj.src.bar import bar
and then your foo.py file would be similar to the way you have it now:
from proj.src.bar import bar
def stuff():
bar.do_stuff()
I recently ran into a similar problem when trying to import one neighboring file into another. This link helped me out, too.

Two changes:
from src import bar in foo.py,
before import modules in test_foo.py, add
import sys
sys.path.append("./")
Then you should be able to run code successfully.

In my case, I had imports of modules which are not actually installed, in my bar.py file, such as:
import requests
After installing those modules, VSCode showed tests properly.

Related

ModuleNotFoundError: No module named 'sharedFunctions'

I have a Python project in which I have the following folder structure:
> root
> download_module
> __init__.py
> downloadProcess.py
> sharedFunctions.py
> someHelper.py
> useSharedFunction.py
The download_module/__init__.py has the following code:
from .sharedFunctions import stringArgumentToDate
from .downloadProcess import downloadProcessMethod
The sharedFunctions.py file contains the following function:
def stringArgumentToDate(arg):
dateformat = "%m/%d/%Y"
date = None
if arg.isnumeric():
date = datetime.fromtimestamp(int(arg))
if date == None:
date = datetime.strptime(arg, dateformat)
return date
Then on the useSharedFunction.py I try to import the shared function and use it like this.
from download_module import stringArgumentToDate
from download_module import downloadProcessMethod
def main():
arg = '03/14/2022'
dateArg = stringArgumentToDate(arg)
if __name__ == '__main__':
main()
When I try to run this by using python3 useSharedFunction.py I got the following error:
Traceback (most recent call last):
File "useSharedFunction.py", line 4, in <module>
from download_module import stringArgumentToDate
File "/Users/jacobo/Documents/project/download_module/__init__.py", line 2, in <module>
from .download_module import downloadAndProcessMethod
File "/Users/jacobo/Documents/project/download_module/downloadProcess.py", line 10, in <module>
from sharedFunctions import stringArgumentToDate, otherFunction
ModuleNotFoundError: No module named 'sharedFunctions'
I do believe the error is in downloadProcess since at the beggining of the file we got this import:
from sharedFunctions import stringArgumentToDate, otherFunction
from someHelper import Helper
Which refers to sibling files.
However I'm unsure what will be a proper fix to allow to run the downloadProcess.py main independently but also, being able to call it one of its method from a root or any other file out of the module.
Consider this structure:
┬ module
| ├ __init__.py
| ├ importing_submodule.py
| └ some_submodule.py
├ __main__.py
├ some_submodule.py
└ module_in_parent_dir.py
with content:
__main__.py
import module
/module/__init__.py
from . import importing_submodule
/module/importing_submodule.py
from some_submodule import SomeClass
/module/some_submodule.py
print("you imported from module")
class SomeClass:
pass
/some_submodule.py
print("you imported from root")
class SomeClass:
pass
/module_in_parent_dir.py
class SomeOtherClass:
pass
How sibling import works
(skip this section if you know already)
Now lets run __main__.py and it will say "you imported from root".
But if we change code a bit..
/module/importing_submodule.py
from module.some_submodule import SomeClass
It now says "You imported from module" as we wanted, probably with scary red line in IDE saying "Unresolved reference" if you didn't config working directory in IDE.
How this happen is simple: script root(Current working directory) is decided by main script(first script that's running), and python uses namespaces.
Python's import system uses 2 import method, and for convenience let's call it absolute import and relative import.
Absolute import: Import from dir listed in sys.path and current working directory
Relative import: Import relative to the very script that called import
And what decide the behavior is whether we use . at start of module name or not.
Since we imported by from some_submodule without preceeding dot, python take it as 'Absolute import'(the term we decided earlier).
And then when we also specified module name like from module.some_submodule python looks for module in path list or in current working directory.
Of course, this is never a good idea; script root can change via calls like os.chdir() then submodules inside module folder may get lost.
Therefore, the best practices for sibling import is using relative import inside module folder.
/module/importing_submodule.py
from .some_submodule import SomeClass
Making script that work in both way
To make submodule import it's siblings when running as main script, yet still work as submodule when imported by other script, then use try - except and look for ImportError.
For importing_submodule.py as an example:
/module/importing_submodule.py
try:
from .some_submodule import SomeClass
except ImportError:
# attempted relative import with no known parent package
# because this is running as main script, there's no parent package.
from some_submodule import SomeClass
Importing modules from parent directory is a bit more tricky.
Since submodule is now main script, relative import to parent level directory doesn't work.
So we need to add the parent directory to sys.path, when the script is running as main script.
/module/importing_submodule.py
try:
from .some_submodule import SomeClass
except ImportError:
# attempted relative import with no known parent package
# because this is running as main script, there's no parent package.
from some_submodule import SomeClass
# now since we don't have parent package, we just append the path.
from sys import path
import pathlib
path.append(pathlib.Path(__file__).parent.parent.as_posix())
print("Importing module_in_parent_dir from sys.path")
else:
print("Importing module_in_parent_dir from working directory")
# Now either case we have parent directory of `module_in_parent_dir`
# in working dir or path, we can import it
# might need to suppress false IDE warning this case.
# noinspection PyUnresolvedReferences
from module_in_parent_dir import SomeOtherClass
Output:
"C:\Program Files\Python310\python.exe" .../module/importing_module.py
you imported from module
Importing module_in_parent_dir from sys.path
Process finished with exit code 0
"C:\Program Files\Python310\python.exe" .../__main__.py
you imported from module
Importing module_in_parent_dir from working directory
Process finished with exit code 0

issue with nested python module importing when executing imported function itself

I believe this question must have already been asked but I cannot find an explanation for my problem, sorry if it is a duplicate.
Folder
├── Generator.py
└── modules
├── Function1.py
└── Subfunction.py
Generator.py imports Function1, and Function1 imports Subfunction.
Function1 must be able to be run as a standalone program and as an imported module of Generator.py
It is not a problem itself, as I am using the if __ name__ == "__ main__": to recognize the call type.
But the program fails on importing Subfunction depending on the code I am executing.
# Generator.py
import Function1
# Function1.py
import Subfunction
import modules.Subfunction
The first one works if I execute Function1.py, but it fails if I run Generator.py
The second one works if I execute Generator.py, but it fails if I run Function1.py
I thought imports and relative paths are related to the module where the code is placed, not from a perspective of the top-caller. I tried import .modules.Function1 and import .Function1 but the issue remains.
Is there any elegant way to import Subfunction for both uses, or do I need to include import under if name == main or trap it in try/except?
Edit: all code for #Bastien B
In this shape it works if I execute Function1.py itself.
If I execute Generator.py, I get the ModuleNotFoundError: No module named 'Function1'
# Generator.py
import Function1
print(Function1.Function1_return)
# Function1.py
def Function1_return():
return Subfunction.Subfunction_return()
import Subfunction
if __name__ == '__main__':
print(Function1_return())
# Subfunction.py
def Subfunction_return():
return "this is subfunction"
From what i can see your 'if name ...' is not the problem.
If you use a local venv this should work just fine:
generator.py
from Folder.modules.function1 import Function1_return
print(Function1_return())
Function1.py
from Folder.modules.Subfunction import Subfunction_return
def Function1_return():
return Subfunction_return()
if __name__ == '__main__':
print(Function1_return())
Subfunction.py
def Subfunction_return():
return "this is subfunction"
Depending of your files structure you may have to tweak this a beat

A strange "No module named 'XX' " problem

I know how to import a package or module, but I meet a quite strange problem.
If I run swmm5_extend_function/example.py, everything is fine. However, when I run example.py, errors occur:
Traceback (most recent call last):
File "example.py", line 2, in <module>
from swmm5_extend_function.Swmm5Extend import SWMM5ReadInp
File "C:\project\swmm5_extend_function\Swmm5Extend.py", line 1, in <module>
import swig.SWMM5ReadInpFile as swmm
ModuleNotFoundError: No module named 'swig'
Here is my project structure:
project/
-- example.py
-- ......
-- swmm5_extend_function/
-- __init__.py
-- example.py
-- Swmm5Extend.py
-- swig/
-- __init__.py
-- SWMM5ReadInpFile.py
-- ....
Here is code of each .py file:
swmm5_extend_function/Swmm5Extend.py
import swig.SWMM5ReadInpFile as swmm
class SWMM5ReadInp(object):
pass
swmm5_extend_function/example.py
from Swmm5Extend import SWMM5ReadInp
example.py
from swmm5_extend_function.Swmm5Extend import SWMM5ReadInp
I want to know why this strange error happens.
For a better explanation, I've created the following folder structure:
test/
-- __init__.py
-- greeter.py # Greets in German
-- subfolder/
-- __init__.py
-- greeter.py # Greets in Italian
-- test.py
-- deepfolder/
-- __init__.py
-- greeter.py # Greets in France
As you may notice, we have 3 files with the same name, each one greets in a different language using a function with the same name. The only function in a greeter.py file is:
def says():
print("Hello World!")
IMPORT FROM THE SAME FOLDER
If from test.py file we import greeter and run the says function, we'll have:
import greeter as greeter
greeter.says()
Output:
Buongiorno Mondo! # Italian output
IMPORT FROM A SUBFOLDER
But what if we want to import from a subfolder?
To import from a subfolder (i.e., deepfolder/), we simply add an empty __init__.py file into the folder, then we can specify the path in the import:
import deepfolder.greeter as greeter
greeter.says()
Output:
Bonjour le Monde! # France output
IMPORT FROM A PARENT FOLDER
At last, you may want to import from a parent folder.
You should try to have your main running file at the top of the folder tree, but things happens and you find yourself looking to import a module from a parent folder.
For doing this, you need to add the parent folder to the sys.path:
import sys
sys.path.append("/path/to/dir")
from test import greeter as greeter
greeter.says()
Output:
Guten Morgen Welt! # German output
Importing scripts and modules isn't really the most pythonic way to solve things, you may want to have a look on Python's documentation about packages.
TL;DR
In your project/example.py use
import swmm5_extend_function.swig.SWMM5ReadInpFile as swmm
instead of
import swig.SWMM5ReadInpFile as swmm

__init__.py not working correctly in python

i want to make a sample package in python 2.7 just to clear my concepts whose structure looks like this:
calculator/
main.py
operations/
file1.py
file2.py
__init__.py
new_operations/
__init__.py
file3.py
main.py content: (this file is present inside calculator folder)
from operations import power
print power(2,2)
__init__.py content: (this file is present inside operations folder)
from .file1 import add
from .file1 import sub
from .file2 import mul
from .file2 import div
file1.py content: (this file is present inside operations folder)
def add(a,b):
return(a+b)
def sub(a,b):
return(a-b)
file2.py content: (this file is present inside operations folder)
def mul(a,b):
return(a*b)
def div(a,b):
return(a/b)
__init__.py content: (this file is present inside new_operations folder)
from .file3 import power
file3.py content: (this file is present inside new_operations folder)
def power(a,b):
return(a**b)
Now, when i run main.py, i got following error:
Traceback (most recent call last):
File "C:\Python27\mycodes\calculator\main.py", line 3, in <module>
from operations import power
ImportError: cannot import name power
Can anyone tell me, what mistake i am doing ? Help me.
Use the following line in your "main.py" file:
from operations.new_operations import power
You are missing an 'add' function in your calculator module. If you create an 'add' function, I would assume that the code would work.
maybe try doing this in the module calculator:
def add(num1,num2):
print(num1+num2)
return num1+num2;
If you don't want it to print while calculating, remove the print statement.
Hope this helps!

Importlib.import_module will not import the module even though the param is the abs path

I have my .py module which is in C:\Python_Projects\MyModules\ with the name button_generator.py.
My code goes something like this:
module_path='C:\\Python_Projects\\MyModules'
module_name='button_generator.py'
sys.path.append(module_path)
try:
limp=importlib.import_module(module_name.split('.')[0])
except:
print 'module import error'
I have tried other versions aswell:
importlib.import_module(module_name) without the split
importlib.import_module('C:\Python_Projects\MyModules\button_generator.py')
importlib.import_module('C:\Python_Projects\MyModules\button_generator')
The folder C:\Python_Projects\MyModules is in my sys.path as I checked during debug.
Why wouldn't the module import?
I suggest you to reorder your project directories and avoid calling other modules which are not in your current directory project. You'll avoid those kind of errors.
For example, let's organize our project directories and folders to look something like this:
MyProjectFolder/
├── main.py
└── modules
├── __init__.py
└── MyLib.py
NB: Don't forget to add an empty file called __init__.py
MyLib.py :
#!/usr/bin/python3
class MyLib:
def __init__(self):
self.say_hello = "Hello i'm in modules/MyLib"
def print_say_hello(self):
print(self.say_hello)
main.py:
#!/usr/bin/python3
# from folder.file import class
from modules.MyLib import MyLib
class MainClass:
def __init__(self):
my_lib = MyLib() # load MyLib class
my_lib.print_say_hello() # access to MyLib methods
### Test
if __name__ == '__main__':
app = MainClass()
In terminal when i run:
$ python3 main.py
output:
Hello i'm in modules/MyLib
So here we have successfully imported the class in modules/MyLib.py into our main.py file.
I found the error:
After treating the ImportError exception by printing it's args, I noticed that button_generator.py had an Import that was not resolving. Basically, button_generator.py could not be imported because it had a wrong import.

Categories

Resources