Python Code Coverage Failing with import statements - python-3.x

I have the following project structure:
v/b.py
v/e.py
v/e_test.py
v/p.py
v/__init__.py
#v/e.py
from b import B
from p import P
class E(object):
def run(self): pass
#v/p.py
class P(object):
def run(self): pass
#v/b.py
from p import P
class B(object):
def run(self): pass
#v/e_test.py
from e import E
import unittest
class ETest(unittest.Testcase):
def testSomething(self): pass
if __name__ == '__main__':
unittest.main()
Then I run this pip3 install coverage.
Then coverage run e_test.py
It's giving me this error
Traceback (most recent call last):
File "e_test.py", line 4, in <module>
from e import E
File "~/v/e.py", line 1, in <module>
from b import B
File "~/v/b.py", line 1, in <module>
from p import P
ImportError: cannot import name 'P' from 'p' (/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/p.py)
My question now is how to fix this. Also I want to be able to run:
coverage run e_test.py b_test.py files_test.py
python3 e_test.py
python3 e.py

mm, I think P Class is not declared yet, so you got an error like that

#v/p.py
class P(object):
def run(self): pass
You haven't defined what P is, the error is reporting that p.py does not have a P object.

At last I found the answer. If I'm in the parent folder which contains the v folder, I can run the following command.
PYTHONPATH=./v:$PYTHONPATH coverage run -m unittest discover -s v -p "*_test.py"
or without coverage
PYTHONPATH=./v:$PYTHONPATH python3 -m unittest discover -s v -p "*_test.py"
If I'm inside the v folder, I can run
python3 e.py
and
python3 e_test.py

Related

How to Unittest sys.argv with multiple values

Let's say I have a Python script file that uses sys.argv variables. And I want to test the sys.argv with different values in multiple tests. The issue is that I have to patch and import it multiple times but i think it holds the sys.args values only from the first import so both TestCases print the same values ['test1', 'Test1']. Is my approach wrong?
example.py
import sys
ex1 = sys.argv[0]
ex2 = sys.argv[1]
print(ex1)
print(ex2)
test_example.py
import unittest
import mock
import sys
class TestExample(unittest.TestCase):
#mock.patch.object(sys, 'argv', ['test1', 'Test1'])
def test_example1(self):
import example
#mock.patch.object(sys, 'argv', ['test2', 'Test2'])
def test_example2(self):
import example
The problem is that Python will not (unless you work hard at it) reimport the same file more than once.
What you should do is have the import only define stuff, and define a main() function in your module that gets called when it's time to run stuff. You call this main() function directly in the script when the script is called by itself (see the last two lines of example.py below), but then you can also call that function by name during unit testing.
For what it's worth, this is best practice in Python: your scripts and module should mostly define functions, classes and whatnot on import, but not run much. Then you call your main() function in a __name__ guard. See What does if __name__ == "__main__": do? for more details about that.
Here's your code modified to work, testing your module with two different sets of sys.argv values:
example.py:
import sys
def main():
ex1 = sys.argv[0]
ex2 = sys.argv[1]
print(ex1)
print(ex2)
if __name__ == "__main__":
main()
test-example.py:
import unittest
import mock
import sys
import example
class TestExample(unittest.TestCase):
#mock.patch.object(sys, 'argv', ['test1', 'Test1'])
def test_example1(self):
example.main()
#mock.patch.object(sys, 'argv', ['test2', 'Test2'])
def test_example2(self):
example.main()
Results from python -m unittest:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
test1
Test1
test2
Test2

Python3 import issues when running directly vs pytests

I have a project like
.
|-application
|---foo.py
|---bar.py
|-tests
|---test_foo.py
Contents are:
bar.py
def myfunc():
return "hello from bar"
foo.py
from bar import myfunc
def do_work():
return myfunc()
if __name__ == "__main__":
print(do_work())
test_bar.py
from application import foo
class TestFoo:
def test_foo_do_work(self):
assert foo.do_work() == "hello from bar"
Running python application/foo.py works great, but running python -m pytest tests/ returns error ModuleNotFoundError: No module named 'bar'
In foo.py one way to fix this is to change the import line from from bar import myfunc to from application.bar import myfunc. This causes pytest to pass, but running python application/foo.py gives an error ModuleNotFoundError: No module named 'application'
I don't know what I'm doing wrong. I'm using python 3.7 so I heard __init__.py is unnecessary.
After a little more googling, I have an answer. I created an __init__.py file inside of tests dir with the contents:
import os
import sys
project_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
app_path = os.path.join(project_path, 'application')
sys.path.append(app_path)
From Python nested subpackage doesn't import when running tests

Python 3 import class from subfolder problem

I have a strange problem regarding import classes from subfolders.
I'm using Python 3.6, therefore an __init__.py should be not required in the subfolders.
I have the following file structure:
root
├── script.py (main)
└── custom
├── class1.py
└── class2.py
This is script.py:
from custom.class1 import Class1
from custom.class2 import Class2
if __name__ == '__main__':
cl1 = Class1()
cl2 = Class2()
This is class1.py:
class Class1():
def __init__(self):
print('Class1')
if __name__ == '__main__':
cl1 = Class1()
This is class2.py, which imports also class1:
from class1 import Class1
class Class2():
def __init__(self):
cl1 = Class1()
print('Class2')
if __name__ == '__main__':
cl2 = Class2()
And now the problem:
It works without error, when i am running python class1.py in the custom subfolder.
It works without error, when i am running python class2.py in the custom subfolder.
But when i am running python script.py in the root folder, i get the following error:
Traceback (most recent call last):
File .... in <module>
from custom.class2 import Class2
File .... line 1, in <module>
from class1 import Class1
ModuleNotFoundError: No module named 'class1'
How can this be fixed in a way, that the scripts in the custom subfolders can be run on its own and also the script in the root folder works?
The problem is that you are running custom.class2 inside of script.py, which means while running custom.class2, you are still in the root directory.
To fix this, you should replace from class1 import Class1 from class2.py with from custom.class1 import Class1.
If you need to be able to run the file from any working directory, you may replace it's contents with this:
import os
import sys
path = os.path.abspath(os.path.dirname(__file__))
if not path in sys.path:
sys.path.append(path)
from class1 import Class1
class Class2():
def __init__(self):
cl1 = Class1()
print('Class2')
if __name__ == '__main__':
cl2 = Class2()
The code adds the file's path in to the sys.path list, which holds different paths from which you can import modules.

Python3 imports changes

I have a module that uses enums defined in the same package. I want to run it locally for self testing and also access it from other packages, but I can't get the import for the enum to handle both situations.
I have tried a blank _ _ init _ _.py (without the spaces) in both the sub and the proj directories, with no apparent change.
I have tried variations of python -m without success.
Here is the minimal code that shows my problems:
/my/proj
|----sub
| |---e1.py
| |---one.py
| |---two.py
|-p1.py
|-p2.py
----
$ cat /my/proj/sub/e1.py
from enum import Enum
class UsefulEnums(Enum):
ZERO = 0
----
$ cat /my/proj/sub/one.py
from e1 import UsefulEnums as E
def profound():
print('The value of {} is {}'.format(E.ZERO.name, E.ZERO.value))
if __name__ == '__main__':
profound()
/my/proj/sub$ python one.py
The value of ZERO is 0
----
$ cat /my/proj/sub/two.py
# note the dot before the module name. No other change from one
from .e1 import UsefulEnums as E
def profound():
print('The value of {} is {}'.format(E.ZERO.name, E.ZERO.value))
if __name__ == '__main__':
profound()
/proj/sub$ python two.py
Traceback (most recent call last):
File "two.py", line 1, in <module>
from .e1 import UsefulEnums as E
ModuleNotFoundError: No module named '__main__.e1'; '__main__' is not a package
----
$ cd /my/proj
/my/proj$ cat p1.py
import sub.one as a
if __name__ == '__main__':
a.profound()
/my/proj$ python p1.py
Traceback (most recent call last):
File "p1.py", line 1, in <module>
import sub.be1 as a
File "/home/esmipau/delete_me/proj/sub/one.py", line 1, in <module>
from e1 import UsefulEnums as E
ModuleNotFoundError: No module named 'e1'
----
/my/proj$ cat p2.py
import sub.two as a
if __name__ == '__main__':
a.profound()
/my/proj$ python p2.py
The value of ZERO is 0
When run from the 'sub' directory, one.py works as expected, two.py fails with a 'ModuleNotFoundError' error as detailed above.
When imported in parent code and run from the parent directory, two.py now works, and one.py fails with a different 'ModuleNotFoundError' error.
I would like a three.py in the 'sub' directory that uses the enums defined in e1.py, and which can be run locally for self testing etc, and can be included from external module not in the same directory.
--- edit for close as duplicate suggestions ---
This is not the same question as others that have been suggested such as Correct import and package structure now that __init__.py is optional as I require a way for one module to import another in the same directory regardless of whether the module is being executed locally or imported from another module.
I had simmilar issue and this solved it:
try creating __init__ file like this:
import my.proj.sub.e1
and then in file you want to use add:
from my.proj.sub import UsefulEnums as E
Given the structure :
/proj
|---/pkg
| |---> usefulEnums.py
| |---> usefulCode.py
|--> myProj.py
I want to be able to run usefulCode.py in self test mode and I want to import and use it in myProj.
$ cat proj/pkg/usefulEnums.py
from enum import Enum
class UsefulEnums(Enum):
ZERO = 0
$ cat proj/pkg/usefulCode.py
if __package__ is None:
# works with python <path/>tcp.py
from usefulEnums import UsefulEnums as E
else:
# works with python -m pkg.tcp
# or when imported by another module
from pkg.usefulEnums import UsefulEnums as E
# This works as well and appears more more portable and pythonic
# but the logic that makes it work is obtuse and fragile
# and it doesn't work if __package__ is None (even though it should!)
# from .usefulEnums import UsefulEnums as E
def profound():
print('The value of {} is {}'.format(E.ZERO.name, E.ZERO.value))
if __name__ == '__main__':
profound()
The main project code is as expected:
cat proj/myProj.py
from pkg.usefulEnums import UsefulEnums as E
import pkg.usefulCode as u
if __name__ == '__main__':
u.profound()
The above is the work around I am accepting as the answer to my stated question, but the reasoning eludes me.
I do not understand why the behavior of the 'dot' import does not work as expected when __package__ is not defined. Surely it always means import relative to the current package, and if no package is explicitly defined, then why doesn't it mean import from the same directory as the current module, which could be argued to be the currently default package?

Trying to import python file to main python file but got Import error in rpi

I am trying to import a python file to main.py.
test1.py
def some_func():
print ('Test1')
if__name__ == '__main__':
service_func()
test1.some_func()
main.py
import test1
def service_func():
print('Service func')
if__name__ == '__main__':
service_func()
test1.some_func()
This code can works in windows but it cannot work on RPI 3. The error message is ImportError: No module name test1.
Please kindly assist.
Thanks

Resources