Skip to content

Commit a21a587

Browse files
committed
Test reporting: auto-discover widgets to test
1 parent e3fd568 commit a21a587

File tree

3 files changed

+49
-63
lines changed

3 files changed

+49
-63
lines changed

Orange/canvas/report/tests/test_report.py

Lines changed: 40 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
from importlib import import_module
2+
import os
3+
import warnings
4+
15
from PyQt4.QtGui import QFont, QBrush
26
from PyQt4.QtCore import Qt
37
from Orange.data.table import Table
@@ -8,43 +12,15 @@
812
from Orange.distance import Euclidean
913
from Orange.canvas.report.owreport import OWReport
1014
from Orange.widgets import gui
15+
from Orange.widgets.widget import OWWidget
1116
from Orange.widgets.tests.base import WidgetTest
12-
from Orange.widgets.classify.owclassificationtree import OWClassificationTree
1317
from Orange.widgets.classify.owclassificationtreegraph import OWClassificationTreeGraph
14-
from Orange.widgets.classify.owknn import OWKNNLearner
15-
from Orange.widgets.classify.owlogisticregression import OWLogisticRegression
16-
from Orange.widgets.classify.owmajority import OWMajority
17-
from Orange.widgets.classify.ownaivebayes import OWNaiveBayes
18-
from Orange.widgets.classify.owrandomforest import OWRandomForest
19-
from Orange.widgets.classify.owsvmclassification import OWSVMClassification
20-
from Orange.widgets.data.owconcatenate import OWConcatenate
21-
from Orange.widgets.data.owcontinuize import OWContinuize
22-
from Orange.widgets.data.owdatainfo import OWDataInfo
23-
from Orange.widgets.data.owdatasampler import OWDataSampler
24-
from Orange.widgets.data.owdiscretize import OWDiscretize
25-
from Orange.widgets.data.owfeatureconstructor import OWFeatureConstructor
2618
from Orange.widgets.data.owfile import OWFile
27-
from Orange.widgets.data.owimpute import OWImpute
28-
from Orange.widgets.data.owmergedata import OWMergeData
29-
from Orange.widgets.data.owoutliers import OWOutliers
30-
from Orange.widgets.data.owpaintdata import OWPaintData
31-
from Orange.widgets.data.owpurgedomain import OWPurgeDomain
32-
from Orange.widgets.data.owrank import OWRank
33-
from Orange.widgets.data.owselectcolumns import OWSelectAttributes
34-
from Orange.widgets.data.owselectrows import OWSelectRows
35-
from Orange.widgets.data.owsql import OWSql
36-
from Orange.widgets.data.owtable import OWDataTable
37-
from Orange.widgets.data.owcolor import OWColor
38-
from Orange.widgets.data.owpreprocess import OWPreprocess
3919
from Orange.widgets.evaluate.owcalibrationplot import OWCalibrationPlot
4020
from Orange.widgets.evaluate.owliftcurve import OWLiftCurve
4121
from Orange.widgets.evaluate.owrocanalysis import OWROCAnalysis
4222
from Orange.widgets.evaluate.owtestlearners import OWTestLearners
43-
from Orange.widgets.regression.owregressiontree import OWRegressionTree
4423
from Orange.widgets.regression.owregressiontreegraph import OWRegressionTreeGraph
45-
from Orange.widgets.regression.owknnregression import OWKNNRegression
46-
from Orange.widgets.regression.owmean import OWMean
47-
from Orange.widgets.regression.owsvmregression import OWSVMRegression
4824
from Orange.widgets.unsupervised.owcorrespondence import OWCorrespondenceAnalysis
4925
from Orange.widgets.unsupervised.owdistancemap import OWDistanceMap
5026
from Orange.widgets.unsupervised.owdistances import OWDistances
@@ -53,15 +29,35 @@
5329
from Orange.widgets.unsupervised.owmds import OWMDS
5430
from Orange.widgets.unsupervised.owpca import OWPCA
5531
from Orange.widgets.utils.itemmodels import PyTableModel
56-
from Orange.widgets.visualize.owboxplot import OWBoxPlot
57-
from Orange.widgets.visualize.owdistributions import OWDistributions
58-
from Orange.widgets.visualize.owheatmap import OWHeatMap
59-
from Orange.widgets.visualize.owlinearprojection import OWLinearProjection
60-
from Orange.widgets.visualize.owmosaic import OWMosaicDisplay
61-
from Orange.widgets.visualize.owscattermap import OWScatterMap
62-
from Orange.widgets.visualize.owscatterplot import OWScatterPlot
63-
from Orange.widgets.visualize.owsieve import OWSieveDiagram
64-
from Orange.widgets.visualize.owvenndiagram import OWVennDiagram
32+
33+
34+
def get_owwidgets(top_module_name):
35+
top_module = import_module(top_module_name)
36+
widgets = []
37+
for root, dirs, files in os.walk(top_module.__path__[0]):
38+
root = root[len(top_module.__path__[0]):].lstrip(os.path.sep)
39+
for file in files:
40+
if file.lower().startswith('ow') and file.lower().endswith('.py'):
41+
module_name = top_module_name + '.' + os.path.join(root, file).replace(os.path.sep, '.')[:-len('.py')]
42+
try:
43+
module = import_module(module_name, top_module_name[:top_module_name.index('.')])
44+
except ImportError:
45+
warnings.warn('Failed to import module: ' + module_name)
46+
continue
47+
for name, value in module.__dict__.items():
48+
if (name.upper().startswith('OW') and
49+
isinstance(value, type) and
50+
issubclass(value, OWWidget) and
51+
getattr(value, 'name', None) and
52+
getattr(value, 'send_report', None)):
53+
widgets.append(value)
54+
return list(set(widgets))
55+
56+
57+
DATA_WIDGETS = get_owwidgets('Orange.widgets.data')
58+
VISUALIZATION_WIDGETS = get_owwidgets('Orange.widgets.visualize')
59+
CLASSIFICATION_WIDGETS = get_owwidgets('Orange.widgets.classify')
60+
REGRESSION_WIDGETS = get_owwidgets('Orange.widgets.regression')
6561

6662

6763
class TestReport(WidgetTest):
@@ -119,32 +115,24 @@ def test_report_table(self):
119115

120116

121117
class TestReportWidgets(WidgetTest):
122-
clas_widgets = [OWClassificationTree, OWKNNLearner, OWLogisticRegression,
123-
OWMajority, OWNaiveBayes, OWRandomForest,
124-
OWSVMClassification]
125-
data_widgets = [OWConcatenate, OWContinuize, OWDataInfo, OWDataSampler,
126-
OWDiscretize, OWFeatureConstructor, OWOutliers, OWImpute,
127-
OWMergeData, OWFile, OWPaintData, OWPurgeDomain, OWRank,
128-
OWSelectAttributes, OWSelectRows, OWSql, OWDataTable,
129-
OWColor, OWPreprocess]
118+
clas_widgets = CLASSIFICATION_WIDGETS
119+
data_widgets = DATA_WIDGETS
130120
eval_widgets = [OWCalibrationPlot, OWLiftCurve, OWROCAnalysis]
131-
regr_widgets = [OWRegressionTree, OWKNNRegression, OWMean, OWSVMRegression]
121+
regr_widgets = REGRESSION_WIDGETS
132122
unsu_widgets = [OWCorrespondenceAnalysis, OWDistances, OWKMeans,
133123
OWMDS, OWPCA]
134124
dist_widgets = [OWDistanceMap, OWHierarchicalClustering]
135-
visu_widgets = [OWBoxPlot, OWDistributions, OWHeatMap, OWLinearProjection,
136-
OWMosaicDisplay, OWScatterPlot,
137-
OWSieveDiagram, OWScatterMap, OWVennDiagram]
125+
visu_widgets = VISUALIZATION_WIDGETS
138126
spec_widgets = [OWClassificationTreeGraph, OWTestLearners,
139127
OWRegressionTreeGraph]
140128

141129
def _create_report(self, widgets, rep, data):
142130
for widget in widgets:
143131
w = self.create_widget(widget)
144-
if w.inputs and data is not None:
132+
if w.inputs and isinstance(data, w.inputs[0].type):
145133
handler = getattr(w, w.inputs[0].handler)
146134
handler(data)
147-
w.create_report_html()
135+
w.create_report_html()
148136
rep.make_report(w)
149137
# rep.show()
150138

@@ -160,14 +148,12 @@ def test_report_widgets_classify(self):
160148
w.create_report_html()
161149
rep.make_report(w)
162150

163-
self.assertEqual(len(widgets) + 1, 8)
164151
self._create_report(widgets, rep, data)
165152

166153
def test_report_widgets_data(self):
167154
rep = OWReport.get_instance()
168155
data = Table("zoo")
169156
widgets = self.data_widgets
170-
self.assertEqual(len(widgets), 19)
171157
self._create_report(widgets, rep, data)
172158

173159
def test_report_widgets_evaluate(self):
@@ -189,7 +175,6 @@ def test_report_widgets_evaluate(self):
189175
w.create_report_html()
190176
rep.make_report(w)
191177

192-
self.assertEqual(len(widgets) + 1, 4)
193178
self._create_report(widgets, rep, results)
194179

195180
def test_report_widgets_regression(self):
@@ -204,35 +189,30 @@ def test_report_widgets_regression(self):
204189
w.create_report_html()
205190
rep.make_report(w)
206191

207-
self.assertEqual(len(widgets) + 1, 5)
208192
self._create_report(widgets, rep, data)
209193

210194
def test_report_widgets_unsupervised(self):
211195
rep = OWReport.get_instance()
212196
data = Table("zoo")
213197
widgets = self.unsu_widgets
214-
self.assertEqual(len(widgets), 5)
215198
self._create_report(widgets, rep, data)
216199

217200
def test_report_widgets_unsupervised_dist(self):
218201
rep = OWReport.get_instance()
219202
data = Table("zoo")
220203
dist = Euclidean(data)
221204
widgets = self.dist_widgets
222-
self.assertEqual(len(widgets), 2)
223205
self._create_report(widgets, rep, dist)
224206

225207
def test_report_widgets_visualize(self):
226208
rep = OWReport.get_instance()
227209
data = Table("zoo")
228210
widgets = self.visu_widgets
229-
self.assertEqual(len(widgets), 9)
230211
self._create_report(widgets, rep, data)
231212

232213
def test_report_widgets_all(self):
233214
rep = OWReport.get_instance()
234215
widgets = self.clas_widgets + self.data_widgets + self.eval_widgets + \
235216
self.regr_widgets + self.unsu_widgets + self.dist_widgets + \
236217
self.visu_widgets + self.spec_widgets
237-
self.assertEqual(len(widgets), 52)
238218
self._create_report(widgets, rep, None)

Orange/widgets/data/oweditdomain.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -543,9 +543,12 @@ def sizeHint(self):
543543
return sh.expandedTo(QSize(660, 550))
544544

545545
def send_report(self):
546-
self.report_raw("", EditDomainReport(
547-
old_domain=chain(self.data.domain.variables, self.data.domain.metas),
548-
new_domain=self.domain_model).to_html())
546+
if self.data is not None:
547+
self.report_raw("", EditDomainReport(
548+
old_domain=chain(self.data.domain.variables, self.data.domain.metas),
549+
new_domain=self.domain_model).to_html())
550+
else:
551+
self.report_data(None)
549552

550553

551554
class EditDomainReport:

Orange/widgets/visualize/owsilhouetteplot.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,9 @@ def commit(self):
335335
self.send("Other Data", other)
336336

337337
def send_report(self):
338+
if not len(self.cluster_var_model):
339+
return
340+
338341
self.report_plot()
339342
caption = "Silhouette plot ({} distance), clustered by '{}'".format(
340343
self.Distances[self.distance_idx][0],

0 commit comments

Comments
 (0)