Instructors
Training Material:
The environment.yml file specifies the dependencies that will be installed in your environment.:
name: env-notebook
dependencies:
- python>=3.9
- ipykernel
$ conda env create -f environment1.yml
$ conda activate env-notebook
$ conda search package-name
$ conda install package-name
$ conda update package-name
$ conda remove package-name
$ conda list
$ conda env list
$ conda remove -n ENVNAME --all
$ conda env export --name ENVNAME > file-name.yml
$ conda env export --name ENVNAME --no-builds | grep -v "prefix" > file-name.yml
$ conda create --clone ENVNAME --name NEWENV
Check this Conda Cheat Sheet!
When Python sees one, it evaluates the assertion’s condition. If it’s true, Python does nothing, but if it’s false, Python halts the program immediately and prints the error message if one is provided.
assert condition, Optional Error Message
# AssertionError with error_message.
a = 1
b = 0
assert b != 0, "Invalid Operation" # denominator can't be 0
print(a / b)
# AssertionError without error_message.
a = 1
b = 0
assert b != 0 # denominator can't be 0
print(a / b)
def average(values):
return (sum(values)/len(values))
What pre-conditions and post-conditions we should write?
def average(values):
return (sum(values)/len(values))
What pre-conditions and post-conditions we should write?
# check if it is a list
assert isinstance(values, list)
# check if all values are integer or real numbers
assert all([isinstance(item, int) or isinstance(item, float) for item in values]
# check list length. Should be greater than zero values
assert len(values)>0
# Average is within the range of the given data
assert average([2,20])>2 and average([2,20])<20
assert average(values)>min(values) and average(values)<max(values)
# Test if works with equal values
assert average([2, 2, 5])==3
# Test if works with negative values
assert average([-2, 2, 6])==2
def get_total_cars(values):
values = [int(element) for element in values]
total = sum(values)
return total
Consider the following function
Given a sequence of a number of cars, the function get_total_cars returns the total number of cars. So, get_total_cars([1, 2, 3, 4]) should return 10.
def get_total(values):
assert len(values) > 0
for element in values:
assert int(element)
values = [int(element) for element in values]
total = sum(values)
assert total > 0
return total
What the assertions in this function check
testing saves time.
tests (should) ensure code is correct
runnable specification: best way to let others know what a function should do and not do.
reproducible debugging: debugging that happened and is saved for later reuse
easier to modify since results can be tested
Unit Tests: Unit tests investigate the behaviors of units of code (such as functions, classes, or data structures). By validating each software unit across the valid range of its input and output parameters, tracking down unexpected behaviors that may appear when the units are combined is made vastly simpler.
Regression Tests: Regression tests defend against new bugs, or regressions, which might appear due to new software and updates.
Integration Tests: Integration tests check that various pieces of the software work together as expected.
“My program doesn’t work” isn’t good enough: in order to diagnose and fix problems, we need to be able to tell correct output from incorrect.
We can only debug something when it fails, so the second step is always to find a test case that makes it fail every time.
The “every time” part is important because few things are more frustrating than debugging an intermittent problem.
If it takes 20 minutes for the bug to surface, we can only do three experiments an hour.
# AssertionError with error_message.
a = 1
b = 0
assert b != 0, "Invalid Operation" # denominator can't be 0
print(a / b)
Every time we make a change, however small, we should re-run our tests immediately.
The more things we change at once, the harder it is to know what’s responsible for what.
Good scientists keep track of what they’ve done so that they can reproduce their work.
If we can’t find a bug in 10 minutes, we should be humble and ask for help.
Each time we make changes to a code, we would like to test it.
This can be tedious and that might prevent us from testing.
We want to make testing as easy as version control is. A testing framework can help us.
In pytest, each test is a function whose name begins with the letters test. We can group tests together in files whose names also begin with the letters test. To execute our tests we run the command pytest.
# example method
def inc(x):
return x + 1
# content of test_sample.py
def test_answer():
assert inc(3) == 5
$ pytest
============================= test session starts =============================
collected 1 items
test_sample.py F
================================== FAILURES ===================================
_________________________________ test_answer _________________________________
def test_answer():
> assert inc(3) == 5
E assert 4 == 5
E + where 4 = inc(3)
test_sample.py:5: AssertionError
========================== 1 failed in 0.04 seconds ===========================
By simple executing pytest:
Consider the following
For example, suppose we need to find where two or more time series overlap.
The range of each time series is represented as a pair of numbers, which are the time the interval started and ended.
The output is the largest range that they all include!
Write a short function for each test.
Write a range_overlap function that should pass those tests.
If range_overlap produces any wrong answers, fix it and re-run the test functions.
file: overlap.py
def range_overlap():
# insert here your function
file: test_overlap.py
from overlap import range_overlap
def test_something():
# insert here your test
def test_anotherthing():
# insert here your test