diff --git a/Bayes Guards SMS/Vectorize/tests/test_task.py b/Bayes Guards SMS/Vectorize/tests/test_task.py index dd0e079..c629a4e 100644 --- a/Bayes Guards SMS/Vectorize/tests/test_task.py +++ b/Bayes Guards SMS/Vectorize/tests/test_task.py @@ -1,6 +1,6 @@ import unittest import numpy as np -from numpy.ma.testutils import assert_array_equal +from safe_assert import safe_assert_array_equal from vectorize import vectorize @@ -17,6 +17,6 @@ def test_dictionary(self): def test_vectorization(self): X = np.array(["Who let the dogs out?", " Who, who, who, who?"]) dictionary, result = vectorize(X) - assert_array_equal(np.array([1, 1, 1, 1, 1]), result[0]) + safe_assert_array_equal(np.array([1, 1, 1, 1, 1]), result[0], "Incorrect vectorization: each word in the first test document should have a count of 1") self.assertTrue(4 in result[1], msg="Something wrong with the output matrix! " - "If a word is repeated its occurrences need to be counted!") + "If a word is repeated, its occurrences need to be counted!") diff --git a/Comic-Con and K-means/Histogram/tests/test_task.py b/Comic-Con and K-means/Histogram/tests/test_task.py index 24df1b3..2a686c6 100644 --- a/Comic-Con and K-means/Histogram/tests/test_task.py +++ b/Comic-Con and K-means/Histogram/tests/test_task.py @@ -1,6 +1,6 @@ import unittest import numpy as np -from numpy.testing import assert_array_equal +from safe_assert import safe_assert_array_equal from plotting import centroid_histogram @@ -10,4 +10,4 @@ def test(self): labels = np.array([1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 3, 1, 2, 1]) expected = np.array([5, 4, 3, 2, 1]) histogram = centroid_histogram(labels) - assert_array_equal(expected, histogram) + safe_assert_array_equal(expected, histogram, "Incorrect histogram computed") diff --git a/Comic-Con and K-means/Image recoloring/tests/test_task.py b/Comic-Con and K-means/Image recoloring/tests/test_task.py index c57d9ca..be64dec 100644 --- a/Comic-Con and K-means/Image recoloring/tests/test_task.py +++ b/Comic-Con and K-means/Image recoloring/tests/test_task.py @@ -1,5 +1,6 @@ import unittest import numpy as np +from safe_assert import safe_assert_array_equal from processing import recolor @@ -16,7 +17,7 @@ def test_colors_num(self): recolored_image = recolor(image, 2) expected_image = np.array([[255, 255, 254], [0, 1, 0], [0, 1, 0], [255, 255, 254]]) self.assertEqual(2, len(np.unique(recolored_image, axis=0))) - np.testing.assert_array_equal(recolored_image, expected_image) + safe_assert_array_equal(recolored_image, expected_image, "The recolored image does not match the expected image") break except IndexError: continue diff --git a/Comic-Con and K-means/K-means/tests/test_task.py b/Comic-Con and K-means/K-means/tests/test_task.py index 1024112..301f050 100644 --- a/Comic-Con and K-means/K-means/tests/test_task.py +++ b/Comic-Con and K-means/K-means/tests/test_task.py @@ -1,6 +1,6 @@ import unittest import numpy as np -from numpy.testing import assert_array_equal +from safe_assert import safe_assert_array_equal from clustering import k_means, init_clusters from distances import euclidean_distance @@ -25,5 +25,5 @@ def test_kmeans_results(self): continue else: break - assert_array_equal(classification, expected_labels) - assert_array_equal(clusters, expected_centers) + safe_assert_array_equal(classification, expected_labels, "The classification array does not match the expected labels") + safe_assert_array_equal(clusters, expected_centers, "The cluster centers array does not match the expected centers") diff --git a/Comic-Con and K-means/Reading an image/tests/test_task.py b/Comic-Con and K-means/Reading an image/tests/test_task.py index 96641ed..5f4427c 100644 --- a/Comic-Con and K-means/Reading an image/tests/test_task.py +++ b/Comic-Con and K-means/Reading an image/tests/test_task.py @@ -1,22 +1,16 @@ import numpy as np import unittest -from numpy.ma.testutils import assert_array_equal +from safe_assert import safe_assert_array_equal from task import read_image - -# The test is checking read_image looking somewhat like this -# def read_image(path='superman-batman.png'): -# image = Image.open(path) -# return np.array(image).reshape(-1, 3) class TestCase(unittest.TestCase): - # TODO: this test not passing in the student mode is a bug - # def test_read_image(self): - # image = read_image("./tests/star.png") - # expected_star = np.loadtxt("./tests/star.txt") - # assert_array_equal(expected_star, image) + def test_read_image(self): + image = read_image("./tests/star.png") + expected_star = np.loadtxt("./tests/star.txt") + safe_assert_array_equal(expected_star, image, "Incorrect image data") def test_shape(self): image = read_image("./superman-batman.png") - self.assertEqual((786432, 3), image.shape) + self.assertEqual((786432, 3), image.shape, "Incorrect image shape") diff --git a/Horror Trees/Predicate/tests/test_task.py b/Horror Trees/Predicate/tests/test_task.py index 98a89b7..75cd961 100644 --- a/Horror Trees/Predicate/tests/test_task.py +++ b/Horror Trees/Predicate/tests/test_task.py @@ -2,7 +2,7 @@ import unittest from numpy import array_equal -from numpy.ma.testutils import assert_array_equal +from safe_assert import safe_assert_array_equal from divide import Predicate @@ -19,14 +19,14 @@ def test_nominal_int(self): X1, y1, X2, y2 = predicate.divide(X, y) if array_equal(np.array([[2, 2, 2], [3, 3, 3]]), X1): - assert_array_equal(np.array([2, 3]), y1, err_msg="Incorrect split for int feature") - assert_array_equal(np.array([[1, 1, 1], [1, 2, 3]]), X2, err_msg="Incorrect split for int feature") - assert_array_equal(np.array([1, 4]), y2, err_msg="Incorrect split for int feature") + safe_assert_array_equal(np.array([2, 3]), y1, err_msg="Incorrect split for int feature") + safe_assert_array_equal(np.array([[1, 1, 1], [1, 2, 3]]), X2, err_msg="Incorrect split for int feature") + safe_assert_array_equal(np.array([1, 4]), y2, err_msg="Incorrect split for int feature") else: - assert_array_equal(np.array([[1, 1, 1], [1, 2, 3]]), X1, err_msg="Incorrect split for int feature") - assert_array_equal(np.array([1, 4]), y1, err_msg="Incorrect split for int feature") - assert_array_equal(np.array([[2, 2, 2], [3, 3, 3]]), X2, err_msg="Incorrect split for int feature") - assert_array_equal(np.array([2, 3]), y2, err_msg="Incorrect split for int feature") + safe_assert_array_equal(np.array([[1, 1, 1], [1, 2, 3]]), X1, err_msg="Incorrect split for int feature") + safe_assert_array_equal(np.array([1, 4]), y1, err_msg="Incorrect split for int feature") + safe_assert_array_equal(np.array([[2, 2, 2], [3, 3, 3]]), X2, err_msg="Incorrect split for int feature") + safe_assert_array_equal(np.array([2, 3]), y2, err_msg="Incorrect split for int feature") def test_nominal_float(self): predicate = Predicate(0, 2.1) @@ -39,16 +39,16 @@ def test_nominal_float(self): X1, y1, X2, y2 = predicate.divide(X, y) if array_equal(np.array([[3, 3, 3]]), X1): - assert_array_equal(np.array([3]), y1, err_msg="Incorrect split for float feature") - assert_array_equal(np.array([[1, 1, 1], [2, 2, 2], [1, 2, 3]]), X2, + safe_assert_array_equal(np.array([3]), y1, err_msg="Incorrect split for float feature") + safe_assert_array_equal(np.array([[1, 1, 1], [2, 2, 2], [1, 2, 3]]), X2, err_msg="Incorrect split for float feature") - assert_array_equal(np.array([1, 2, 4]), y2, err_msg="Incorrect split for float feature") + safe_assert_array_equal(np.array([1, 2, 4]), y2, err_msg="Incorrect split for float feature") else: - assert_array_equal(np.array([[1, 1, 1], [2, 2, 2], [1, 2, 3]]), X1, + safe_assert_array_equal(np.array([[1, 1, 1], [2, 2, 2], [1, 2, 3]]), X1, err_msg="Incorrect split for float feature") - assert_array_equal(np.array([1, 2, 4]), y1, err_msg="Incorrect split for float feature") - assert_array_equal(np.array([[3, 3, 3]]), X2, err_msg="Incorrect split for float feature") - assert_array_equal(np.array([3]), y2, err_msg="Incorrect split for float feature") + safe_assert_array_equal(np.array([1, 2, 4]), y1, err_msg="Incorrect split for float feature") + safe_assert_array_equal(np.array([[3, 3, 3]]), X2, err_msg="Incorrect split for float feature") + safe_assert_array_equal(np.array([3]), y2, err_msg="Incorrect split for float feature") def test_quantitative(self): predicate = Predicate(3, 'clear') @@ -61,14 +61,14 @@ def test_quantitative(self): X1, y1, X2, y2 = predicate.divide(X, y) if array_equal(np.array([[1, 1, 1, 'clear'], [2, 2, 2, 'clear']]), X1): - assert_array_equal(np.array([1, 2]), y1, err_msg="Incorrect split for quantitative feature") - assert_array_equal(np.array([[3, 3, 3, 'green'], [1, 2, 3, 'black']]), X2, + safe_assert_array_equal(np.array([1, 2]), y1, err_msg="Incorrect split for quantitative feature") + safe_assert_array_equal(np.array([[3, 3, 3, 'green'], [1, 2, 3, 'black']]), X2, err_msg="Incorrect split for quantitative feature") - assert_array_equal(np.array([3, 4]), y2, err_msg="Incorrect split for quantitative feature") + safe_assert_array_equal(np.array([3, 4]), y2, err_msg="Incorrect split for quantitative feature") else: - assert_array_equal(np.array([[3, 3, 3, 'green'], [1, 2, 3, 'black']]), X1, + safe_assert_array_equal(np.array([[3, 3, 3, 'green'], [1, 2, 3, 'black']]), X1, err_msg="Incorrect split for quantitative feature") - assert_array_equal(np.array([3, 4]), y1, err_msg="Incorrect split for quantitative feature") - assert_array_equal(np.array([[1, 1, 1, 'clear'], [2, 2, 2, 'clear']]), X2, + safe_assert_array_equal(np.array([3, 4]), y1, err_msg="Incorrect split for quantitative feature") + safe_assert_array_equal(np.array([[1, 1, 1, 'clear'], [2, 2, 2, 'clear']]), X2, err_msg="Incorrect split for quantitative feature") - assert_array_equal(np.array([1, 2]), y2, err_msg="Incorrect split for quantitative feature") + safe_assert_array_equal(np.array([1, 2]), y2, err_msg="Incorrect split for quantitative feature") diff --git a/Iris Network/Train and Predict/tests/test_task.py b/Iris Network/Train and Predict/tests/test_task.py index 1183e3c..c5db517 100644 --- a/Iris Network/Train and Predict/tests/test_task.py +++ b/Iris Network/Train and Predict/tests/test_task.py @@ -1,7 +1,7 @@ import unittest import numpy as np -from numpy.ma.testutils import assert_array_equal +from safe_assert import safe_assert_array_equal from network import NN @@ -18,11 +18,11 @@ def test_predict(self): for i in range(11): if i == 10: - self.fail() + self.fail("train method failed: the network could not learn the training data after 10 attempts") try: nn.train(X_train, y_train) nn_y = nn.predict(X_train) - assert_array_equal((nn_y > 0.5).astype(int), y_train) + safe_assert_array_equal((nn_y > 0.5).astype(int), y_train, "Incorrect predictions after training") break except: continue diff --git a/Neighbors and Wine/K-nearest neighbors/tests/test_task.py b/Neighbors and Wine/K-nearest neighbors/tests/test_task.py index 9881c94..165f15d 100644 --- a/Neighbors and Wine/K-nearest neighbors/tests/test_task.py +++ b/Neighbors and Wine/K-nearest neighbors/tests/test_task.py @@ -1,7 +1,7 @@ import numpy as np import unittest -from numpy.ma.testutils import assert_array_equal +from safe_assert import safe_assert_array_equal from metric_classification import knn from distances import euclidean_dist @@ -63,7 +63,7 @@ def test_knn_1_neighbor(self): ]) y_test = np.array([4, 3, 5, 2, 1, 2, 1, 0, 1, 5, 5, 2]) y_predicted = knn(X_train, y_train, X_test, 1, euclidean_dist) - assert_array_equal(y_predicted, y_test) + safe_assert_array_equal(y_predicted, y_test, "Incorrect predictions for knn with k=1") def test_knn_4_neighbor(self): X_train = np.array([ @@ -77,19 +77,19 @@ def test_knn_4_neighbor(self): y_train = np.array([0, 1, 2, 3, 4, 5]) X_test = np.array([ - [0, 255, 0], - [255, 0, 0], - [0, 0, 255], - [255, 0, 255], - [100, 0, 50], - [100, 100, 100], - [50, 50, 50], - [200, 200, 200], - [10, 20, 30], - [100, 10, 200], - [32, 0, 255], - [128, 255, 64] + [10, 200, 30], + [240, 10, 20], + [20, 30, 240], + [200, 10, 200], + [90, 10, 60], + [120, 110, 90], + [40, 60, 70], + [210, 210, 190], + [15, 25, 35], + [110, 20, 210], + [40, 5, 240], + [140, 240, 80] ]) - y_test = np.array([0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0]) + y_test = np.array([1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0]) y_predicted = knn(X_train, y_train, X_test, 4, euclidean_dist) - assert_array_equal(y_predicted, y_test) + safe_assert_array_equal(y_predicted, y_test, "Incorrect predictions for knn with k=4") diff --git a/Neighbors and Wine/Leave-one-out/tests/test_task.py b/Neighbors and Wine/Leave-one-out/tests/test_task.py index e289635..fc7bc3b 100644 --- a/Neighbors and Wine/Leave-one-out/tests/test_task.py +++ b/Neighbors and Wine/Leave-one-out/tests/test_task.py @@ -9,20 +9,16 @@ class TestCase(unittest.TestCase): def test_loo(self): X_train = np.array([ - [255, 255, 255], - [255, 255, 255], - [255, 255, 255], - [255, 255, 255], - [255, 255, 255], - [255, 255, 255], - [255, 255, 255], - [255, 255, 255], - [255, 255, 255], - [128, 128, 128], - [128, 128, 128], - [128, 128, 128], + [0, 4], + [0, 7], + [3, 9], + [7, 2], + [4, 8], + [3, 7], + [4, 0], + [4, 4] ]) - y_train = np.array([0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1]) + y_train = np.array([0, 1, 1, 0, 0, 1, 0, 0]) euclidean_opt = loocv(X_train, y_train, euclidean_dist) self.assertEqual(3, euclidean_opt) diff --git a/Neighbors and Wine/Sample division/tests/test_task.py b/Neighbors and Wine/Sample division/tests/test_task.py index 6e5bb2b..a96f3e5 100644 --- a/Neighbors and Wine/Sample division/tests/test_task.py +++ b/Neighbors and Wine/Sample division/tests/test_task.py @@ -1,4 +1,4 @@ -from numpy.ma.testutils import assert_array_equal, fail_if_array_equal +from safe_assert import safe_assert_array_equal, safe_fail_if_array_equal from task import train_test_split import unittest @@ -23,16 +23,16 @@ def test_arrays_mapping(self): y = np.arange(10) X_train, y_train, X_test, y_test = train_test_split(X, y, ratio=.5) - assert_array_equal(X_train[:, 0], y_train * 10, "X_train doesn't match y_train values") - assert_array_equal(X_test[:, 0], y_test * 10, "X_test doesn't match y_test values") + safe_assert_array_equal(X_train[:, 0], y_train * 10, "X_train doesn't match y_train values") + safe_assert_array_equal(X_test[:, 0], y_test * 10, "X_test doesn't match y_test values") def test_arrays_lengths(self): X = np.arange(100).reshape((10, 10)) y = np.arange(10) X_train, y_train, X_test, y_test = train_test_split(X, y, ratio=.7) - assert_array_equal(X_train.shape[0], len(y_train), "X_train length doesn't match y_train length") - assert_array_equal(X_test.shape[0], len(y_test), "X_test length doesn't match y_test length") + safe_assert_array_equal(X_train.shape[0], len(y_train), "X_train length doesn't match y_train length") + safe_assert_array_equal(X_test.shape[0], len(y_test), "X_test length doesn't match y_test length") def test_ratio(self): X = np.arange(100).reshape((10, 10)) @@ -50,15 +50,17 @@ def test_randomize(self): ratio = .8 X_train, y_train, X_test, y_test = train_test_split(X, y, ratio=ratio) X_train1, y_train1, X_test1, y_test1 = train_test_split(X, y, ratio=ratio) - fail_if_array_equal(X_train, X_train1, "train_test_split should split arrays into random train and test subsets. Use numpy.random.permutation") - fail_if_array_equal(X_test, X_test1, "train_test_split should split arrays into random train and test subsets. Use numpy.random.permutation") - fail_if_array_equal(y_train, y_train1, "train_test_split should split arrays into random train and test subsets. Use numpy.random.permutation") - fail_if_array_equal(y_test, y_test1, "train_test_split should split arrays into random train and test subsets. Use numpy.random.permutation") + + safe_fail_if_array_equal(X_train, X_train1, "train_test_split should split arrays into random train and test subsets") + safe_fail_if_array_equal(X_test, X_test1, "train_test_split should split arrays into random train and test subsets") + safe_fail_if_array_equal(y_train, y_train1, "train_test_split should split arrays into random train and test subsets") + safe_fail_if_array_equal(y_test, y_test1, "train_test_split should split arrays into random train and test subsets") + def test_no_randomize_initial_arrays(self): X = np.arange(100).reshape((10, 10)) y = np.arange(10) ratio = .8 train_test_split(X, y, ratio=ratio) - assert_array_equal(X, np.arange(100).reshape((10, 10)), "Do not reorder initial X array") - assert_array_equal(y, np.arange(10), "Do not reorder initial y array") \ No newline at end of file + safe_assert_array_equal(X, np.arange(100).reshape((10, 10)), "Do not reorder initial X array") + safe_assert_array_equal(y, np.arange(10), "Do not reorder initial y array") \ No newline at end of file diff --git a/Pima Indians Diabetes and Linear Classifier/Loss function/tests/test_task.py b/Pima Indians Diabetes and Linear Classifier/Loss function/tests/test_task.py index 8eefdcf..28b4c54 100644 --- a/Pima Indians Diabetes and Linear Classifier/Loss function/tests/test_task.py +++ b/Pima Indians Diabetes and Linear Classifier/Loss function/tests/test_task.py @@ -1,7 +1,7 @@ import unittest import numpy as np -from numpy.ma.testutils import assert_array_almost_equal +from safe_assert import safe_assert_array_almost_equal from loss_functions import log_loss, sigmoid_loss @@ -23,7 +23,7 @@ def test_log_loss(self): [-0.41701172, -0.68531017], [-0.4628473 , -0.63164579], [-0.72098685, -0.38828417]]]) - assert_array_almost_equal(y_loss, y_predicted) + safe_assert_array_almost_equal(y_loss, y_predicted, err_msg="Incorrect values returned by log_loss: check the loss formula and its derivative") def test_sigmoid_loss(self): y = np.array([[0.5, 0.5], [0.1, 0.9], [0.01, 0.99], @@ -41,4 +41,4 @@ def test_sigmoid_loss(self): [-0.41100061, -0.49875208], [-0.43578999, -0.49226817], [-0.49999988, -0.39340555]]]) - assert_array_almost_equal(y_loss, y_predicted) + safe_assert_array_almost_equal(y_loss, y_predicted, err_msg="Incorrect values returned by sigmoid_loss: check the loss formula and its derivative") diff --git a/course-info.yaml b/course-info.yaml index 750eb82..6379c01 100644 --- a/course-info.yaml +++ b/course-info.yaml @@ -21,4 +21,5 @@ content: - Iris Network additional_files: - name: requirements.txt + - name: safe_assert.py yaml_version: 5 diff --git a/safe_assert.py b/safe_assert.py new file mode 100644 index 0000000..901fb7e --- /dev/null +++ b/safe_assert.py @@ -0,0 +1,28 @@ +from numpy.ma.testutils import assert_array_equal, fail_if_array_equal, assert_array_almost_equal + +def safe_assert_array_equal(x, y, err_msg=""): + try: + assert_array_equal(x, y) + except AssertionError as e: + details = str(e).strip() + if err_msg: + details = f"{err_msg}\n{details}" + raise AssertionError(details) from None + +def safe_fail_if_array_equal(x, y, err_msg=""): + try: + fail_if_array_equal(x, y, err_msg) + except AssertionError as e: + details = str(e).strip() + if err_msg and err_msg not in details: + details = f"{err_msg}\n{details}" + raise AssertionError(details) from None + +def safe_assert_array_almost_equal(x, y, decimal=6, err_msg=""): + try: + assert_array_almost_equal(x, y, decimal, err_msg) + except AssertionError as e: + details = str(e).strip() + if err_msg: + details = f"{err_msg}\n{details}" + raise AssertionError(details) from None \ No newline at end of file