From 8a077a1fedfa0a9662777484cde226276a505d38 Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Fri, 26 Mar 2021 10:42:07 +0100 Subject: [PATCH 1/2] Add github action that will run unit tests everyday, closes #42 --- .github/workflows/cronjob_unit_tests.yml | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/cronjob_unit_tests.yml diff --git a/.github/workflows/cronjob_unit_tests.yml b/.github/workflows/cronjob_unit_tests.yml new file mode 100644 index 00000000..91a1facd --- /dev/null +++ b/.github/workflows/cronjob_unit_tests.yml @@ -0,0 +1,44 @@ +name: Cron Test Dependencies + +# Controls when the action will run. +# Everyday at 4:05 +# See https://crontab.guru/#5_4_*_*_* +on: + schedule: + - cron: "5 4 * * *" + +jobs: + run: + name: Run unit tests + runs-on: ${{ matrix.os }} + strategy: + matrix: + build: [macos, ubuntu, windows] + include: + - build: macos + os: macos-latest + SKIP_LIGHTGBM: True + - build: ubuntu + os: ubuntu-latest + SKIP_LIGHTGBM: False + - build: windows + os: windows-latest + SKIP_LIGHTGBM: False + python-version: [3.6, 3.7, 3.8] + steps: + - uses: actions/checkout@master + - name: Setup Python + uses: actions/setup-python@master + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + env: + SKIP_LIGHTGBM: ${{ matrix.SKIP_LIGHTGBM }} + run: | + pip3 install --upgrade setuptools pip + pip3 install ".[all]" + - name: Run unit tests + env: + SKIP_LIGHTGBM: ${{ matrix.SKIP_LIGHTGBM }} + run: | + pytest From e526bcc2e024f4efe3c321334c22f55c3148b4ce Mon Sep 17 00:00:00 2001 From: mgarbacz Date: Fri, 26 Mar 2021 11:55:51 +0100 Subject: [PATCH 2/2] Fix failing tests --- tests/interpret/test_model_interpret.py | 55 ++++++++----------- tests/interpret/test_shap_dependence.py | 6 +- .../test_metric_volatility.py | 6 +- 3 files changed, 28 insertions(+), 39 deletions(-) diff --git a/tests/interpret/test_model_interpret.py b/tests/interpret/test_model_interpret.py index ca1efbde..db0b4be0 100644 --- a/tests/interpret/test_model_interpret.py +++ b/tests/interpret/test_model_interpret.py @@ -4,7 +4,6 @@ import numpy as np import pandas as pd from probatus.interpret import ShapModelInterpreter -from unittest.mock import patch import os @@ -116,16 +115,14 @@ def test_shap_interpret(fitted_tree, X_train, y_train, X_test, y_test, expected_ assert test_auc == pytest.approx(0.833, 0.01) # Check if plots work for such dataset - with patch("matplotlib.pyplot.figure") as _: - with patch("shap.plots._waterfall.waterfall_legacy"): - ax1 = shap_interpret.plot("importance", target_set="test", show=False) - ax2 = shap_interpret.plot("summary", target_set="test", show=False) - ax3 = shap_interpret.plot("dependence", target_columns="col_3", target_set="test", show=False) - ax4 = shap_interpret.plot("sample", samples_index=X_test.index.tolist()[0:2], target_set="test", show=False) - ax5 = shap_interpret.plot("importance", target_set="train") - ax6 = shap_interpret.plot("summary", target_set="train") - ax7 = shap_interpret.plot("dependence", target_columns="col_3", target_set="train") - ax8 = shap_interpret.plot("sample", samples_index=X_train.index.tolist()[0:2], target_set="train") + ax1 = shap_interpret.plot("importance", target_set="test", show=False) + ax2 = shap_interpret.plot("summary", target_set="test", show=False) + ax3 = shap_interpret.plot("dependence", target_columns="col_3", target_set="test", show=False) + ax4 = shap_interpret.plot("sample", samples_index=X_test.index.tolist()[0:2], target_set="test", show=False) + ax5 = shap_interpret.plot("importance", target_set="train", show=False) + ax6 = shap_interpret.plot("summary", target_set="train", show=False) + ax7 = shap_interpret.plot("dependence", target_columns="col_3", target_set="train", show=False) + ax8 = shap_interpret.plot("sample", samples_index=X_train.index.tolist()[0:2], target_set="train", show=False) assert not (isinstance(ax1, list)) assert not (isinstance(ax2, list)) assert isinstance(ax3, list) and len(ax4) == 2 @@ -167,16 +164,14 @@ def test_shap_interpret_lin_models( assert test_auc == pytest.approx(0.833, 0.01) # Check if plots work for such dataset - with patch("matplotlib.pyplot.figure") as _: - with patch("shap.plots._waterfall.waterfall_legacy"): - ax1 = shap_interpret.plot("importance", target_set="test", show=False) - ax2 = shap_interpret.plot("summary", target_set="test", show=False) - ax3 = shap_interpret.plot("dependence", target_columns="col_3", target_set="test", show=False) - ax4 = shap_interpret.plot("sample", samples_index=X_test.index.tolist()[0:2], target_set="test", show=False) - ax5 = shap_interpret.plot("importance", target_set="train") - ax6 = shap_interpret.plot("summary", target_set="train") - ax7 = shap_interpret.plot("dependence", target_columns="col_3", target_set="train") - ax8 = shap_interpret.plot("sample", samples_index=X_train.index.tolist()[0:2], target_set="train") + ax1 = shap_interpret.plot("importance", target_set="test", show=False) + ax2 = shap_interpret.plot("summary", target_set="test", show=False) + ax3 = shap_interpret.plot("dependence", target_columns="col_3", target_set="test", show=False) + ax4 = shap_interpret.plot("sample", samples_index=X_test.index.tolist()[0:2], target_set="test", show=False) + ax5 = shap_interpret.plot("importance", target_set="train", show=False) + ax6 = shap_interpret.plot("summary", target_set="train", show=False) + ax7 = shap_interpret.plot("dependence", target_columns="col_3", target_set="train", show=False) + ax8 = shap_interpret.plot("sample", samples_index=X_train.index.tolist()[0:2], target_set="train", show=False) assert not (isinstance(ax1, list)) assert not (isinstance(ax2, list)) assert isinstance(ax3, list) and len(ax4) == 2 @@ -263,16 +258,14 @@ def test_shap_interpret_complex_data(complex_data_split, complex_fitted_lightgbm assert importance_df.shape[0] == X_train.shape[1] # Check if plots work for such dataset - with patch("matplotlib.pyplot.figure") as _: - with patch("shap.plots._waterfall.waterfall_legacy"): - ax1 = shap_interpret.plot("importance", target_set="test") - ax2 = shap_interpret.plot("summary", target_set="test") - ax3 = shap_interpret.plot("dependence", target_columns="f2_missing", target_set="test") - ax4 = shap_interpret.plot("sample", samples_index=X_test.index.tolist()[0:2], target_set="test") - ax5 = shap_interpret.plot("importance", target_set="train") - ax6 = shap_interpret.plot("summary", target_set="train") - ax7 = shap_interpret.plot("dependence", target_columns="f2_missing", target_set="train") - ax8 = shap_interpret.plot("sample", samples_index=X_train.index.tolist()[0:2], target_set="train") + ax1 = shap_interpret.plot("importance", target_set="test", show=False) + ax2 = shap_interpret.plot("summary", target_set="test", show=False) + ax3 = shap_interpret.plot("dependence", target_columns="f2_missing", target_set="test", show=False) + ax4 = shap_interpret.plot("sample", samples_index=X_test.index.tolist()[0:2], target_set="test", show=False) + ax5 = shap_interpret.plot("importance", target_set="train", show=False) + ax6 = shap_interpret.plot("summary", target_set="train", show=False) + ax7 = shap_interpret.plot("dependence", target_columns="f2_missing", target_set="train", show=False) + ax8 = shap_interpret.plot("sample", samples_index=X_train.index.tolist()[0:2], target_set="train", show=False) assert not (isinstance(ax1, list)) assert not (isinstance(ax2, list)) assert isinstance(ax3, list) and len(ax4) == 2 diff --git a/tests/interpret/test_shap_dependence.py b/tests/interpret/test_shap_dependence.py index 5a681243..2385526c 100644 --- a/tests/interpret/test_shap_dependence.py +++ b/tests/interpret/test_shap_dependence.py @@ -3,7 +3,6 @@ import numpy as np import pandas as pd from sklearn.ensemble import RandomForestClassifier -from unittest.mock import patch from probatus.interpret.shap_dependence import DependencePlotter from probatus.utils.exceptions import NotFittedError import os @@ -121,9 +120,8 @@ def test_fit_complex(complex_data_split, complex_fitted_lightgbm): assert plotter.fitted is True # Check if plotting doesnt cause errors - with patch("matplotlib.pyplot.figure") as _: - for binning in ["simple", "agglomerative", "quantile"]: - _ = plotter.plot(feature="f2_missing", type_binning=binning) + for binning in ["simple", "agglomerative", "quantile"]: + _ = plotter.plot(feature="f2_missing", type_binning=binning, show=False) def test_get_X_y_shap_with_q_cut_normal(X_y, clf): diff --git a/tests/metric_volatility/test_metric_volatility.py b/tests/metric_volatility/test_metric_volatility.py index 3460a5e9..d481d0cf 100644 --- a/tests/metric_volatility/test_metric_volatility.py +++ b/tests/metric_volatility/test_metric_volatility.py @@ -397,8 +397,7 @@ def test_fit_compute_full_process(X_df, y_series): assert report.shape == (2, 6) # Check if plot runs - with patch("matplotlib.pyplot.figure") as _: - vol.plot() + vol.plot(show=False) @pytest.mark.skipif(os.environ.get("SKIP_LIGHTGBM") == "true", reason="LightGBM tests disabled") @@ -420,5 +419,4 @@ def test_fit_compute_complex(complex_data, complex_lightgbm): assert report.shape == (1, 6) # Check if plot runs - with patch("matplotlib.pyplot.figure") as _: - vol.plot(show=False) + vol.plot(show=False)