How to use Python 3.6 interpreter inside a bash script? - python

I want to have a little script, that will find, run and report about all the tests in the folder, like this one:
#!/bin/bash
coverage run -m unittest discover
coverage report -m
But, when I run it, I get some errors, which I do not get on Windows (like using of super() without an argument). As I've understood, it's connected with the fact, that build-in and default version of Python on Linux is 2.x, whereas I am using 3.6. How should I change the script, so it would use Python 3.6 interpreter?
EDIT:
So here's one of the files with tests that I run:
#!/usr/bin/env python3
import unittest
import random
import math
import sort_functions as s
from comparison_functions import less, greater
class BaseTestCases:
class BaseTest(unittest.TestCase):
sort_func = None
def setUp(self):
self.array_one = [101, -12, 99, 3, 2, 1]
self.array_two = [random.random() for _ in range(100)]
self.array_three = [random.random() for _ in range(500)]
self.result_one = sorted(self.array_one)
self.result_two = sorted(self.array_two)
self.result_three = sorted(self.array_three)
def tearDown(self):
less.calls = 0
greater.calls = 0
def test_sort(self):
result_one = self.sort_func(self.array_one)
result_two = self.sort_func(self.array_two)
result_three = self.sort_func(self.array_three)
self.assertEqual(self.result_one, result_one)
self.assertEqual(self.result_two, result_two)
self.assertEqual(self.result_three, result_three)
# and some more tests here
class TestBubble(BaseTestCases.BaseTest):
def setUp(self):
self.sort_func = s.bubble_sort
super().setUp()
# and some more classes looking like this
And the error:
ERROR: test_key (test_sort_func.TestBubble)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/lelik/Desktop/Sorters/test_sort_func.py", line 67, in setUp
super().setUp()
TypeError: super() takes at least 1 argument (0 given)

First, install it for your python3 (if you have it and pip installed)
sudo python3 -m pip install coverage
Then, in order to run coverage for python3, run python3 -m coverage report -m
So your final script should look like this:
#!/bin/bash
python3 -m coverage run -m unittest discover
python3 -m coverage report -m
Also you can replace python3 with path to your pythons bin. For example /usr/bin/python3. So You can call it this way as well:
#!/bin/bash
/usr/bin/python3 -m coverage run -m unittest discover
/usr/bin/python3 -m coverage report -m

The problem is that the coverage command on your Linux host has been installed for Python 2. That is, somewhere there exists a coverage script that starts with:
#!/usr/bin/python
And on your system, /usr/bin/python is python 2.
The best solution here is probably to set up a Python 3 virtual environment for running your tests (and then installing coverage into that virtualenv). You may also want to investigate tox, which will handle this for you automatically.

Related

sytanx error running pytest from terminal

I'm trying to use pytest with a simple example, saved as "test_lesson1.py" with directory structure as shown below.
import pytest
TOL = 2e-2
def squared(x):
return x**2
def test_squared():
x = 4
expected = 16
computed = squared(x)
msg = "fail"
np.testing.assert_allclose(expected, computed, rtol=TOL, err_msg=msg)
Example directory structure:
proj
|--tests
|--|--test_lesson1.py
On Windows but using Git Bash as a bash terminal, how can I run pytest? Here is what I am entering the terminal:
alias py='C:/Users/name/anaconda3/envs/myenv/python.exe'
. C:/Users/name/anaconda3/etc/profile.d/conda.sh
conda activate myenv
cd tests/
py -c "pytest test_lesson1.py"
which returns
File "<string>", line 1
pytest test_lesson1.py
^
SyntaxError: invalid syntax
(myenv)
I can confirm that python works with py -c "print('hello world')", which prints as expected.
pytest is a command that will execute all tests in all files whose names follow the form test_*.py or \*_test.py in the current directory and its subdirectories, therefore you don't need python to invoke it.
Just run
pytest test_lesson1.py
On the other hand, print is a python function and you need python to invoke it.

How to use a python module in combination with a command from shell

I would like to use a python module from shell (to be exact: indirect from gnuplot). I do not want to write for every call an extra script or implement some I/O logic.
Let's say as a minimal working example, I have a python module module_foo.py with
#!/usr/bin/python
def bar():
print(1,2,3)
My question is:
Why isn't it possible to use a python module combining module loading and command execution like here?:
$ python -m module_foo -c 'bar()'
When executed, nothing happens. But what does work, is using only a command call like this
$ python -c 'import module_foo; module_foo.bar()'
1 2 3
or this
$ python -c 'from module_foo import *; bar()'
1 2 3
As soon as I load a module before, even a syntactically errorneous command is “accepted” – not executed, I suppose (the bracked of the call to bar isn't closed):
$ python -m module_foo -c 'bar('
$
It is, however, possible to use the -m module option using a python unit test (from the python docs):
python -m unittest test_module1 test_module2
The python manpage says for both options:
-c command
Specify the command to execute (see next section). This terminates the option
list (following options are passed as arguments to the command).
-m module-name
Searches sys.path for the named module and runs the corresponding .py file as
a script.
So I'd expect to be able to use path options in this -m ... -c ..., but not in reverse order -c ... -m ...'. Am I missing something obvious?
If you want your Python module to be executable and to call function bar(), you should add this to the end of the python file:
if __name__ == "__main__": # this checks that the file is "executed", rather than "imported"
bar() # call the function you want to call
Then call:
python module_foo.py
If you want more control, you can pass arguments to the script and access them from sys.argv.
For even more flexibility in arguments passed to the script, see argparse module.

Mac gcloud install ImportError: No module named __future__

When installing gcloud for mac I get this error when I run the install.sh command according to docs here:
Traceback (most recent call last):
File "/path_to_unzipped_file/google-cloud-sdk/bin/bootstrapping/install.py", line 8, in <module>
from __future__ import absolute_import
I poked through and echoed out some stuff in the install shell script. It is setting the environment variables correctly (pointing to my default python installation, pointing to the correct location of the gcloud SDK).
If I just enter the python interpreter (using the same default python that the install script points to when running install.py) I can import the module just fine:
>>> from __future__ import absolute_import
>>>
Only other information worth noting is my default python setup is a virtual environment that I create from python 2.7.15 installed through brew. The virtual environment python bin is first in my PATH so python and python2 and python2.7 all invoke the correct binary. I've had no other issues installing packages on this setup so far.
If I echo the final line of the install.sh script that calls the install.py script it shows /path_to_virtualenv/bin/python -S /path_to_unzipped_file/google-cloud-sdk/bin/bootstrapping/install.py which is the correct python. Or am I missing something?
The script uses the -S command-line switch, which disables loading the site module on start-up.
However, it is a custom dedicated site module installed in a virtualenv that makes a virtualenv work. As such, the -S switch and virtualenvs are incompatible, with -S set fundamental imports such as from __future__ break down entirely.
You can either remove the -S switch from the install.bat command or use a wrapper script to strip it from the command line as you call your real virtualenv Python.
I had the error below when trying to run gcloud commands.
File "/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/lib/gcloud.py", line 20, in <module>
from __future__ import absolute_import
ImportError: No module named __future__
If you have your virtualenv sourced automatically you can specify the environment variable CLOUDSDK_PYTHON i.e. set -x CLOUDSDK_PYTHON /usr/bin/python to not use the virtualenv python.
In google-cloud-sdk/install.sh go to last line, remove variable $CLOUDSDK_PYTHON_ARGS as below.
"$CLOUDSDK_PYTHON" $CLOUDSDK_PYTHON_ARGS "${CLOUDSDK_ROOT_DIR}/bin/bootstrapping/install.py" "$#"
"$CLOUDSDK_PYTHON" "${CLOUDSDK_ROOT_DIR}/bin/bootstrapping/install.py" "$#"

Pytest file not covered (0 percent lines covered)

I am using the python coverage package to determine line percent coverage for the following file
coverage report -m math_test.py
Once running the command however I ended up having 0 lines covered.
import example
import pytest
import unittest
class SampleTest(unittest.TestCase):
def testAddition(self):
expected = 10
math_addition = example.add(5,5)
self.assertEqual(math_addition, expected)
def add(x,y):
return x+y
Running math_test.py won't do anything. It defines a class and a function, but doesn't do anything with either of them. Coverage.py is not a test runner. You need to use something like pytest or unittest to run the tests:
coverage run -m unittest discover
coverage report -m

Running coverage.py over unit tests with mocking

I'm trying to run code coverage over my program's unit tests. I'm using mock in the tests, which means I have to use python3 and up. I've installed coverage.py using pip:
pip install coverage
The installation worked and coverage is working preperly. The issue is that when I'm trying to run coverage over my unit tests it runs with python2.6 and fails on import mock although my script starts with #!/usr/bin/python3:
coverage run ./my_tests.py
Traceback (most recent call last):
File "./my_tests.py", line 9, in module
from unittest.mock import patch
ImportError: No module named mock
Is there a way to configure coverage to run with python3? Is there a version of coverage which works with python3 by default?
You apparently have 2.6 as your default python. Or at least, you installed the coveragepy module in the 2.6 tree, which put 'coverage' in python26/Scripts, which then runs coveragepy with 2.6. However, the module works with both 2.x and 3.x if you explicitly run it with one or the other instead of just the default.
I happened to have 'installed' coveragepy by cloning it in my dev directory. I also wrote a cover.bat for my particular need, which is to test new and patched idlelib files in my python repository clone before committing them. Here is my file. Of particular relevance to your question are the lines that begin with %py%. I set that to my repository build of 3.4, but you could just as easily point it to installed 3.4 or even make it an input.
#echo off
rem Usage: cover fileName [test_ suffix] # proper case required by coveragepy
rem filename without .py, 2nd parameter if test is not test_filename
setlocal
set py=34\pcbuild\python_d
set src=idlelib.%1
if "%2" EQU "" set tst=34/Lib/idlelib/idle_test/test_%1.py
if "%2" NEQ "" set tst=34/Lib/idlelib/idle_test/test_%2.py
%py% coveragepy run --pylib --source=%src% %tst%
%py% coveragepy report --show-missing
%py% coveragepy html
htmlcov\34_Lib_idlelib_%1.html
rem Above opens new report; htmlcov\index.html displays report index

Categories