Repository: biolab/orange3

Issue:
Rank crashes when getting data without target
**Describe the bug**

When Rank widget get data without a target and random forest learner (maybe the same bug happen with other learners), it crashes.

**To Reproduce**
Steps to reproduce the behavior:
1. Open data without target
2. Connect to the Rank widget
3. Connect the Random forest to Rank
4. Observe the crash

**Orange version:**
3.24.1


**Additional context**

Traceback (most recent call last):
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/orangecanvas/scheme/signalmanager.py", line 936, in __process_next
    if self.__process_next_helper(use_max_active=True):
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/orangecanvas/scheme/signalmanager.py", line 974, in __process_next_helper
    self.process_node(selected_node)
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/orangecanvas/scheme/signalmanager.py", line 605, in process_node
    self.send_to_node(node, signals_in)
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/orangewidget/workflow/widgetsscheme.py", line 792, in send_to_node
    self.process_signals_for_widget(node, widget, signals)
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/orangewidget/workflow/widgetsscheme.py", line 833, in process_signals_for_widget
    widget.handleNewSignals()
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/Orange/widgets/data/owrank.py", line 355, in handleNewSignals
    self.updateScores()
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/Orange/widgets/data/owrank.py", line 435, in updateScores
    for scorer in scorers))
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/Orange/widgets/data/owrank.py", line 435, in <genexpr>
    for scorer in scorers))
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/Orange/misc/cache.py", line 50, in _wrapped_func
    return _cached_method(weakref.ref(self), *args, **kwargs)
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/Orange/misc/cache.py", line 46, in _cached_method
    return func(self_weak(), *args, **kwargs)
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/Orange/widgets/data/owrank.py", line 397, in get_scorer_scores
    scores = scorer.scorer.score_data(self.data).T
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/Orange/preprocess/score.py", line 182, in score_data
    scores, model_attributes = self.score(data)
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/Orange/modelling/randomforest.py", line 16, in score
    model = self.get_learner(data)(data)
  File "/Applications/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/Orange/modelling/base.py", line 75, in get_learner
    raise TypeError("No learner to handle '{}'".format(problem_type))
TypeError: No learner to handle 'None'


Discussion:

Resolving patch:
diff --git a/Orange/widgets/data/owrank.py b/Orange/widgets/data/owrank.py
--- a/Orange/widgets/data/owrank.py
+++ b/Orange/widgets/data/owrank.py
@@ -395,7 +395,7 @@ def get_method_scores(self, method):
     def get_scorer_scores(self, scorer):
         try:
             scores = scorer.scorer.score_data(self.data).T
-        except ValueError:
+        except (ValueError, TypeError):
             log.error("%s doesn't work on this data", scorer.name)
             scores = np.full((len(self.data.domain.attributes), 1), np.nan)
 


Test patch:
diff --git a/Orange/widgets/data/tests/test_owrank.py b/Orange/widgets/data/tests/test_owrank.py
--- a/Orange/widgets/data/tests/test_owrank.py
+++ b/Orange/widgets/data/tests/test_owrank.py
@@ -247,6 +247,24 @@ def test_scores_updates_no_class(self):
         self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,
                          (len(self.iris.domain.variables), 8))
 
+    def test_no_class_data_learner_class_reg(self):
+        """
+        Check workflow with learners that can be both classifier
+        or regressor and data have no class variable. This test should not
+        fail.
+        """
+        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)
+        random_forest = RandomForestLearner()
+        self.assertIsNone(data.domain.class_var)
+        self.send_signal(self.widget.Inputs.data, data)
+
+        with patch("Orange.widgets.data.owrank.log.error") as log:
+            self.send_signal(self.widget.Inputs.scorer, random_forest, 1)
+            log.assert_called()
+
+        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,
+                         (len(self.iris.domain.variables), 1))
+
     def test_scores_sorting(self):
         """Check clicking on header column orders scores in a different way"""
         self.send_signal(self.widget.Inputs.data, self.iris)