From e74b1cca255068280485e881a53b9bafc653bc70 Mon Sep 17 00:00:00 2001 From: Kernc Date: Wed, 20 Jul 2016 13:18:54 +0200 Subject: [PATCH] Test reporting: auto-discover widgets to test --- Orange/canvas/report/tests/test_report.py | 100 ++++++++----------- Orange/widgets/data/oweditdomain.py | 9 +- Orange/widgets/visualize/owsilhouetteplot.py | 3 + 3 files changed, 49 insertions(+), 63 deletions(-) diff --git a/Orange/canvas/report/tests/test_report.py b/Orange/canvas/report/tests/test_report.py index c2bc143a6cb..4175a099a2c 100644 --- a/Orange/canvas/report/tests/test_report.py +++ b/Orange/canvas/report/tests/test_report.py @@ -1,3 +1,7 @@ +from importlib import import_module +import os +import warnings + from PyQt4.QtGui import QFont, QBrush from PyQt4.QtCore import Qt from Orange.data.table import Table @@ -8,43 +12,15 @@ from Orange.distance import Euclidean from Orange.canvas.report.owreport import OWReport from Orange.widgets import gui +from Orange.widgets.widget import OWWidget from Orange.widgets.tests.base import WidgetTest -from Orange.widgets.classify.owclassificationtree import OWClassificationTree from Orange.widgets.classify.owclassificationtreegraph import OWClassificationTreeGraph -from Orange.widgets.classify.owknn import OWKNNLearner -from Orange.widgets.classify.owlogisticregression import OWLogisticRegression -from Orange.widgets.classify.owmajority import OWMajority -from Orange.widgets.classify.ownaivebayes import OWNaiveBayes -from Orange.widgets.classify.owrandomforest import OWRandomForest -from Orange.widgets.classify.owsvmclassification import OWSVMClassification -from Orange.widgets.data.owconcatenate import OWConcatenate -from Orange.widgets.data.owcontinuize import OWContinuize -from Orange.widgets.data.owdatainfo import OWDataInfo -from Orange.widgets.data.owdatasampler import OWDataSampler -from Orange.widgets.data.owdiscretize import OWDiscretize -from Orange.widgets.data.owfeatureconstructor import OWFeatureConstructor from Orange.widgets.data.owfile import OWFile -from Orange.widgets.data.owimpute import OWImpute -from Orange.widgets.data.owmergedata import OWMergeData -from Orange.widgets.data.owoutliers import OWOutliers -from Orange.widgets.data.owpaintdata import OWPaintData -from Orange.widgets.data.owpurgedomain import OWPurgeDomain -from Orange.widgets.data.owrank import OWRank -from Orange.widgets.data.owselectcolumns import OWSelectAttributes -from Orange.widgets.data.owselectrows import OWSelectRows -from Orange.widgets.data.owsql import OWSql -from Orange.widgets.data.owtable import OWDataTable -from Orange.widgets.data.owcolor import OWColor -from Orange.widgets.data.owpreprocess import OWPreprocess from Orange.widgets.evaluate.owcalibrationplot import OWCalibrationPlot from Orange.widgets.evaluate.owliftcurve import OWLiftCurve from Orange.widgets.evaluate.owrocanalysis import OWROCAnalysis from Orange.widgets.evaluate.owtestlearners import OWTestLearners -from Orange.widgets.regression.owregressiontree import OWRegressionTree from Orange.widgets.regression.owregressiontreegraph import OWRegressionTreeGraph -from Orange.widgets.regression.owknnregression import OWKNNRegression -from Orange.widgets.regression.owmean import OWMean -from Orange.widgets.regression.owsvmregression import OWSVMRegression from Orange.widgets.unsupervised.owcorrespondence import OWCorrespondenceAnalysis from Orange.widgets.unsupervised.owdistancemap import OWDistanceMap from Orange.widgets.unsupervised.owdistances import OWDistances @@ -53,15 +29,35 @@ from Orange.widgets.unsupervised.owmds import OWMDS from Orange.widgets.unsupervised.owpca import OWPCA from Orange.widgets.utils.itemmodels import PyTableModel -from Orange.widgets.visualize.owboxplot import OWBoxPlot -from Orange.widgets.visualize.owdistributions import OWDistributions -from Orange.widgets.visualize.owheatmap import OWHeatMap -from Orange.widgets.visualize.owlinearprojection import OWLinearProjection -from Orange.widgets.visualize.owmosaic import OWMosaicDisplay -from Orange.widgets.visualize.owscattermap import OWScatterMap -from Orange.widgets.visualize.owscatterplot import OWScatterPlot -from Orange.widgets.visualize.owsieve import OWSieveDiagram -from Orange.widgets.visualize.owvenndiagram import OWVennDiagram + + +def get_owwidgets(top_module_name): + top_module = import_module(top_module_name) + widgets = [] + for root, dirs, files in os.walk(top_module.__path__[0]): + root = root[len(top_module.__path__[0]):].lstrip(os.path.sep) + for file in files: + if file.lower().startswith('ow') and file.lower().endswith('.py'): + module_name = top_module_name + '.' + os.path.join(root, file).replace(os.path.sep, '.')[:-len('.py')] + try: + module = import_module(module_name, top_module_name[:top_module_name.index('.')]) + except ImportError: + warnings.warn('Failed to import module: ' + module_name) + continue + for name, value in module.__dict__.items(): + if (name.upper().startswith('OW') and + isinstance(value, type) and + issubclass(value, OWWidget) and + getattr(value, 'name', None) and + getattr(value, 'send_report', None)): + widgets.append(value) + return list(set(widgets)) + + +DATA_WIDGETS = get_owwidgets('Orange.widgets.data') +VISUALIZATION_WIDGETS = get_owwidgets('Orange.widgets.visualize') +CLASSIFICATION_WIDGETS = get_owwidgets('Orange.widgets.classify') +REGRESSION_WIDGETS = get_owwidgets('Orange.widgets.regression') class TestReport(WidgetTest): @@ -119,32 +115,24 @@ def test_report_table(self): class TestReportWidgets(WidgetTest): - clas_widgets = [OWClassificationTree, OWKNNLearner, OWLogisticRegression, - OWMajority, OWNaiveBayes, OWRandomForest, - OWSVMClassification] - data_widgets = [OWConcatenate, OWContinuize, OWDataInfo, OWDataSampler, - OWDiscretize, OWFeatureConstructor, OWOutliers, OWImpute, - OWMergeData, OWFile, OWPaintData, OWPurgeDomain, OWRank, - OWSelectAttributes, OWSelectRows, OWSql, OWDataTable, - OWColor, OWPreprocess] + clas_widgets = CLASSIFICATION_WIDGETS + data_widgets = DATA_WIDGETS eval_widgets = [OWCalibrationPlot, OWLiftCurve, OWROCAnalysis] - regr_widgets = [OWRegressionTree, OWKNNRegression, OWMean, OWSVMRegression] + regr_widgets = REGRESSION_WIDGETS unsu_widgets = [OWCorrespondenceAnalysis, OWDistances, OWKMeans, OWMDS, OWPCA] dist_widgets = [OWDistanceMap, OWHierarchicalClustering] - visu_widgets = [OWBoxPlot, OWDistributions, OWHeatMap, OWLinearProjection, - OWMosaicDisplay, OWScatterPlot, - OWSieveDiagram, OWScatterMap, OWVennDiagram] + visu_widgets = VISUALIZATION_WIDGETS spec_widgets = [OWClassificationTreeGraph, OWTestLearners, OWRegressionTreeGraph] def _create_report(self, widgets, rep, data): for widget in widgets: w = self.create_widget(widget) - if w.inputs and data is not None: + if w.inputs and isinstance(data, w.inputs[0].type): handler = getattr(w, w.inputs[0].handler) handler(data) - w.create_report_html() + w.create_report_html() rep.make_report(w) # rep.show() @@ -160,14 +148,12 @@ def test_report_widgets_classify(self): w.create_report_html() rep.make_report(w) - self.assertEqual(len(widgets) + 1, 8) self._create_report(widgets, rep, data) def test_report_widgets_data(self): rep = OWReport.get_instance() data = Table("zoo") widgets = self.data_widgets - self.assertEqual(len(widgets), 19) self._create_report(widgets, rep, data) def test_report_widgets_evaluate(self): @@ -189,7 +175,6 @@ def test_report_widgets_evaluate(self): w.create_report_html() rep.make_report(w) - self.assertEqual(len(widgets) + 1, 4) self._create_report(widgets, rep, results) def test_report_widgets_regression(self): @@ -204,14 +189,12 @@ def test_report_widgets_regression(self): w.create_report_html() rep.make_report(w) - self.assertEqual(len(widgets) + 1, 5) self._create_report(widgets, rep, data) def test_report_widgets_unsupervised(self): rep = OWReport.get_instance() data = Table("zoo") widgets = self.unsu_widgets - self.assertEqual(len(widgets), 5) self._create_report(widgets, rep, data) def test_report_widgets_unsupervised_dist(self): @@ -219,14 +202,12 @@ def test_report_widgets_unsupervised_dist(self): data = Table("zoo") dist = Euclidean(data) widgets = self.dist_widgets - self.assertEqual(len(widgets), 2) self._create_report(widgets, rep, dist) def test_report_widgets_visualize(self): rep = OWReport.get_instance() data = Table("zoo") widgets = self.visu_widgets - self.assertEqual(len(widgets), 9) self._create_report(widgets, rep, data) def test_report_widgets_all(self): @@ -234,5 +215,4 @@ def test_report_widgets_all(self): widgets = self.clas_widgets + self.data_widgets + self.eval_widgets + \ self.regr_widgets + self.unsu_widgets + self.dist_widgets + \ self.visu_widgets + self.spec_widgets - self.assertEqual(len(widgets), 52) self._create_report(widgets, rep, None) diff --git a/Orange/widgets/data/oweditdomain.py b/Orange/widgets/data/oweditdomain.py index fa85ca41dc9..03fcf4b24f0 100644 --- a/Orange/widgets/data/oweditdomain.py +++ b/Orange/widgets/data/oweditdomain.py @@ -543,9 +543,12 @@ def sizeHint(self): return sh.expandedTo(QSize(660, 550)) def send_report(self): - self.report_raw("", EditDomainReport( - old_domain=chain(self.data.domain.variables, self.data.domain.metas), - new_domain=self.domain_model).to_html()) + if self.data is not None: + self.report_raw("", EditDomainReport( + old_domain=chain(self.data.domain.variables, self.data.domain.metas), + new_domain=self.domain_model).to_html()) + else: + self.report_data(None) class EditDomainReport: diff --git a/Orange/widgets/visualize/owsilhouetteplot.py b/Orange/widgets/visualize/owsilhouetteplot.py index 5850e4164a5..37c50719259 100644 --- a/Orange/widgets/visualize/owsilhouetteplot.py +++ b/Orange/widgets/visualize/owsilhouetteplot.py @@ -335,6 +335,9 @@ def commit(self): self.send("Other Data", other) def send_report(self): + if not len(self.cluster_var_model): + return + self.report_plot() caption = "Silhouette plot ({} distance), clustered by '{}'".format( self.Distances[self.distance_idx][0],