{
    "file_diffs": [
        {
            "old_file_content": "\"\"\"\nRank\n====\n\nRank (score) features for prediction.\n\n\"\"\"\nimport warnings\nfrom collections import namedtuple, OrderedDict\nimport logging\nfrom functools import partial\nfrom itertools import chain\n\nimport numpy as np\nfrom scipy.sparse import issparse\n\nfrom AnyQt.QtGui import QFontMetrics\nfrom AnyQt.QtWidgets import (\n    QTableView, QRadioButton, QButtonGroup, QGridLayout,\n    QStackedWidget, QHeaderView, QCheckBox, QItemDelegate,\n)\nfrom AnyQt.QtCore import (\n    Qt, QItemSelection, QItemSelectionRange, QItemSelectionModel,\n)\n\nfrom Orange.data import (Table, Domain, ContinuousVariable, DiscreteVariable,\n                         StringVariable)\nfrom Orange.misc.cache import memoize_method\nfrom Orange.preprocess import score\nfrom Orange.widgets import report\nfrom Orange.widgets import gui\nfrom Orange.widgets.settings import (DomainContextHandler, Setting,\n                                     ContextSetting)\nfrom Orange.widgets.utils.itemmodels import PyTableModel\nfrom Orange.widgets.utils.sql import check_sql_input\nfrom Orange.widgets.utils.widgetpreview import WidgetPreview\nfrom Orange.widgets.widget import (\n    OWWidget, Msg, Input, Output, AttributeList\n)\n\n\nlog = logging.getLogger(__name__)\n\n\nclass ProblemType:\n    CLASSIFICATION, REGRESSION, UNSUPERVISED = range(3)\n\n    @classmethod\n    def from_variable(cls, variable):\n        return (cls.CLASSIFICATION if isinstance(variable, DiscreteVariable) else\n                cls.REGRESSION if isinstance(variable, ContinuousVariable) else\n                cls.UNSUPERVISED)\n\nScoreMeta = namedtuple(\"score_meta\", [\"name\", \"shortname\", \"scorer\", 'problem_type', 'is_default'])\n\n# Default scores.\nCLS_SCORES = [\n    ScoreMeta(\"Information Gain\", \"Info. gain\",\n              score.InfoGain, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"Information Gain Ratio\", \"Gain ratio\",\n              score.GainRatio, ProblemType.CLASSIFICATION, True),\n    ScoreMeta(\"Gini Decrease\", \"Gini\",\n              score.Gini, ProblemType.CLASSIFICATION, True),\n    ScoreMeta(\"ANOVA\", \"ANOVA\",\n              score.ANOVA, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"χ²\", \"χ²\",\n              score.Chi2, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"ReliefF\", \"ReliefF\",\n              score.ReliefF, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"FCBF\", \"FCBF\",\n              score.FCBF, ProblemType.CLASSIFICATION, False)\n]\nREG_SCORES = [\n    ScoreMeta(\"Univariate Regression\", \"Univar. reg.\",\n              score.UnivariateLinearRegression, ProblemType.REGRESSION, True),\n    ScoreMeta(\"RReliefF\", \"RReliefF\",\n              score.RReliefF, ProblemType.REGRESSION, True)\n]\nSCORES = CLS_SCORES + REG_SCORES\n\n\nclass TableView(QTableView):\n    def __init__(self, parent=None, **kwargs):\n        super().__init__(parent=parent,\n                         selectionBehavior=QTableView.SelectRows,\n                         selectionMode=QTableView.ExtendedSelection,\n                         sortingEnabled=True,\n                         showGrid=True,\n                         cornerButtonEnabled=False,\n                         alternatingRowColors=False,\n                         **kwargs)\n        self.setItemDelegate(gui.ColoredBarItemDelegate(self))\n        self.setItemDelegateForColumn(0, QItemDelegate())\n\n        header = self.verticalHeader()\n        header.setSectionResizeMode(header.Fixed)\n        header.setFixedWidth(50)\n        header.setDefaultSectionSize(22)\n        header.setTextElideMode(Qt.ElideMiddle)  # Note: https://bugreports.qt.io/browse/QTBUG-62091\n\n        header = self.horizontalHeader()\n        header.setSectionResizeMode(header.Fixed)\n        header.setFixedHeight(24)\n        header.setDefaultSectionSize(80)\n        header.setTextElideMode(Qt.ElideMiddle)\n\n    def setVHeaderFixedWidthFromLabel(self, max_label):\n        header = self.verticalHeader()\n        width = QFontMetrics(header.font()).width(max_label)\n        header.setFixedWidth(min(width + 40, 400))\n\n\nclass TableModel(PyTableModel):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._extremes = {}\n\n    def data(self, index, role=Qt.DisplayRole):\n        if role == gui.BarRatioRole and index.isValid():\n            value = super().data(index, Qt.EditRole)\n            if not isinstance(value, float):\n                return None\n            vmin, vmax = self._extremes.get(index.column(), (-np.inf, np.inf))\n            value = (value - vmin) / ((vmax - vmin) or 1)\n            return value\n\n        if role == Qt.DisplayRole:\n            role = Qt.EditRole\n\n        value = super().data(index, role)\n\n        # Display nothing for non-existent attr value counts in the first column\n        if role == Qt.EditRole and index.column() == 0 and np.isnan(value):\n            return ''\n\n        return value\n\n    def headerData(self, section, orientation, role=Qt.DisplayRole):\n        if role == Qt.InitialSortOrderRole:\n            return Qt.DescendingOrder\n        return super().headerData(section, orientation, role)\n\n    def setExtremesFrom(self, column, values):\n        \"\"\"Set extremes for columnn's ratio bars from values\"\"\"\n        try:\n            with warnings.catch_warnings():\n                warnings.filterwarnings(\n                    \"ignore\", \".*All-NaN slice encountered.*\", RuntimeWarning)\n                vmin = np.nanmin(values)\n            if np.isnan(vmin):\n                raise TypeError\n        except TypeError:\n            vmin, vmax = -np.inf, np.inf\n        else:\n            vmax = np.nanmax(values)\n        self._extremes[column] = (vmin, vmax)\n\n    def resetSorting(self, yes_reset=False):\n        # pylint: disable=arguments-differ\n        \"\"\"We don't want to invalidate our sort proxy model everytime we\n        wrap a new list. Our proxymodel only invalidates explicitly\n        (i.e. when new data is set)\"\"\"\n        if yes_reset:\n            super().resetSorting()\n\n    def _argsortData(self, data, order):\n        \"\"\"Always sort NaNs last\"\"\"\n        indices = np.argsort(data, kind='mergesort')\n        if order == Qt.DescendingOrder:\n            return np.roll(indices[::-1], -np.isnan(data).sum())\n        return indices\n\n\nclass OWRank(OWWidget):\n    name = \"Rank\"\n    description = \"Rank and filter data features by their relevance.\"\n    icon = \"icons/Rank.svg\"\n    priority = 1102\n    keywords = []\n\n    buttons_area_orientation = Qt.Vertical\n\n    class Inputs:\n        data = Input(\"Data\", Table)\n        scorer = Input(\"Scorer\", score.Scorer, multiple=True)\n\n    class Outputs:\n        reduced_data = Output(\"Reduced Data\", Table, default=True)\n        scores = Output(\"Scores\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    SelectNone, SelectAll, SelectManual, SelectNBest = range(4)\n\n    nSelected = ContextSetting(5)\n    auto_apply = Setting(True)\n\n    sorting = Setting((0, Qt.DescendingOrder))\n    selected_methods = Setting(set())\n\n    settings_version = 2\n    settingsHandler = DomainContextHandler()\n    selected_rows = ContextSetting([])\n    selectionMethod = ContextSetting(SelectNBest)\n\n    class Information(OWWidget.Information):\n        no_target_var = Msg(\"Data does not have a single target variable. \"\n                            \"You can still connect in unsupervised scorers \"\n                            \"such as PCA.\")\n        missings_imputed = Msg('Missing values will be imputed as needed.')\n\n    class Error(OWWidget.Error):\n        invalid_type = Msg(\"Cannot handle target variable type {}\")\n        inadequate_learner = Msg(\"Scorer {} inadequate: {}\")\n        no_attributes = Msg(\"Data does not have a single attribute.\")\n\n    def __init__(self):\n        super().__init__()\n        self.scorers = OrderedDict()\n        self.out_domain_desc = None\n        self.data = None\n        self.problem_type_mode = ProblemType.CLASSIFICATION\n\n        if not self.selected_methods:\n            self.selected_methods = {method.name for method in SCORES\n                                     if method.is_default}\n\n        # GUI\n\n        self.ranksModel = model = TableModel(parent=self)  # type: TableModel\n        self.ranksView = view = TableView(self)            # type: TableView\n        self.mainArea.layout().addWidget(view)\n        view.setModel(model)\n        view.setColumnWidth(0, 30)\n        view.selectionModel().selectionChanged.connect(self.on_select)\n\n        def _set_select_manual():\n            self.setSelectionMethod(OWRank.SelectManual)\n\n        view.pressed.connect(_set_select_manual)\n        view.verticalHeader().sectionClicked.connect(_set_select_manual)\n        view.horizontalHeader().sectionClicked.connect(self.headerClick)\n\n        self.measuresStack = stacked = QStackedWidget(self)\n        self.controlArea.layout().addWidget(stacked)\n\n        for scoring_methods in (CLS_SCORES,\n                                REG_SCORES,\n                                []):\n            box = gui.vBox(None, \"Scoring Methods\" if scoring_methods else None)\n            stacked.addWidget(box)\n            for method in scoring_methods:\n                box.layout().addWidget(QCheckBox(\n                    method.name, self,\n                    objectName=method.shortname,  # To be easily found in tests\n                    checked=method.name in self.selected_methods,\n                    stateChanged=partial(self.methodSelectionChanged, method_name=method.name)))\n            gui.rubber(box)\n\n        gui.rubber(self.controlArea)\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n\n        selMethBox = gui.vBox(self.controlArea, \"Select Attributes\", addSpace=True)\n\n        grid = QGridLayout()\n        grid.setContentsMargins(6, 0, 6, 0)\n        self.selectButtons = QButtonGroup()\n        self.selectButtons.buttonClicked[int].connect(self.setSelectionMethod)\n\n        def button(text, buttonid, toolTip=None):\n            b = QRadioButton(text)\n            self.selectButtons.addButton(b, buttonid)\n            if toolTip is not None:\n                b.setToolTip(toolTip)\n            return b\n\n        b1 = button(self.tr(\"None\"), OWRank.SelectNone)\n        b2 = button(self.tr(\"All\"), OWRank.SelectAll)\n        b3 = button(self.tr(\"Manual\"), OWRank.SelectManual)\n        b4 = button(self.tr(\"Best ranked:\"), OWRank.SelectNBest)\n\n        s = gui.spin(selMethBox, self, \"nSelected\", 1, 999,\n                     callback=lambda: self.setSelectionMethod(OWRank.SelectNBest))\n\n        grid.addWidget(b1, 0, 0)\n        grid.addWidget(b2, 1, 0)\n        grid.addWidget(b3, 2, 0)\n        grid.addWidget(b4, 3, 0)\n        grid.addWidget(s, 3, 1)\n\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n        selMethBox.layout().addLayout(grid)\n\n        gui.auto_send(selMethBox, self, \"auto_apply\", box=False)\n\n        self.resize(690, 500)\n\n    def switchProblemType(self, index):\n        \"\"\"\n        Switch between discrete/continuous/no_class mode\n        \"\"\"\n        self.measuresStack.setCurrentIndex(index)\n        self.problem_type_mode = index\n\n    @Inputs.data\n    @check_sql_input\n    def set_data(self, data):\n        self.closeContext()\n        self.selected_rows = []\n        self.ranksModel.clear()\n        self.ranksModel.resetSorting(True)\n\n        self.get_method_scores.cache_clear()  # pylint: disable=no-member\n        self.get_scorer_scores.cache_clear()  # pylint: disable=no-member\n\n        self.Error.clear()\n        self.Information.clear()\n        self.Information.missings_imputed(\n            shown=data is not None and data.has_missing())\n\n        if data is not None and not data.domain.attributes:\n            data = None\n            self.Error.no_attributes()\n        self.data = data\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n        if self.data is not None:\n            domain = self.data.domain\n\n            if domain.has_discrete_class:\n                problem_type = ProblemType.CLASSIFICATION\n            elif domain.has_continuous_class:\n                problem_type = ProblemType.REGRESSION\n            elif not domain.class_var:\n                self.Information.no_target_var()\n                problem_type = ProblemType.UNSUPERVISED\n            else:\n                # This can happen?\n                self.Error.invalid_type(type(domain.class_var).__name__)\n                problem_type = None\n\n            if problem_type is not None:\n                self.switchProblemType(problem_type)\n\n            self.ranksModel.setVerticalHeaderLabels(domain.attributes)\n            self.ranksView.setVHeaderFixedWidthFromLabel(\n                max((a.name for a in domain.attributes), key=len))\n\n            self.selectionMethod = OWRank.SelectNBest\n\n        self.openContext(data)\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n    def handleNewSignals(self):\n        self.setStatusMessage('Running')\n        self.updateScores()\n        self.setStatusMessage('')\n        self.on_select()\n\n    @Inputs.scorer\n    def set_learner(self, scorer, id):  # pylint: disable=redefined-builtin\n        if scorer is None:\n            self.scorers.pop(id, None)\n        else:\n            # Avoid caching a (possibly stale) previous instance of the same\n            # Scorer passed via the same signal\n            if id in self.scorers:\n                # pylint: disable=no-member\n                self.get_scorer_scores.cache_clear()\n\n            self.scorers[id] = ScoreMeta(scorer.name, scorer.name, scorer,\n                                         ProblemType.from_variable(scorer.class_type),\n                                         False)\n\n    @memoize_method()\n    def get_method_scores(self, method):\n        # These errors often happen, but they result in nans, which\n        # are handled correctly by the widget\n        estimator = method.scorer()\n        data = self.data\n        try:\n            scores = np.asarray(estimator(data))\n        except ValueError:\n            try:\n                scores = np.array([estimator(data, attr)\n                                   for attr in data.domain.attributes])\n            except ValueError:\n                log.error(\"%s doesn't work on this data\", method.name)\n                scores = np.full(len(data.domain.attributes), np.nan)\n            else:\n                log.warning(\"%s had to be computed separately for each \"\n                            \"variable\", method.name)\n        return scores\n\n    @memoize_method()\n    def get_scorer_scores(self, scorer):\n        try:\n            scores = scorer.scorer.score_data(self.data).T\n        except ValueError:\n            log.error(\"%s doesn't work on this data\", scorer.name)\n            scores = np.full((len(self.data.domain.attributes), 1), np.nan)\n\n        labels = ((scorer.shortname,)\n                  if scores.shape[1] == 1 else\n                  tuple(scorer.shortname + '_' + str(i)\n                        for i in range(1, 1 + scores.shape[1])))\n        return scores, labels\n\n    def updateScores(self):\n        if self.data is None:\n            self.ranksModel.clear()\n            self.Outputs.scores.send(None)\n            return\n\n        methods = [method\n                   for method in SCORES\n                   if (method.name in self.selected_methods and\n                       method.problem_type == self.problem_type_mode and\n                       (not issparse(self.data.X) or\n                        method.scorer.supports_sparse_data))]\n\n        scorers = []\n        self.Error.inadequate_learner.clear()\n        for scorer in self.scorers.values():\n            if scorer.problem_type in (self.problem_type_mode, ProblemType.UNSUPERVISED):\n                scorers.append(scorer)\n            else:\n                self.Error.inadequate_learner(scorer.name, scorer.learner_adequacy_err_msg)\n\n        method_scores = tuple(self.get_method_scores(method)\n                              for method in methods)\n\n        scorer_scores, scorer_labels = (), ()\n        if scorers:\n            scorer_scores, scorer_labels = zip(*(self.get_scorer_scores(scorer)\n                                                 for scorer in scorers))\n            scorer_labels = tuple(chain.from_iterable(scorer_labels))\n\n        labels = tuple(method.shortname for method in methods) + scorer_labels\n        model_array = np.column_stack(\n            ([len(a.values) if a.is_discrete else np.nan\n              for a in self.data.domain.attributes],) +\n            (method_scores if method_scores else ()) +\n            (scorer_scores if scorer_scores else ())\n        )\n        for column, values in enumerate(model_array.T):\n            self.ranksModel.setExtremesFrom(column, values)\n\n        self.ranksModel.wrap(model_array.tolist())\n        self.ranksModel.setHorizontalHeaderLabels(('#',) + labels)\n        self.ranksView.setColumnWidth(0, 40)\n\n        # Re-apply sort\n        try:\n            sort_column, sort_order = self.sorting\n            if sort_column < len(labels):\n                # adds 1 for '#' (discrete count) column\n                self.ranksModel.sort(sort_column + 1, sort_order)\n                self.ranksView.horizontalHeader().setSortIndicator(sort_column + 1, sort_order)\n        except ValueError:\n            pass\n\n        self.autoSelection()\n        self.Outputs.scores.send(self.create_scores_table(labels))\n\n    def on_select(self):\n        # Save indices of attributes in the original, unsorted domain\n        self.selected_rows = list(self.ranksModel.mapToSourceRows([\n            i.row() for i in self.ranksView.selectionModel().selectedRows(0)]))\n        self.commit()\n\n    def setSelectionMethod(self, method):\n        self.selectionMethod = method\n        self.selectButtons.button(method).setChecked(True)\n        self.autoSelection()\n\n    def autoSelection(self):\n        selModel = self.ranksView.selectionModel()\n        model = self.ranksModel\n        rowCount = model.rowCount()\n        columnCount = model.columnCount()\n\n        if self.selectionMethod == OWRank.SelectNone:\n            selection = QItemSelection()\n        elif self.selectionMethod == OWRank.SelectAll:\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(rowCount - 1, columnCount - 1)\n            )\n        elif self.selectionMethod == OWRank.SelectNBest:\n            nSelected = min(self.nSelected, rowCount)\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(nSelected - 1, columnCount - 1)\n            )\n        else:\n            selection = QItemSelection()\n            if self.selected_rows is not None:\n                for row in model.mapFromSourceRows(self.selected_rows):\n                    selection.append(QItemSelectionRange(\n                        model.index(row, 0), model.index(row, columnCount - 1)))\n\n        selModel.select(selection, QItemSelectionModel.ClearAndSelect)\n\n    def headerClick(self, index):\n        if index >= 1 and self.selectionMethod == OWRank.SelectNBest:\n            # Reselect the top ranked attributes\n            self.autoSelection()\n\n        # Store the header states\n        sort_order = self.ranksModel.sortOrder()\n        sort_column = self.ranksModel.sortColumn() - 1  # -1 for '#' (discrete count) column\n        self.sorting = (sort_column, sort_order)\n\n    def methodSelectionChanged(self, state, method_name):\n        if state == Qt.Checked:\n            self.selected_methods.add(method_name)\n        elif method_name in self.selected_methods:\n            self.selected_methods.remove(method_name)\n\n        self.updateScores()\n\n    def send_report(self):\n        if not self.data:\n            return\n        self.report_domain(\"Input\", self.data.domain)\n        self.report_table(\"Ranks\", self.ranksView, num_format=\"{:.3f}\")\n        if self.out_domain_desc is not None:\n            self.report_items(\"Output\", self.out_domain_desc)\n\n    def commit(self):\n        selected_attrs = []\n        if self.data is not None:\n            selected_attrs = [self.data.domain.attributes[i]\n                              for i in self.selected_rows]\n        if not selected_attrs:\n            self.Outputs.reduced_data.send(None)\n            self.Outputs.features.send(None)\n            self.out_domain_desc = None\n        else:\n            reduced_domain = Domain(\n                selected_attrs, self.data.domain.class_var, self.data.domain.metas)\n            data = self.data.transform(reduced_domain)\n            self.Outputs.reduced_data.send(data)\n            self.Outputs.features.send(AttributeList(selected_attrs))\n            self.out_domain_desc = report.describe_domain(data.domain)\n\n    def create_scores_table(self, labels):\n        model_list = self.ranksModel.tolist()\n        if not model_list or len(model_list[0]) == 1:  # Empty or just n_values column\n            return None\n\n        domain = Domain([ContinuousVariable(label) for label in labels],\n                        metas=[StringVariable(\"Feature\")])\n\n        # Prevent np.inf scores\n        finfo = np.finfo(np.float64)\n        scores = np.clip(np.array(model_list)[:, 1:], finfo.min, finfo.max)\n\n        feature_names = np.array([a.name for a in self.data.domain.attributes])\n        # Reshape to 2d array as Table does not like 1d arrays\n        feature_names = feature_names[:, None]\n\n        new_table = Table(domain, scores, metas=feature_names)\n        new_table.name = \"Feature Scores\"\n        return new_table\n\n    @classmethod\n    def migrate_settings(cls, settings, version):\n        # If older settings, restore sort header to default\n        # Saved selected_rows will likely be incorrect\n        if version is None or version < 2:\n            column, order = 0, Qt.DescendingOrder\n            headerState = settings.pop(\"headerState\", None)\n\n            # Lacking knowledge of last problemType, use discrete ranks view's ordering\n            if isinstance(headerState, (tuple, list)):\n                headerState = headerState[0]\n\n            if isinstance(headerState, bytes):\n                hview = QHeaderView(Qt.Horizontal)\n                hview.restoreState(headerState)\n                column, order = hview.sortIndicatorSection() - 1, hview.sortIndicatorOrder()\n            settings[\"sorting\"] = (column, order)\n\n    @classmethod\n    def migrate_context(cls, context, version):\n        if version is None or version < 2:\n            # Old selection was saved as sorted indices. New selection is original indices.\n            # Since we can't devise the latter without first computing the ranks,\n            # just reset the selection to avoid confusion.\n            context.values['selected_rows'] = []\n\n\nif __name__ == \"__main__\":  # pragma: no cover\n    from Orange.classification import RandomForestLearner\n    previewer = WidgetPreview(OWRank)\n    previewer.run(Table(\"heart_disease.tab\"), no_exit=True)\n    previewer.send_signals(\n        set_learner=(RandomForestLearner(), (3, 'Learner', None)))\n    previewer.run()\n\n    # pylint: disable=pointless-string-statement\n    \"\"\"\n    WidgetPreview(OWRank).run(\n        set_learner=(RandomForestLearner(), (3, 'Learner', None)),\n        set_data=Table(\"heart_disease.tab\"))\n\"\"\"\n",
            "new_file_content": "\"\"\"\nRank\n====\n\nRank (score) features for prediction.\n\n\"\"\"\nimport warnings\nfrom collections import namedtuple, OrderedDict\nimport logging\nfrom functools import partial\nfrom itertools import chain\n\nimport numpy as np\nfrom scipy.sparse import issparse\n\nfrom AnyQt.QtGui import QFontMetrics\nfrom AnyQt.QtWidgets import (\n    QTableView, QRadioButton, QButtonGroup, QGridLayout,\n    QStackedWidget, QHeaderView, QCheckBox, QItemDelegate,\n)\nfrom AnyQt.QtCore import (\n    Qt, QItemSelection, QItemSelectionRange, QItemSelectionModel,\n)\n\nfrom Orange.data import (Table, Domain, ContinuousVariable, DiscreteVariable,\n                         StringVariable)\nfrom Orange.misc.cache import memoize_method\nfrom Orange.preprocess import score\nfrom Orange.widgets import report\nfrom Orange.widgets import gui\nfrom Orange.widgets.settings import (DomainContextHandler, Setting,\n                                     ContextSetting)\nfrom Orange.widgets.utils.itemmodels import PyTableModel\nfrom Orange.widgets.utils.sql import check_sql_input\nfrom Orange.widgets.utils.widgetpreview import WidgetPreview\nfrom Orange.widgets.widget import (\n    OWWidget, Msg, Input, Output, AttributeList\n)\n\n\nlog = logging.getLogger(__name__)\n\n\nclass ProblemType:\n    CLASSIFICATION, REGRESSION, UNSUPERVISED = range(3)\n\n    @classmethod\n    def from_variable(cls, variable):\n        return (cls.CLASSIFICATION if isinstance(variable, DiscreteVariable) else\n                cls.REGRESSION if isinstance(variable, ContinuousVariable) else\n                cls.UNSUPERVISED)\n\nScoreMeta = namedtuple(\"score_meta\", [\"name\", \"shortname\", \"scorer\", 'problem_type', 'is_default'])\n\n# Default scores.\nCLS_SCORES = [\n    ScoreMeta(\"Information Gain\", \"Info. gain\",\n              score.InfoGain, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"Information Gain Ratio\", \"Gain ratio\",\n              score.GainRatio, ProblemType.CLASSIFICATION, True),\n    ScoreMeta(\"Gini Decrease\", \"Gini\",\n              score.Gini, ProblemType.CLASSIFICATION, True),\n    ScoreMeta(\"ANOVA\", \"ANOVA\",\n              score.ANOVA, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"χ²\", \"χ²\",\n              score.Chi2, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"ReliefF\", \"ReliefF\",\n              score.ReliefF, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"FCBF\", \"FCBF\",\n              score.FCBF, ProblemType.CLASSIFICATION, False)\n]\nREG_SCORES = [\n    ScoreMeta(\"Univariate Regression\", \"Univar. reg.\",\n              score.UnivariateLinearRegression, ProblemType.REGRESSION, True),\n    ScoreMeta(\"RReliefF\", \"RReliefF\",\n              score.RReliefF, ProblemType.REGRESSION, True)\n]\nSCORES = CLS_SCORES + REG_SCORES\n\n\nclass TableView(QTableView):\n    def __init__(self, parent=None, **kwargs):\n        super().__init__(parent=parent,\n                         selectionBehavior=QTableView.SelectRows,\n                         selectionMode=QTableView.ExtendedSelection,\n                         sortingEnabled=True,\n                         showGrid=True,\n                         cornerButtonEnabled=False,\n                         alternatingRowColors=False,\n                         **kwargs)\n        self.setItemDelegate(gui.ColoredBarItemDelegate(self))\n        self.setItemDelegateForColumn(0, QItemDelegate())\n\n        header = self.verticalHeader()\n        header.setSectionResizeMode(header.Fixed)\n        header.setFixedWidth(50)\n        header.setDefaultSectionSize(22)\n        header.setTextElideMode(Qt.ElideMiddle)  # Note: https://bugreports.qt.io/browse/QTBUG-62091\n\n        header = self.horizontalHeader()\n        header.setSectionResizeMode(header.Fixed)\n        header.setFixedHeight(24)\n        header.setDefaultSectionSize(80)\n        header.setTextElideMode(Qt.ElideMiddle)\n\n    def setVHeaderFixedWidthFromLabel(self, max_label):\n        header = self.verticalHeader()\n        width = QFontMetrics(header.font()).width(max_label)\n        header.setFixedWidth(min(width + 40, 400))\n\n\nclass TableModel(PyTableModel):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._extremes = {}\n\n    def data(self, index, role=Qt.DisplayRole):\n        if role == gui.BarRatioRole and index.isValid():\n            value = super().data(index, Qt.EditRole)\n            if not isinstance(value, float):\n                return None\n            vmin, vmax = self._extremes.get(index.column(), (-np.inf, np.inf))\n            value = (value - vmin) / ((vmax - vmin) or 1)\n            return value\n\n        if role == Qt.DisplayRole:\n            role = Qt.EditRole\n\n        value = super().data(index, role)\n\n        # Display nothing for non-existent attr value counts in the first column\n        if role == Qt.EditRole and index.column() == 0 and np.isnan(value):\n            return ''\n\n        return value\n\n    def headerData(self, section, orientation, role=Qt.DisplayRole):\n        if role == Qt.InitialSortOrderRole:\n            return Qt.DescendingOrder\n        return super().headerData(section, orientation, role)\n\n    def setExtremesFrom(self, column, values):\n        \"\"\"Set extremes for columnn's ratio bars from values\"\"\"\n        try:\n            with warnings.catch_warnings():\n                warnings.filterwarnings(\n                    \"ignore\", \".*All-NaN slice encountered.*\", RuntimeWarning)\n                vmin = np.nanmin(values)\n            if np.isnan(vmin):\n                raise TypeError\n        except TypeError:\n            vmin, vmax = -np.inf, np.inf\n        else:\n            vmax = np.nanmax(values)\n        self._extremes[column] = (vmin, vmax)\n\n    def resetSorting(self, yes_reset=False):\n        # pylint: disable=arguments-differ\n        \"\"\"We don't want to invalidate our sort proxy model everytime we\n        wrap a new list. Our proxymodel only invalidates explicitly\n        (i.e. when new data is set)\"\"\"\n        if yes_reset:\n            super().resetSorting()\n\n    def _argsortData(self, data, order):\n        \"\"\"Always sort NaNs last\"\"\"\n        indices = np.argsort(data, kind='mergesort')\n        if order == Qt.DescendingOrder:\n            return np.roll(indices[::-1], -np.isnan(data).sum())\n        return indices\n\n\nclass OWRank(OWWidget):\n    name = \"Rank\"\n    description = \"Rank and filter data features by their relevance.\"\n    icon = \"icons/Rank.svg\"\n    priority = 1102\n    keywords = []\n\n    buttons_area_orientation = Qt.Vertical\n\n    class Inputs:\n        data = Input(\"Data\", Table)\n        scorer = Input(\"Scorer\", score.Scorer, multiple=True)\n\n    class Outputs:\n        reduced_data = Output(\"Reduced Data\", Table, default=True)\n        scores = Output(\"Scores\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    SelectNone, SelectAll, SelectManual, SelectNBest = range(4)\n\n    nSelected = ContextSetting(5)\n    auto_apply = Setting(True)\n\n    sorting = Setting((0, Qt.DescendingOrder))\n    selected_methods = Setting(set())\n\n    settings_version = 2\n    settingsHandler = DomainContextHandler()\n    selected_rows = ContextSetting([])\n    selectionMethod = ContextSetting(SelectNBest)\n\n    class Information(OWWidget.Information):\n        no_target_var = Msg(\"Data does not have a single target variable. \"\n                            \"You can still connect in unsupervised scorers \"\n                            \"such as PCA.\")\n        missings_imputed = Msg('Missing values will be imputed as needed.')\n\n    class Error(OWWidget.Error):\n        invalid_type = Msg(\"Cannot handle target variable type {}\")\n        inadequate_learner = Msg(\"Scorer {} inadequate: {}\")\n        no_attributes = Msg(\"Data does not have a single attribute.\")\n\n    def __init__(self):\n        super().__init__()\n        self.scorers = OrderedDict()\n        self.out_domain_desc = None\n        self.data = None\n        self.problem_type_mode = ProblemType.CLASSIFICATION\n\n        if not self.selected_methods:\n            self.selected_methods = {method.name for method in SCORES\n                                     if method.is_default}\n\n        # GUI\n\n        self.ranksModel = model = TableModel(parent=self)  # type: TableModel\n        self.ranksView = view = TableView(self)            # type: TableView\n        self.mainArea.layout().addWidget(view)\n        view.setModel(model)\n        view.setColumnWidth(0, 30)\n        view.selectionModel().selectionChanged.connect(self.on_select)\n\n        def _set_select_manual():\n            self.setSelectionMethod(OWRank.SelectManual)\n\n        view.pressed.connect(_set_select_manual)\n        view.verticalHeader().sectionClicked.connect(_set_select_manual)\n        view.horizontalHeader().sectionClicked.connect(self.headerClick)\n\n        self.measuresStack = stacked = QStackedWidget(self)\n        self.controlArea.layout().addWidget(stacked)\n\n        for scoring_methods in (CLS_SCORES,\n                                REG_SCORES,\n                                []):\n            box = gui.vBox(None, \"Scoring Methods\" if scoring_methods else None)\n            stacked.addWidget(box)\n            for method in scoring_methods:\n                box.layout().addWidget(QCheckBox(\n                    method.name, self,\n                    objectName=method.shortname,  # To be easily found in tests\n                    checked=method.name in self.selected_methods,\n                    stateChanged=partial(self.methodSelectionChanged, method_name=method.name)))\n            gui.rubber(box)\n\n        gui.rubber(self.controlArea)\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n\n        selMethBox = gui.vBox(self.controlArea, \"Select Attributes\", addSpace=True)\n\n        grid = QGridLayout()\n        grid.setContentsMargins(6, 0, 6, 0)\n        self.selectButtons = QButtonGroup()\n        self.selectButtons.buttonClicked[int].connect(self.setSelectionMethod)\n\n        def button(text, buttonid, toolTip=None):\n            b = QRadioButton(text)\n            self.selectButtons.addButton(b, buttonid)\n            if toolTip is not None:\n                b.setToolTip(toolTip)\n            return b\n\n        b1 = button(self.tr(\"None\"), OWRank.SelectNone)\n        b2 = button(self.tr(\"All\"), OWRank.SelectAll)\n        b3 = button(self.tr(\"Manual\"), OWRank.SelectManual)\n        b4 = button(self.tr(\"Best ranked:\"), OWRank.SelectNBest)\n\n        s = gui.spin(selMethBox, self, \"nSelected\", 1, 999,\n                     callback=lambda: self.setSelectionMethod(OWRank.SelectNBest))\n\n        grid.addWidget(b1, 0, 0)\n        grid.addWidget(b2, 1, 0)\n        grid.addWidget(b3, 2, 0)\n        grid.addWidget(b4, 3, 0)\n        grid.addWidget(s, 3, 1)\n\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n        selMethBox.layout().addLayout(grid)\n\n        gui.auto_send(selMethBox, self, \"auto_apply\", box=False)\n\n        self.resize(690, 500)\n\n    def switchProblemType(self, index):\n        \"\"\"\n        Switch between discrete/continuous/no_class mode\n        \"\"\"\n        self.measuresStack.setCurrentIndex(index)\n        self.problem_type_mode = index\n\n    @Inputs.data\n    @check_sql_input\n    def set_data(self, data):\n        self.closeContext()\n        self.selected_rows = []\n        self.ranksModel.clear()\n        self.ranksModel.resetSorting(True)\n\n        self.get_method_scores.cache_clear()  # pylint: disable=no-member\n        self.get_scorer_scores.cache_clear()  # pylint: disable=no-member\n\n        self.Error.clear()\n        self.Information.clear()\n        self.Information.missings_imputed(\n            shown=data is not None and data.has_missing())\n\n        if data is not None and not data.domain.attributes:\n            data = None\n            self.Error.no_attributes()\n        self.data = data\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n        if self.data is not None:\n            domain = self.data.domain\n\n            if domain.has_discrete_class:\n                problem_type = ProblemType.CLASSIFICATION\n            elif domain.has_continuous_class:\n                problem_type = ProblemType.REGRESSION\n            elif not domain.class_var:\n                self.Information.no_target_var()\n                problem_type = ProblemType.UNSUPERVISED\n            else:\n                # This can happen?\n                self.Error.invalid_type(type(domain.class_var).__name__)\n                problem_type = None\n\n            if problem_type is not None:\n                self.switchProblemType(problem_type)\n\n            self.ranksModel.setVerticalHeaderLabels(domain.attributes)\n            self.ranksView.setVHeaderFixedWidthFromLabel(\n                max((a.name for a in domain.attributes), key=len))\n\n            self.selectionMethod = OWRank.SelectNBest\n\n        self.openContext(data)\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n    def handleNewSignals(self):\n        self.setStatusMessage('Running')\n        self.updateScores()\n        self.setStatusMessage('')\n        self.on_select()\n\n    @Inputs.scorer\n    def set_learner(self, scorer, id):  # pylint: disable=redefined-builtin\n        if scorer is None:\n            self.scorers.pop(id, None)\n        else:\n            # Avoid caching a (possibly stale) previous instance of the same\n            # Scorer passed via the same signal\n            if id in self.scorers:\n                # pylint: disable=no-member\n                self.get_scorer_scores.cache_clear()\n\n            self.scorers[id] = ScoreMeta(scorer.name, scorer.name, scorer,\n                                         ProblemType.from_variable(scorer.class_type),\n                                         False)\n\n    @memoize_method()\n    def get_method_scores(self, method):\n        # These errors often happen, but they result in nans, which\n        # are handled correctly by the widget\n        estimator = method.scorer()\n        data = self.data\n        try:\n            scores = np.asarray(estimator(data))\n        except ValueError:\n            try:\n                scores = np.array([estimator(data, attr)\n                                   for attr in data.domain.attributes])\n            except ValueError:\n                log.error(\"%s doesn't work on this data\", method.name)\n                scores = np.full(len(data.domain.attributes), np.nan)\n            else:\n                log.warning(\"%s had to be computed separately for each \"\n                            \"variable\", method.name)\n        return scores\n\n    @memoize_method()\n    def get_scorer_scores(self, scorer):\n        try:\n            scores = scorer.scorer.score_data(self.data).T\n        except (ValueError, TypeError):\n            log.error(\"%s doesn't work on this data\", scorer.name)\n            scores = np.full((len(self.data.domain.attributes), 1), np.nan)\n\n        labels = ((scorer.shortname,)\n                  if scores.shape[1] == 1 else\n                  tuple(scorer.shortname + '_' + str(i)\n                        for i in range(1, 1 + scores.shape[1])))\n        return scores, labels\n\n    def updateScores(self):\n        if self.data is None:\n            self.ranksModel.clear()\n            self.Outputs.scores.send(None)\n            return\n\n        methods = [method\n                   for method in SCORES\n                   if (method.name in self.selected_methods and\n                       method.problem_type == self.problem_type_mode and\n                       (not issparse(self.data.X) or\n                        method.scorer.supports_sparse_data))]\n\n        scorers = []\n        self.Error.inadequate_learner.clear()\n        for scorer in self.scorers.values():\n            if scorer.problem_type in (self.problem_type_mode, ProblemType.UNSUPERVISED):\n                scorers.append(scorer)\n            else:\n                self.Error.inadequate_learner(scorer.name, scorer.learner_adequacy_err_msg)\n\n        method_scores = tuple(self.get_method_scores(method)\n                              for method in methods)\n\n        scorer_scores, scorer_labels = (), ()\n        if scorers:\n            scorer_scores, scorer_labels = zip(*(self.get_scorer_scores(scorer)\n                                                 for scorer in scorers))\n            scorer_labels = tuple(chain.from_iterable(scorer_labels))\n\n        labels = tuple(method.shortname for method in methods) + scorer_labels\n        model_array = np.column_stack(\n            ([len(a.values) if a.is_discrete else np.nan\n              for a in self.data.domain.attributes],) +\n            (method_scores if method_scores else ()) +\n            (scorer_scores if scorer_scores else ())\n        )\n        for column, values in enumerate(model_array.T):\n            self.ranksModel.setExtremesFrom(column, values)\n\n        self.ranksModel.wrap(model_array.tolist())\n        self.ranksModel.setHorizontalHeaderLabels(('#',) + labels)\n        self.ranksView.setColumnWidth(0, 40)\n\n        # Re-apply sort\n        try:\n            sort_column, sort_order = self.sorting\n            if sort_column < len(labels):\n                # adds 1 for '#' (discrete count) column\n                self.ranksModel.sort(sort_column + 1, sort_order)\n                self.ranksView.horizontalHeader().setSortIndicator(sort_column + 1, sort_order)\n        except ValueError:\n            pass\n\n        self.autoSelection()\n        self.Outputs.scores.send(self.create_scores_table(labels))\n\n    def on_select(self):\n        # Save indices of attributes in the original, unsorted domain\n        self.selected_rows = list(self.ranksModel.mapToSourceRows([\n            i.row() for i in self.ranksView.selectionModel().selectedRows(0)]))\n        self.commit()\n\n    def setSelectionMethod(self, method):\n        self.selectionMethod = method\n        self.selectButtons.button(method).setChecked(True)\n        self.autoSelection()\n\n    def autoSelection(self):\n        selModel = self.ranksView.selectionModel()\n        model = self.ranksModel\n        rowCount = model.rowCount()\n        columnCount = model.columnCount()\n\n        if self.selectionMethod == OWRank.SelectNone:\n            selection = QItemSelection()\n        elif self.selectionMethod == OWRank.SelectAll:\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(rowCount - 1, columnCount - 1)\n            )\n        elif self.selectionMethod == OWRank.SelectNBest:\n            nSelected = min(self.nSelected, rowCount)\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(nSelected - 1, columnCount - 1)\n            )\n        else:\n            selection = QItemSelection()\n            if self.selected_rows is not None:\n                for row in model.mapFromSourceRows(self.selected_rows):\n                    selection.append(QItemSelectionRange(\n                        model.index(row, 0), model.index(row, columnCount - 1)))\n\n        selModel.select(selection, QItemSelectionModel.ClearAndSelect)\n\n    def headerClick(self, index):\n        if index >= 1 and self.selectionMethod == OWRank.SelectNBest:\n            # Reselect the top ranked attributes\n            self.autoSelection()\n\n        # Store the header states\n        sort_order = self.ranksModel.sortOrder()\n        sort_column = self.ranksModel.sortColumn() - 1  # -1 for '#' (discrete count) column\n        self.sorting = (sort_column, sort_order)\n\n    def methodSelectionChanged(self, state, method_name):\n        if state == Qt.Checked:\n            self.selected_methods.add(method_name)\n        elif method_name in self.selected_methods:\n            self.selected_methods.remove(method_name)\n\n        self.updateScores()\n\n    def send_report(self):\n        if not self.data:\n            return\n        self.report_domain(\"Input\", self.data.domain)\n        self.report_table(\"Ranks\", self.ranksView, num_format=\"{:.3f}\")\n        if self.out_domain_desc is not None:\n            self.report_items(\"Output\", self.out_domain_desc)\n\n    def commit(self):\n        selected_attrs = []\n        if self.data is not None:\n            selected_attrs = [self.data.domain.attributes[i]\n                              for i in self.selected_rows]\n        if not selected_attrs:\n            self.Outputs.reduced_data.send(None)\n            self.Outputs.features.send(None)\n            self.out_domain_desc = None\n        else:\n            reduced_domain = Domain(\n                selected_attrs, self.data.domain.class_var, self.data.domain.metas)\n            data = self.data.transform(reduced_domain)\n            self.Outputs.reduced_data.send(data)\n            self.Outputs.features.send(AttributeList(selected_attrs))\n            self.out_domain_desc = report.describe_domain(data.domain)\n\n    def create_scores_table(self, labels):\n        model_list = self.ranksModel.tolist()\n        if not model_list or len(model_list[0]) == 1:  # Empty or just n_values column\n            return None\n\n        domain = Domain([ContinuousVariable(label) for label in labels],\n                        metas=[StringVariable(\"Feature\")])\n\n        # Prevent np.inf scores\n        finfo = np.finfo(np.float64)\n        scores = np.clip(np.array(model_list)[:, 1:], finfo.min, finfo.max)\n\n        feature_names = np.array([a.name for a in self.data.domain.attributes])\n        # Reshape to 2d array as Table does not like 1d arrays\n        feature_names = feature_names[:, None]\n\n        new_table = Table(domain, scores, metas=feature_names)\n        new_table.name = \"Feature Scores\"\n        return new_table\n\n    @classmethod\n    def migrate_settings(cls, settings, version):\n        # If older settings, restore sort header to default\n        # Saved selected_rows will likely be incorrect\n        if version is None or version < 2:\n            column, order = 0, Qt.DescendingOrder\n            headerState = settings.pop(\"headerState\", None)\n\n            # Lacking knowledge of last problemType, use discrete ranks view's ordering\n            if isinstance(headerState, (tuple, list)):\n                headerState = headerState[0]\n\n            if isinstance(headerState, bytes):\n                hview = QHeaderView(Qt.Horizontal)\n                hview.restoreState(headerState)\n                column, order = hview.sortIndicatorSection() - 1, hview.sortIndicatorOrder()\n            settings[\"sorting\"] = (column, order)\n\n    @classmethod\n    def migrate_context(cls, context, version):\n        if version is None or version < 2:\n            # Old selection was saved as sorted indices. New selection is original indices.\n            # Since we can't devise the latter without first computing the ranks,\n            # just reset the selection to avoid confusion.\n            context.values['selected_rows'] = []\n\n\nif __name__ == \"__main__\":  # pragma: no cover\n    from Orange.classification import RandomForestLearner\n    previewer = WidgetPreview(OWRank)\n    previewer.run(Table(\"heart_disease.tab\"), no_exit=True)\n    previewer.send_signals(\n        set_learner=(RandomForestLearner(), (3, 'Learner', None)))\n    previewer.run()\n\n    # pylint: disable=pointless-string-statement\n    \"\"\"\n    WidgetPreview(OWRank).run(\n        set_learner=(RandomForestLearner(), (3, 'Learner', None)),\n        set_data=Table(\"heart_disease.tab\"))\n\"\"\"\n",
            "header": {
                "file": {
                    "path": "Orange/widgets/data/owrank.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "edbf5ffb9",
                "new_commit_hash": "d84d3e79f",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Orange/widgets/data/owrank.py"
            },
            "plus_file": {
                "path": "b/Orange/widgets/data/owrank.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 395,
                            "length": 7
                        },
                        "new_range": {
                            "start": 395,
                            "length": 7
                        },
                        "section": "class OWRank(OWWidget):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    def get_scorer_scores(self, scorer):",
                                "type": "context"
                            },
                            {
                                "content": "        try:",
                                "type": "context"
                            },
                            {
                                "content": "            scores = scorer.scorer.score_data(self.data).T",
                                "type": "context"
                            },
                            {
                                "content": "        except ValueError:",
                                "type": "deleted"
                            },
                            {
                                "content": "        except (ValueError, TypeError):",
                                "type": "added"
                            },
                            {
                                "content": "            log.error(\"%s doesn't work on this data\", scorer.name)",
                                "type": "context"
                            },
                            {
                                "content": "            scores = np.full((len(self.data.domain.attributes), 1), np.nan)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/widgets/data/owrank.py",
                            "type": "class",
                            "name": "OWRank",
                            "content": "class OWRank(OWWidget):\n    name = \"Rank\"\n    description = \"Rank and filter data features by their relevance.\"\n    icon = \"icons/Rank.svg\"\n    priority = 1102\n    keywords = []\n\n    buttons_area_orientation = Qt.Vertical\n\n    class Inputs:\n        data = Input(\"Data\", Table)\n        scorer = Input(\"Scorer\", score.Scorer, multiple=True)\n\n    class Outputs:\n        reduced_data = Output(\"Reduced Data\", Table, default=True)\n        scores = Output(\"Scores\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    SelectNone, SelectAll, SelectManual, SelectNBest = range(4)\n\n    nSelected = ContextSetting(5)\n    auto_apply = Setting(True)\n\n    sorting = Setting((0, Qt.DescendingOrder))\n    selected_methods = Setting(set())\n\n    settings_version = 2\n    settingsHandler = DomainContextHandler()\n    selected_rows = ContextSetting([])\n    selectionMethod = ContextSetting(SelectNBest)\n\n    class Information(OWWidget.Information):\n        no_target_var = Msg(\"Data does not have a single target variable. \"\n                            \"You can still connect in unsupervised scorers \"\n                            \"such as PCA.\")\n        missings_imputed = Msg('Missing values will be imputed as needed.')\n\n    class Error(OWWidget.Error):\n        invalid_type = Msg(\"Cannot handle target variable type {}\")\n        inadequate_learner = Msg(\"Scorer {} inadequate: {}\")\n        no_attributes = Msg(\"Data does not have a single attribute.\")\n\n    def __init__(self):\n        super().__init__()\n        self.scorers = OrderedDict()\n        self.out_domain_desc = None\n        self.data = None\n        self.problem_type_mode = ProblemType.CLASSIFICATION\n\n        if not self.selected_methods:\n            self.selected_methods = {method.name for method in SCORES\n                                     if method.is_default}\n\n        # GUI\n\n        self.ranksModel = model = TableModel(parent=self)  # type: TableModel\n        self.ranksView = view = TableView(self)            # type: TableView\n        self.mainArea.layout().addWidget(view)\n        view.setModel(model)\n        view.setColumnWidth(0, 30)\n        view.selectionModel().selectionChanged.connect(self.on_select)\n\n        def _set_select_manual():\n            self.setSelectionMethod(OWRank.SelectManual)\n\n        view.pressed.connect(_set_select_manual)\n        view.verticalHeader().sectionClicked.connect(_set_select_manual)\n        view.horizontalHeader().sectionClicked.connect(self.headerClick)\n\n        self.measuresStack = stacked = QStackedWidget(self)\n        self.controlArea.layout().addWidget(stacked)\n\n        for scoring_methods in (CLS_SCORES,\n                                REG_SCORES,\n                                []):\n            box = gui.vBox(None, \"Scoring Methods\" if scoring_methods else None)\n            stacked.addWidget(box)\n            for method in scoring_methods:\n                box.layout().addWidget(QCheckBox(\n                    method.name, self,\n                    objectName=method.shortname,  # To be easily found in tests\n                    checked=method.name in self.selected_methods,\n                    stateChanged=partial(self.methodSelectionChanged, method_name=method.name)))\n            gui.rubber(box)\n\n        gui.rubber(self.controlArea)\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n\n        selMethBox = gui.vBox(self.controlArea, \"Select Attributes\", addSpace=True)\n\n        grid = QGridLayout()\n        grid.setContentsMargins(6, 0, 6, 0)\n        self.selectButtons = QButtonGroup()\n        self.selectButtons.buttonClicked[int].connect(self.setSelectionMethod)\n\n        def button(text, buttonid, toolTip=None):\n            b = QRadioButton(text)\n            self.selectButtons.addButton(b, buttonid)\n            if toolTip is not None:\n                b.setToolTip(toolTip)\n            return b\n\n        b1 = button(self.tr(\"None\"), OWRank.SelectNone)\n        b2 = button(self.tr(\"All\"), OWRank.SelectAll)\n        b3 = button(self.tr(\"Manual\"), OWRank.SelectManual)\n        b4 = button(self.tr(\"Best ranked:\"), OWRank.SelectNBest)\n\n        s = gui.spin(selMethBox, self, \"nSelected\", 1, 999,\n                     callback=lambda: self.setSelectionMethod(OWRank.SelectNBest))\n\n        grid.addWidget(b1, 0, 0)\n        grid.addWidget(b2, 1, 0)\n        grid.addWidget(b3, 2, 0)\n        grid.addWidget(b4, 3, 0)\n        grid.addWidget(s, 3, 1)\n\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n        selMethBox.layout().addLayout(grid)\n\n        gui.auto_send(selMethBox, self, \"auto_apply\", box=False)\n\n        self.resize(690, 500)\n\n    def switchProblemType(self, index):\n        \"\"\"\n        Switch between discrete/continuous/no_class mode\n        \"\"\"\n        self.measuresStack.setCurrentIndex(index)\n        self.problem_type_mode = index\n\n    @Inputs.data\n    @check_sql_input\n    def set_data(self, data):\n        self.closeContext()\n        self.selected_rows = []\n        self.ranksModel.clear()\n        self.ranksModel.resetSorting(True)\n\n        self.get_method_scores.cache_clear()  # pylint: disable=no-member\n        self.get_scorer_scores.cache_clear()  # pylint: disable=no-member\n\n        self.Error.clear()\n        self.Information.clear()\n        self.Information.missings_imputed(\n            shown=data is not None and data.has_missing())\n\n        if data is not None and not data.domain.attributes:\n            data = None\n            self.Error.no_attributes()\n        self.data = data\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n        if self.data is not None:\n            domain = self.data.domain\n\n            if domain.has_discrete_class:\n                problem_type = ProblemType.CLASSIFICATION\n            elif domain.has_continuous_class:\n                problem_type = ProblemType.REGRESSION\n            elif not domain.class_var:\n                self.Information.no_target_var()\n                problem_type = ProblemType.UNSUPERVISED\n            else:\n                # This can happen?\n                self.Error.invalid_type(type(domain.class_var).__name__)\n                problem_type = None\n\n            if problem_type is not None:\n                self.switchProblemType(problem_type)\n\n            self.ranksModel.setVerticalHeaderLabels(domain.attributes)\n            self.ranksView.setVHeaderFixedWidthFromLabel(\n                max((a.name for a in domain.attributes), key=len))\n\n            self.selectionMethod = OWRank.SelectNBest\n\n        self.openContext(data)\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n    def handleNewSignals(self):\n        self.setStatusMessage('Running')\n        self.updateScores()\n        self.setStatusMessage('')\n        self.on_select()\n\n    @Inputs.scorer\n    def set_learner(self, scorer, id):  # pylint: disable=redefined-builtin\n        if scorer is None:\n            self.scorers.pop(id, None)\n        else:\n            # Avoid caching a (possibly stale) previous instance of the same\n            # Scorer passed via the same signal\n            if id in self.scorers:\n                # pylint: disable=no-member\n                self.get_scorer_scores.cache_clear()\n\n            self.scorers[id] = ScoreMeta(scorer.name, scorer.name, scorer,\n                                         ProblemType.from_variable(scorer.class_type),\n                                         False)\n\n    @memoize_method()\n    def get_method_scores(self, method):\n        # These errors often happen, but they result in nans, which\n        # are handled correctly by the widget\n        estimator = method.scorer()\n        data = self.data\n        try:\n            scores = np.asarray(estimator(data))\n        except ValueError:\n            try:\n                scores = np.array([estimator(data, attr)\n                                   for attr in data.domain.attributes])\n            except ValueError:\n                log.error(\"%s doesn't work on this data\", method.name)\n                scores = np.full(len(data.domain.attributes), np.nan)\n            else:\n                log.warning(\"%s had to be computed separately for each \"\n                            \"variable\", method.name)\n        return scores\n\n    @memoize_method()\n    def get_scorer_scores(self, scorer):\n        try:\n            scores = scorer.scorer.score_data(self.data).T\n        except ValueError:\n            log.error(\"%s doesn't work on this data\", scorer.name)\n            scores = np.full((len(self.data.domain.attributes), 1), np.nan)\n\n        labels = ((scorer.shortname,)\n                  if scores.shape[1] == 1 else\n                  tuple(scorer.shortname + '_' + str(i)\n                        for i in range(1, 1 + scores.shape[1])))\n        return scores, labels\n\n    def updateScores(self):\n        if self.data is None:\n            self.ranksModel.clear()\n            self.Outputs.scores.send(None)\n            return\n\n        methods = [method\n                   for method in SCORES\n                   if (method.name in self.selected_methods and\n                       method.problem_type == self.problem_type_mode and\n                       (not issparse(self.data.X) or\n                        method.scorer.supports_sparse_data))]\n\n        scorers = []\n        self.Error.inadequate_learner.clear()\n        for scorer in self.scorers.values():\n            if scorer.problem_type in (self.problem_type_mode, ProblemType.UNSUPERVISED):\n                scorers.append(scorer)\n            else:\n                self.Error.inadequate_learner(scorer.name, scorer.learner_adequacy_err_msg)\n\n        method_scores = tuple(self.get_method_scores(method)\n                              for method in methods)\n\n        scorer_scores, scorer_labels = (), ()\n        if scorers:\n            scorer_scores, scorer_labels = zip(*(self.get_scorer_scores(scorer)\n                                                 for scorer in scorers))\n            scorer_labels = tuple(chain.from_iterable(scorer_labels))\n\n        labels = tuple(method.shortname for method in methods) + scorer_labels\n        model_array = np.column_stack(\n            ([len(a.values) if a.is_discrete else np.nan\n              for a in self.data.domain.attributes],) +\n            (method_scores if method_scores else ()) +\n            (scorer_scores if scorer_scores else ())\n        )\n        for column, values in enumerate(model_array.T):\n            self.ranksModel.setExtremesFrom(column, values)\n\n        self.ranksModel.wrap(model_array.tolist())\n        self.ranksModel.setHorizontalHeaderLabels(('#',) + labels)\n        self.ranksView.setColumnWidth(0, 40)\n\n        # Re-apply sort\n        try:\n            sort_column, sort_order = self.sorting\n            if sort_column < len(labels):\n                # adds 1 for '#' (discrete count) column\n                self.ranksModel.sort(sort_column + 1, sort_order)\n                self.ranksView.horizontalHeader().setSortIndicator(sort_column + 1, sort_order)\n        except ValueError:\n            pass\n\n        self.autoSelection()\n        self.Outputs.scores.send(self.create_scores_table(labels))\n\n    def on_select(self):\n        # Save indices of attributes in the original, unsorted domain\n        self.selected_rows = list(self.ranksModel.mapToSourceRows([\n            i.row() for i in self.ranksView.selectionModel().selectedRows(0)]))\n        self.commit()\n\n    def setSelectionMethod(self, method):\n        self.selectionMethod = method\n        self.selectButtons.button(method).setChecked(True)\n        self.autoSelection()\n\n    def autoSelection(self):\n        selModel = self.ranksView.selectionModel()\n        model = self.ranksModel\n        rowCount = model.rowCount()\n        columnCount = model.columnCount()\n\n        if self.selectionMethod == OWRank.SelectNone:\n            selection = QItemSelection()\n        elif self.selectionMethod == OWRank.SelectAll:\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(rowCount - 1, columnCount - 1)\n            )\n        elif self.selectionMethod == OWRank.SelectNBest:\n            nSelected = min(self.nSelected, rowCount)\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(nSelected - 1, columnCount - 1)\n            )\n        else:\n            selection = QItemSelection()\n            if self.selected_rows is not None:\n                for row in model.mapFromSourceRows(self.selected_rows):\n                    selection.append(QItemSelectionRange(\n                        model.index(row, 0), model.index(row, columnCount - 1)))\n\n        selModel.select(selection, QItemSelectionModel.ClearAndSelect)\n\n    def headerClick(self, index):\n        if index >= 1 and self.selectionMethod == OWRank.SelectNBest:\n            # Reselect the top ranked attributes\n            self.autoSelection()\n\n        # Store the header states\n        sort_order = self.ranksModel.sortOrder()\n        sort_column = self.ranksModel.sortColumn() - 1  # -1 for '#' (discrete count) column\n        self.sorting = (sort_column, sort_order)\n\n    def methodSelectionChanged(self, state, method_name):\n        if state == Qt.Checked:\n            self.selected_methods.add(method_name)\n        elif method_name in self.selected_methods:\n            self.selected_methods.remove(method_name)\n\n        self.updateScores()\n\n    def send_report(self):\n        if not self.data:\n            return\n        self.report_domain(\"Input\", self.data.domain)\n        self.report_table(\"Ranks\", self.ranksView, num_format=\"{:.3f}\")\n        if self.out_domain_desc is not None:\n            self.report_items(\"Output\", self.out_domain_desc)\n\n    def commit(self):\n        selected_attrs = []\n        if self.data is not None:\n            selected_attrs = [self.data.domain.attributes[i]\n                              for i in self.selected_rows]\n        if not selected_attrs:\n            self.Outputs.reduced_data.send(None)\n            self.Outputs.features.send(None)\n            self.out_domain_desc = None\n        else:\n            reduced_domain = Domain(\n                selected_attrs, self.data.domain.class_var, self.data.domain.metas)\n            data = self.data.transform(reduced_domain)\n            self.Outputs.reduced_data.send(data)\n            self.Outputs.features.send(AttributeList(selected_attrs))\n            self.out_domain_desc = report.describe_domain(data.domain)\n\n    def create_scores_table(self, labels):\n        model_list = self.ranksModel.tolist()\n        if not model_list or len(model_list[0]) == 1:  # Empty or just n_values column\n            return None\n\n        domain = Domain([ContinuousVariable(label) for label in labels],\n                        metas=[StringVariable(\"Feature\")])\n\n        # Prevent np.inf scores\n        finfo = np.finfo(np.float64)\n        scores = np.clip(np.array(model_list)[:, 1:], finfo.min, finfo.max)\n\n        feature_names = np.array([a.name for a in self.data.domain.attributes])\n        # Reshape to 2d array as Table does not like 1d arrays\n        feature_names = feature_names[:, None]\n\n        new_table = Table(domain, scores, metas=feature_names)\n        new_table.name = \"Feature Scores\"\n        return new_table\n\n    @classmethod\n    def migrate_settings(cls, settings, version):\n        # If older settings, restore sort header to default\n        # Saved selected_rows will likely be incorrect\n        if version is None or version < 2:\n            column, order = 0, Qt.DescendingOrder\n            headerState = settings.pop(\"headerState\", None)\n\n            # Lacking knowledge of last problemType, use discrete ranks view's ordering\n            if isinstance(headerState, (tuple, list)):\n                headerState = headerState[0]\n\n            if isinstance(headerState, bytes):\n                hview = QHeaderView(Qt.Horizontal)\n                hview.restoreState(headerState)\n                column, order = hview.sortIndicatorSection() - 1, hview.sortIndicatorOrder()\n            settings[\"sorting\"] = (column, order)\n\n    @classmethod\n    def migrate_context(cls, context, version):\n        if version is None or version < 2:\n            # Old selection was saved as sorted indices. New selection is original indices.\n            # Since we can't devise the latter without first computing the ranks,\n            # just reset the selection to avoid confusion.\n            context.values['selected_rows'] = []",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 174,
                            "end_lineno": 591,
                            "parent": null
                        },
                        {
                            "file_name": "Orange/widgets/data/owrank.py",
                            "type": "method",
                            "name": "OWRank.get_scorer_scores",
                            "content": "class OWRank(OWWidget):\n    name = \"Rank\"\n    description = \"Rank and filter data features by their relevance.\"\n    icon = \"icons/Rank.svg\"\n    priority = 1102\n    keywords = []\n\n    buttons_area_orientation = Qt.Vertical\n\n    class Inputs:\n        data = Input(\"Data\", Table)\n        scorer = Input(\"Scorer\", score.Scorer, multiple=True)\n\n    class Outputs:\n        reduced_data = Output(\"Reduced Data\", Table, default=True)\n        scores = Output(\"Scores\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    SelectNone, SelectAll, SelectManual, SelectNBest = range(4)\n\n    nSelected = ContextSetting(5)\n    auto_apply = Setting(True)\n\n    sorting = Setting((0, Qt.DescendingOrder))\n    selected_methods = Setting(set())\n\n    settings_version = 2\n    settingsHandler = DomainContextHandler()\n    selected_rows = ContextSetting([])\n    selectionMethod = ContextSetting(SelectNBest)\n\n    class Information(OWWidget.Information):\n        no_target_var = Msg(\"Data does not have a single target variable. \"\n                            \"You can still connect in unsupervised scorers \"\n                            \"such as PCA.\")\n        missings_imputed = Msg('Missing values will be imputed as needed.')\n\n    class Error(OWWidget.Error):\n        invalid_type = Msg(\"Cannot handle target variable type {}\")\n        inadequate_learner = Msg(\"Scorer {} inadequate: {}\")\n        no_attributes = Msg(\"Data does not have a single attribute.\")\n\n    def __init__(self):\n        super().__init__()\n        self.scorers = OrderedDict()\n        self.out_domain_desc = None\n        self.data = None\n        self.problem_type_mode = ProblemType.CLASSIFICATION\n\n        if not self.selected_methods:\n            self.selected_methods = {method.name for method in SCORES\n                                     if method.is_default}\n\n        # GUI\n\n        self.ranksModel = model = TableModel(parent=self)  # type: TableModel\n        self.ranksView = view = TableView(self)            # type: TableView\n        self.mainArea.layout().addWidget(view)\n        view.setModel(model)\n        view.setColumnWidth(0, 30)\n        view.selectionModel().selectionChanged.connect(self.on_select)\n\n        def _set_select_manual():\n            self.setSelectionMethod(OWRank.SelectManual)\n\n        view.pressed.connect(_set_select_manual)\n        view.verticalHeader().sectionClicked.connect(_set_select_manual)\n        view.horizontalHeader().sectionClicked.connect(self.headerClick)\n\n        self.measuresStack = stacked = QStackedWidget(self)\n        self.controlArea.layout().addWidget(stacked)\n\n        for scoring_methods in (CLS_SCORES,\n                                REG_SCORES,\n                                []):\n            box = gui.vBox(None, \"Scoring Methods\" if scoring_methods else None)\n            stacked.addWidget(box)\n            for method in scoring_methods:\n                box.layout().addWidget(QCheckBox(\n                    method.name, self,\n                    objectName=method.shortname,  # To be easily found in tests\n                    checked=method.name in self.selected_methods,\n                    stateChanged=partial(self.methodSelectionChanged, method_name=method.name)))\n            gui.rubber(box)\n\n        gui.rubber(self.controlArea)\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n\n        selMethBox = gui.vBox(self.controlArea, \"Select Attributes\", addSpace=True)\n\n        grid = QGridLayout()\n        grid.setContentsMargins(6, 0, 6, 0)\n        self.selectButtons = QButtonGroup()\n        self.selectButtons.buttonClicked[int].connect(self.setSelectionMethod)\n\n        def button(text, buttonid, toolTip=None):\n            b = QRadioButton(text)\n            self.selectButtons.addButton(b, buttonid)\n            if toolTip is not None:\n                b.setToolTip(toolTip)\n            return b\n\n        b1 = button(self.tr(\"None\"), OWRank.SelectNone)\n        b2 = button(self.tr(\"All\"), OWRank.SelectAll)\n        b3 = button(self.tr(\"Manual\"), OWRank.SelectManual)\n        b4 = button(self.tr(\"Best ranked:\"), OWRank.SelectNBest)\n\n        s = gui.spin(selMethBox, self, \"nSelected\", 1, 999,\n                     callback=lambda: self.setSelectionMethod(OWRank.SelectNBest))\n\n        grid.addWidget(b1, 0, 0)\n        grid.addWidget(b2, 1, 0)\n        grid.addWidget(b3, 2, 0)\n        grid.addWidget(b4, 3, 0)\n        grid.addWidget(s, 3, 1)\n\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n        selMethBox.layout().addLayout(grid)\n\n        gui.auto_send(selMethBox, self, \"auto_apply\", box=False)\n\n        self.resize(690, 500)\n\n    def switchProblemType(self, index):\n        \"\"\"\n        Switch between discrete/continuous/no_class mode\n        \"\"\"\n        self.measuresStack.setCurrentIndex(index)\n        self.problem_type_mode = index\n\n    @Inputs.data\n    @check_sql_input\n    def set_data(self, data):\n        self.closeContext()\n        self.selected_rows = []\n        self.ranksModel.clear()\n        self.ranksModel.resetSorting(True)\n\n        self.get_method_scores.cache_clear()  # pylint: disable=no-member\n        self.get_scorer_scores.cache_clear()  # pylint: disable=no-member\n\n        self.Error.clear()\n        self.Information.clear()\n        self.Information.missings_imputed(\n            shown=data is not None and data.has_missing())\n\n        if data is not None and not data.domain.attributes:\n            data = None\n            self.Error.no_attributes()\n        self.data = data\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n        if self.data is not None:\n            domain = self.data.domain\n\n            if domain.has_discrete_class:\n                problem_type = ProblemType.CLASSIFICATION\n            elif domain.has_continuous_class:\n                problem_type = ProblemType.REGRESSION\n            elif not domain.class_var:\n                self.Information.no_target_var()\n                problem_type = ProblemType.UNSUPERVISED\n            else:\n                # This can happen?\n                self.Error.invalid_type(type(domain.class_var).__name__)\n                problem_type = None\n\n            if problem_type is not None:\n                self.switchProblemType(problem_type)\n\n            self.ranksModel.setVerticalHeaderLabels(domain.attributes)\n            self.ranksView.setVHeaderFixedWidthFromLabel(\n                max((a.name for a in domain.attributes), key=len))\n\n            self.selectionMethod = OWRank.SelectNBest\n\n        self.openContext(data)\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n    def handleNewSignals(self):\n        self.setStatusMessage('Running')\n        self.updateScores()\n        self.setStatusMessage('')\n        self.on_select()\n\n    @Inputs.scorer\n    def set_learner(self, scorer, id):  # pylint: disable=redefined-builtin\n        if scorer is None:\n            self.scorers.pop(id, None)\n        else:\n            # Avoid caching a (possibly stale) previous instance of the same\n            # Scorer passed via the same signal\n            if id in self.scorers:\n                # pylint: disable=no-member\n                self.get_scorer_scores.cache_clear()\n\n            self.scorers[id] = ScoreMeta(scorer.name, scorer.name, scorer,\n                                         ProblemType.from_variable(scorer.class_type),\n                                         False)\n\n    @memoize_method()\n    def get_method_scores(self, method):\n        # These errors often happen, but they result in nans, which\n        # are handled correctly by the widget\n        estimator = method.scorer()\n        data = self.data\n        try:\n            scores = np.asarray(estimator(data))\n        except ValueError:\n            try:\n                scores = np.array([estimator(data, attr)\n                                   for attr in data.domain.attributes])\n            except ValueError:\n                log.error(\"%s doesn't work on this data\", method.name)\n                scores = np.full(len(data.domain.attributes), np.nan)\n            else:\n                log.warning(\"%s had to be computed separately for each \"\n                            \"variable\", method.name)\n        return scores\n\n    @memoize_method()\n    def get_scorer_scores(self, scorer):\n        try:\n            scores = scorer.scorer.score_data(self.data).T\n        except ValueError:\n            log.error(\"%s doesn't work on this data\", scorer.name)\n            scores = np.full((len(self.data.domain.attributes), 1), np.nan)\n\n        labels = ((scorer.shortname,)\n                  if scores.shape[1] == 1 else\n                  tuple(scorer.shortname + '_' + str(i)\n                        for i in range(1, 1 + scores.shape[1])))\n        return scores, labels\n\n    def updateScores(self):\n        if self.data is None:\n            self.ranksModel.clear()\n            self.Outputs.scores.send(None)\n            return\n\n        methods = [method\n                   for method in SCORES\n                   if (method.name in self.selected_methods and\n                       method.problem_type == self.problem_type_mode and\n                       (not issparse(self.data.X) or\n                        method.scorer.supports_sparse_data))]\n\n        scorers = []\n        self.Error.inadequate_learner.clear()\n        for scorer in self.scorers.values():\n            if scorer.problem_type in (self.problem_type_mode, ProblemType.UNSUPERVISED):\n                scorers.append(scorer)\n            else:\n                self.Error.inadequate_learner(scorer.name, scorer.learner_adequacy_err_msg)\n\n        method_scores = tuple(self.get_method_scores(method)\n                              for method in methods)\n\n        scorer_scores, scorer_labels = (), ()\n        if scorers:\n            scorer_scores, scorer_labels = zip(*(self.get_scorer_scores(scorer)\n                                                 for scorer in scorers))\n            scorer_labels = tuple(chain.from_iterable(scorer_labels))\n\n        labels = tuple(method.shortname for method in methods) + scorer_labels\n        model_array = np.column_stack(\n            ([len(a.values) if a.is_discrete else np.nan\n              for a in self.data.domain.attributes],) +\n            (method_scores if method_scores else ()) +\n            (scorer_scores if scorer_scores else ())\n        )\n        for column, values in enumerate(model_array.T):\n            self.ranksModel.setExtremesFrom(column, values)\n\n        self.ranksModel.wrap(model_array.tolist())\n        self.ranksModel.setHorizontalHeaderLabels(('#',) + labels)\n        self.ranksView.setColumnWidth(0, 40)\n\n        # Re-apply sort\n        try:\n            sort_column, sort_order = self.sorting\n            if sort_column < len(labels):\n                # adds 1 for '#' (discrete count) column\n                self.ranksModel.sort(sort_column + 1, sort_order)\n                self.ranksView.horizontalHeader().setSortIndicator(sort_column + 1, sort_order)\n        except ValueError:\n            pass\n\n        self.autoSelection()\n        self.Outputs.scores.send(self.create_scores_table(labels))\n\n    def on_select(self):\n        # Save indices of attributes in the original, unsorted domain\n        self.selected_rows = list(self.ranksModel.mapToSourceRows([\n            i.row() for i in self.ranksView.selectionModel().selectedRows(0)]))\n        self.commit()\n\n    def setSelectionMethod(self, method):\n        self.selectionMethod = method\n        self.selectButtons.button(method).setChecked(True)\n        self.autoSelection()\n\n    def autoSelection(self):\n        selModel = self.ranksView.selectionModel()\n        model = self.ranksModel\n        rowCount = model.rowCount()\n        columnCount = model.columnCount()\n\n        if self.selectionMethod == OWRank.SelectNone:\n            selection = QItemSelection()\n        elif self.selectionMethod == OWRank.SelectAll:\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(rowCount - 1, columnCount - 1)\n            )\n        elif self.selectionMethod == OWRank.SelectNBest:\n            nSelected = min(self.nSelected, rowCount)\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(nSelected - 1, columnCount - 1)\n            )\n        else:\n            selection = QItemSelection()\n            if self.selected_rows is not None:\n                for row in model.mapFromSourceRows(self.selected_rows):\n                    selection.append(QItemSelectionRange(\n                        model.index(row, 0), model.index(row, columnCount - 1)))\n\n        selModel.select(selection, QItemSelectionModel.ClearAndSelect)\n\n    def headerClick(self, index):\n        if index >= 1 and self.selectionMethod == OWRank.SelectNBest:\n            # Reselect the top ranked attributes\n            self.autoSelection()\n\n        # Store the header states\n        sort_order = self.ranksModel.sortOrder()\n        sort_column = self.ranksModel.sortColumn() - 1  # -1 for '#' (discrete count) column\n        self.sorting = (sort_column, sort_order)\n\n    def methodSelectionChanged(self, state, method_name):\n        if state == Qt.Checked:\n            self.selected_methods.add(method_name)\n        elif method_name in self.selected_methods:\n            self.selected_methods.remove(method_name)\n\n        self.updateScores()\n\n    def send_report(self):\n        if not self.data:\n            return\n        self.report_domain(\"Input\", self.data.domain)\n        self.report_table(\"Ranks\", self.ranksView, num_format=\"{:.3f}\")\n        if self.out_domain_desc is not None:\n            self.report_items(\"Output\", self.out_domain_desc)\n\n    def commit(self):\n        selected_attrs = []\n        if self.data is not None:\n            selected_attrs = [self.data.domain.attributes[i]\n                              for i in self.selected_rows]\n        if not selected_attrs:\n            self.Outputs.reduced_data.send(None)\n            self.Outputs.features.send(None)\n            self.out_domain_desc = None\n        else:\n            reduced_domain = Domain(\n                selected_attrs, self.data.domain.class_var, self.data.domain.metas)\n            data = self.data.transform(reduced_domain)\n            self.Outputs.reduced_data.send(data)\n            self.Outputs.features.send(AttributeList(selected_attrs))\n            self.out_domain_desc = report.describe_domain(data.domain)\n\n    def create_scores_table(self, labels):\n        model_list = self.ranksModel.tolist()\n        if not model_list or len(model_list[0]) == 1:  # Empty or just n_values column\n            return None\n\n        domain = Domain([ContinuousVariable(label) for label in labels],\n                        metas=[StringVariable(\"Feature\")])\n\n        # Prevent np.inf scores\n        finfo = np.finfo(np.float64)\n        scores = np.clip(np.array(model_list)[:, 1:], finfo.min, finfo.max)\n\n        feature_names = np.array([a.name for a in self.data.domain.attributes])\n        # Reshape to 2d array as Table does not like 1d arrays\n        feature_names = feature_names[:, None]\n\n        new_table = Table(domain, scores, metas=feature_names)\n        new_table.name = \"Feature Scores\"\n        return new_table\n\n    @classmethod\n    def migrate_settings(cls, settings, version):\n        # If older settings, restore sort header to default\n        # Saved selected_rows will likely be incorrect\n        if version is None or version < 2:\n            column, order = 0, Qt.DescendingOrder\n            headerState = settings.pop(\"headerState\", None)\n\n            # Lacking knowledge of last problemType, use discrete ranks view's ordering\n            if isinstance(headerState, (tuple, list)):\n                headerState = headerState[0]\n\n            if isinstance(headerState, bytes):\n                hview = QHeaderView(Qt.Horizontal)\n                hview.restoreState(headerState)\n                column, order = hview.sortIndicatorSection() - 1, hview.sortIndicatorOrder()\n            settings[\"sorting\"] = (column, order)\n\n    @classmethod\n    def migrate_context(cls, context, version):\n        if version is None or version < 2:\n            # Old selection was saved as sorted indices. New selection is original indices.\n            # Since we can't devise the latter without first computing the ranks,\n            # just reset the selection to avoid confusion.\n            context.values['selected_rows'] = []",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 395,
                            "end_lineno": 406,
                            "parent": {
                                "file_name": "Orange/widgets/data/owrank.py",
                                "type": "class",
                                "name": "OWRank",
                                "content": "class OWRank(OWWidget):\n    name = \"Rank\"\n    description = \"Rank and filter data features by their relevance.\"\n    icon = \"icons/Rank.svg\"\n    priority = 1102\n    keywords = []\n\n    buttons_area_orientation = Qt.Vertical\n\n    class Inputs:\n        data = Input(\"Data\", Table)\n        scorer = Input(\"Scorer\", score.Scorer, multiple=True)\n\n    class Outputs:\n        reduced_data = Output(\"Reduced Data\", Table, default=True)\n        scores = Output(\"Scores\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    SelectNone, SelectAll, SelectManual, SelectNBest = range(4)\n\n    nSelected = ContextSetting(5)\n    auto_apply = Setting(True)\n\n    sorting = Setting((0, Qt.DescendingOrder))\n    selected_methods = Setting(set())\n\n    settings_version = 2\n    settingsHandler = DomainContextHandler()\n    selected_rows = ContextSetting([])\n    selectionMethod = ContextSetting(SelectNBest)\n\n    class Information(OWWidget.Information):\n        no_target_var = Msg(\"Data does not have a single target variable. \"\n                            \"You can still connect in unsupervised scorers \"\n                            \"such as PCA.\")\n        missings_imputed = Msg('Missing values will be imputed as needed.')\n\n    class Error(OWWidget.Error):\n        invalid_type = Msg(\"Cannot handle target variable type {}\")\n        inadequate_learner = Msg(\"Scorer {} inadequate: {}\")\n        no_attributes = Msg(\"Data does not have a single attribute.\")\n\n    def __init__(self):\n        super().__init__()\n        self.scorers = OrderedDict()\n        self.out_domain_desc = None\n        self.data = None\n        self.problem_type_mode = ProblemType.CLASSIFICATION\n\n        if not self.selected_methods:\n            self.selected_methods = {method.name for method in SCORES\n                                     if method.is_default}\n\n        # GUI\n\n        self.ranksModel = model = TableModel(parent=self)  # type: TableModel\n        self.ranksView = view = TableView(self)            # type: TableView\n        self.mainArea.layout().addWidget(view)\n        view.setModel(model)\n        view.setColumnWidth(0, 30)\n        view.selectionModel().selectionChanged.connect(self.on_select)\n\n        def _set_select_manual():\n            self.setSelectionMethod(OWRank.SelectManual)\n\n        view.pressed.connect(_set_select_manual)\n        view.verticalHeader().sectionClicked.connect(_set_select_manual)\n        view.horizontalHeader().sectionClicked.connect(self.headerClick)\n\n        self.measuresStack = stacked = QStackedWidget(self)\n        self.controlArea.layout().addWidget(stacked)\n\n        for scoring_methods in (CLS_SCORES,\n                                REG_SCORES,\n                                []):\n            box = gui.vBox(None, \"Scoring Methods\" if scoring_methods else None)\n            stacked.addWidget(box)\n            for method in scoring_methods:\n                box.layout().addWidget(QCheckBox(\n                    method.name, self,\n                    objectName=method.shortname,  # To be easily found in tests\n                    checked=method.name in self.selected_methods,\n                    stateChanged=partial(self.methodSelectionChanged, method_name=method.name)))\n            gui.rubber(box)\n\n        gui.rubber(self.controlArea)\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n\n        selMethBox = gui.vBox(self.controlArea, \"Select Attributes\", addSpace=True)\n\n        grid = QGridLayout()\n        grid.setContentsMargins(6, 0, 6, 0)\n        self.selectButtons = QButtonGroup()\n        self.selectButtons.buttonClicked[int].connect(self.setSelectionMethod)\n\n        def button(text, buttonid, toolTip=None):\n            b = QRadioButton(text)\n            self.selectButtons.addButton(b, buttonid)\n            if toolTip is not None:\n                b.setToolTip(toolTip)\n            return b\n\n        b1 = button(self.tr(\"None\"), OWRank.SelectNone)\n        b2 = button(self.tr(\"All\"), OWRank.SelectAll)\n        b3 = button(self.tr(\"Manual\"), OWRank.SelectManual)\n        b4 = button(self.tr(\"Best ranked:\"), OWRank.SelectNBest)\n\n        s = gui.spin(selMethBox, self, \"nSelected\", 1, 999,\n                     callback=lambda: self.setSelectionMethod(OWRank.SelectNBest))\n\n        grid.addWidget(b1, 0, 0)\n        grid.addWidget(b2, 1, 0)\n        grid.addWidget(b3, 2, 0)\n        grid.addWidget(b4, 3, 0)\n        grid.addWidget(s, 3, 1)\n\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n        selMethBox.layout().addLayout(grid)\n\n        gui.auto_send(selMethBox, self, \"auto_apply\", box=False)\n\n        self.resize(690, 500)\n\n    def switchProblemType(self, index):\n        \"\"\"\n        Switch between discrete/continuous/no_class mode\n        \"\"\"\n        self.measuresStack.setCurrentIndex(index)\n        self.problem_type_mode = index\n\n    @Inputs.data\n    @check_sql_input\n    def set_data(self, data):\n        self.closeContext()\n        self.selected_rows = []\n        self.ranksModel.clear()\n        self.ranksModel.resetSorting(True)\n\n        self.get_method_scores.cache_clear()  # pylint: disable=no-member\n        self.get_scorer_scores.cache_clear()  # pylint: disable=no-member\n\n        self.Error.clear()\n        self.Information.clear()\n        self.Information.missings_imputed(\n            shown=data is not None and data.has_missing())\n\n        if data is not None and not data.domain.attributes:\n            data = None\n            self.Error.no_attributes()\n        self.data = data\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n        if self.data is not None:\n            domain = self.data.domain\n\n            if domain.has_discrete_class:\n                problem_type = ProblemType.CLASSIFICATION\n            elif domain.has_continuous_class:\n                problem_type = ProblemType.REGRESSION\n            elif not domain.class_var:\n                self.Information.no_target_var()\n                problem_type = ProblemType.UNSUPERVISED\n            else:\n                # This can happen?\n                self.Error.invalid_type(type(domain.class_var).__name__)\n                problem_type = None\n\n            if problem_type is not None:\n                self.switchProblemType(problem_type)\n\n            self.ranksModel.setVerticalHeaderLabels(domain.attributes)\n            self.ranksView.setVHeaderFixedWidthFromLabel(\n                max((a.name for a in domain.attributes), key=len))\n\n            self.selectionMethod = OWRank.SelectNBest\n\n        self.openContext(data)\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n    def handleNewSignals(self):\n        self.setStatusMessage('Running')\n        self.updateScores()\n        self.setStatusMessage('')\n        self.on_select()\n\n    @Inputs.scorer\n    def set_learner(self, scorer, id):  # pylint: disable=redefined-builtin\n        if scorer is None:\n            self.scorers.pop(id, None)\n        else:\n            # Avoid caching a (possibly stale) previous instance of the same\n            # Scorer passed via the same signal\n            if id in self.scorers:\n                # pylint: disable=no-member\n                self.get_scorer_scores.cache_clear()\n\n            self.scorers[id] = ScoreMeta(scorer.name, scorer.name, scorer,\n                                         ProblemType.from_variable(scorer.class_type),\n                                         False)\n\n    @memoize_method()\n    def get_method_scores(self, method):\n        # These errors often happen, but they result in nans, which\n        # are handled correctly by the widget\n        estimator = method.scorer()\n        data = self.data\n        try:\n            scores = np.asarray(estimator(data))\n        except ValueError:\n            try:\n                scores = np.array([estimator(data, attr)\n                                   for attr in data.domain.attributes])\n            except ValueError:\n                log.error(\"%s doesn't work on this data\", method.name)\n                scores = np.full(len(data.domain.attributes), np.nan)\n            else:\n                log.warning(\"%s had to be computed separately for each \"\n                            \"variable\", method.name)\n        return scores\n\n    @memoize_method()\n    def get_scorer_scores(self, scorer):\n        try:\n            scores = scorer.scorer.score_data(self.data).T\n        except ValueError:\n            log.error(\"%s doesn't work on this data\", scorer.name)\n            scores = np.full((len(self.data.domain.attributes), 1), np.nan)\n\n        labels = ((scorer.shortname,)\n                  if scores.shape[1] == 1 else\n                  tuple(scorer.shortname + '_' + str(i)\n                        for i in range(1, 1 + scores.shape[1])))\n        return scores, labels\n\n    def updateScores(self):\n        if self.data is None:\n            self.ranksModel.clear()\n            self.Outputs.scores.send(None)\n            return\n\n        methods = [method\n                   for method in SCORES\n                   if (method.name in self.selected_methods and\n                       method.problem_type == self.problem_type_mode and\n                       (not issparse(self.data.X) or\n                        method.scorer.supports_sparse_data))]\n\n        scorers = []\n        self.Error.inadequate_learner.clear()\n        for scorer in self.scorers.values():\n            if scorer.problem_type in (self.problem_type_mode, ProblemType.UNSUPERVISED):\n                scorers.append(scorer)\n            else:\n                self.Error.inadequate_learner(scorer.name, scorer.learner_adequacy_err_msg)\n\n        method_scores = tuple(self.get_method_scores(method)\n                              for method in methods)\n\n        scorer_scores, scorer_labels = (), ()\n        if scorers:\n            scorer_scores, scorer_labels = zip(*(self.get_scorer_scores(scorer)\n                                                 for scorer in scorers))\n            scorer_labels = tuple(chain.from_iterable(scorer_labels))\n\n        labels = tuple(method.shortname for method in methods) + scorer_labels\n        model_array = np.column_stack(\n            ([len(a.values) if a.is_discrete else np.nan\n              for a in self.data.domain.attributes],) +\n            (method_scores if method_scores else ()) +\n            (scorer_scores if scorer_scores else ())\n        )\n        for column, values in enumerate(model_array.T):\n            self.ranksModel.setExtremesFrom(column, values)\n\n        self.ranksModel.wrap(model_array.tolist())\n        self.ranksModel.setHorizontalHeaderLabels(('#',) + labels)\n        self.ranksView.setColumnWidth(0, 40)\n\n        # Re-apply sort\n        try:\n            sort_column, sort_order = self.sorting\n            if sort_column < len(labels):\n                # adds 1 for '#' (discrete count) column\n                self.ranksModel.sort(sort_column + 1, sort_order)\n                self.ranksView.horizontalHeader().setSortIndicator(sort_column + 1, sort_order)\n        except ValueError:\n            pass\n\n        self.autoSelection()\n        self.Outputs.scores.send(self.create_scores_table(labels))\n\n    def on_select(self):\n        # Save indices of attributes in the original, unsorted domain\n        self.selected_rows = list(self.ranksModel.mapToSourceRows([\n            i.row() for i in self.ranksView.selectionModel().selectedRows(0)]))\n        self.commit()\n\n    def setSelectionMethod(self, method):\n        self.selectionMethod = method\n        self.selectButtons.button(method).setChecked(True)\n        self.autoSelection()\n\n    def autoSelection(self):\n        selModel = self.ranksView.selectionModel()\n        model = self.ranksModel\n        rowCount = model.rowCount()\n        columnCount = model.columnCount()\n\n        if self.selectionMethod == OWRank.SelectNone:\n            selection = QItemSelection()\n        elif self.selectionMethod == OWRank.SelectAll:\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(rowCount - 1, columnCount - 1)\n            )\n        elif self.selectionMethod == OWRank.SelectNBest:\n            nSelected = min(self.nSelected, rowCount)\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(nSelected - 1, columnCount - 1)\n            )\n        else:\n            selection = QItemSelection()\n            if self.selected_rows is not None:\n                for row in model.mapFromSourceRows(self.selected_rows):\n                    selection.append(QItemSelectionRange(\n                        model.index(row, 0), model.index(row, columnCount - 1)))\n\n        selModel.select(selection, QItemSelectionModel.ClearAndSelect)\n\n    def headerClick(self, index):\n        if index >= 1 and self.selectionMethod == OWRank.SelectNBest:\n            # Reselect the top ranked attributes\n            self.autoSelection()\n\n        # Store the header states\n        sort_order = self.ranksModel.sortOrder()\n        sort_column = self.ranksModel.sortColumn() - 1  # -1 for '#' (discrete count) column\n        self.sorting = (sort_column, sort_order)\n\n    def methodSelectionChanged(self, state, method_name):\n        if state == Qt.Checked:\n            self.selected_methods.add(method_name)\n        elif method_name in self.selected_methods:\n            self.selected_methods.remove(method_name)\n\n        self.updateScores()\n\n    def send_report(self):\n        if not self.data:\n            return\n        self.report_domain(\"Input\", self.data.domain)\n        self.report_table(\"Ranks\", self.ranksView, num_format=\"{:.3f}\")\n        if self.out_domain_desc is not None:\n            self.report_items(\"Output\", self.out_domain_desc)\n\n    def commit(self):\n        selected_attrs = []\n        if self.data is not None:\n            selected_attrs = [self.data.domain.attributes[i]\n                              for i in self.selected_rows]\n        if not selected_attrs:\n            self.Outputs.reduced_data.send(None)\n            self.Outputs.features.send(None)\n            self.out_domain_desc = None\n        else:\n            reduced_domain = Domain(\n                selected_attrs, self.data.domain.class_var, self.data.domain.metas)\n            data = self.data.transform(reduced_domain)\n            self.Outputs.reduced_data.send(data)\n            self.Outputs.features.send(AttributeList(selected_attrs))\n            self.out_domain_desc = report.describe_domain(data.domain)\n\n    def create_scores_table(self, labels):\n        model_list = self.ranksModel.tolist()\n        if not model_list or len(model_list[0]) == 1:  # Empty or just n_values column\n            return None\n\n        domain = Domain([ContinuousVariable(label) for label in labels],\n                        metas=[StringVariable(\"Feature\")])\n\n        # Prevent np.inf scores\n        finfo = np.finfo(np.float64)\n        scores = np.clip(np.array(model_list)[:, 1:], finfo.min, finfo.max)\n\n        feature_names = np.array([a.name for a in self.data.domain.attributes])\n        # Reshape to 2d array as Table does not like 1d arrays\n        feature_names = feature_names[:, None]\n\n        new_table = Table(domain, scores, metas=feature_names)\n        new_table.name = \"Feature Scores\"\n        return new_table\n\n    @classmethod\n    def migrate_settings(cls, settings, version):\n        # If older settings, restore sort header to default\n        # Saved selected_rows will likely be incorrect\n        if version is None or version < 2:\n            column, order = 0, Qt.DescendingOrder\n            headerState = settings.pop(\"headerState\", None)\n\n            # Lacking knowledge of last problemType, use discrete ranks view's ordering\n            if isinstance(headerState, (tuple, list)):\n                headerState = headerState[0]\n\n            if isinstance(headerState, bytes):\n                hview = QHeaderView(Qt.Horizontal)\n                hview.restoreState(headerState)\n                column, order = hview.sortIndicatorSection() - 1, hview.sortIndicatorOrder()\n            settings[\"sorting\"] = (column, order)\n\n    @classmethod\n    def migrate_context(cls, context, version):\n        if version is None or version < 2:\n            # Old selection was saved as sorted indices. New selection is original indices.\n            # Since we can't devise the latter without first computing the ranks,\n            # just reset the selection to avoid confusion.\n            context.values['selected_rows'] = []",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 174,
                                "end_lineno": 591,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import warnings\nimport unittest\nfrom unittest.mock import patch\n\nimport numpy as np\nfrom sklearn.exceptions import ConvergenceWarning\n\nfrom AnyQt.QtCore import Qt, QItemSelection\nfrom AnyQt.QtWidgets import QCheckBox\n\nfrom Orange.data import Table, Domain, ContinuousVariable, DiscreteVariable\nfrom Orange.modelling import RandomForestLearner, SGDLearner\nfrom Orange.preprocess.score import Scorer\nfrom Orange.classification import LogisticRegressionLearner\nfrom Orange.regression import LinearRegressionLearner\nfrom Orange.projection import PCA\nfrom Orange.widgets.data.owrank import OWRank, ProblemType, CLS_SCORES, REG_SCORES\nfrom Orange.widgets.tests.base import WidgetTest, datasets\nfrom Orange.widgets.widget import AttributeList\n\n\nclass TestOWRank(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWRank)  # type: OWRank\n        self.iris = Table(\"iris\")\n        self.housing = Table(\"housing\")\n        self.log_reg = LogisticRegressionLearner()\n        self.lin_reg = LinearRegressionLearner()\n        self.pca = PCA()\n\n    def _get_checkbox(self, method_shortname):\n        return self.widget.controlArea.findChild(QCheckBox, method_shortname)\n\n    def test_input_data(self):\n        \"\"\"Check widget's data with data on the input\"\"\"\n        self.assertEqual(self.widget.data, None)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n\n    def test_input_data_disconnect(self):\n        \"\"\"Check widget's data after disconnecting data on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertEqual(self.widget.data, None)\n\n    def test_input_scorer(self):\n        \"\"\"Check widget's scorer with scorer on the input\"\"\"\n        self.assertEqual(self.widget.scorers, {})\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        value = self.widget.scorers[1]\n        self.assertEqual(self.log_reg, value.scorer)\n        self.assertIsInstance(value.scorer, Scorer)\n\n    def test_input_scorer_fitter(self):\n        heart_disease = Table('heart_disease')\n        self.assertEqual(self.widget.scorers, {})\n\n        model = self.widget.ranksModel\n\n        for fitter, name in ((RandomForestLearner(), 'random forest'),\n                             (SGDLearner(), 'sgd')):\n            with self.subTest(fitter=fitter),\\\n                    warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", \".*\", ConvergenceWarning)\n                self.send_signal(\"Scorer\", fitter, 1)\n\n                for data in (self.housing,\n                             heart_disease):\n                    with self.subTest(data=data.name):\n                        self.send_signal('Data', data)\n                        scores = [model.data(model.index(row, model.columnCount() - 1))\n                                  for row in range(model.rowCount())]\n                        self.assertEqual(len(scores), len(data.domain.attributes))\n                        self.assertFalse(np.isnan(scores).any())\n\n                        last_column = model.headerData(\n                            model.columnCount() - 1, Qt.Horizontal).lower()\n                        self.assertIn(name, last_column)\n\n                self.send_signal(\"Scorer\", None, 1)\n                self.assertEqual(self.widget.scorers, {})\n\n    def test_input_scorer_disconnect(self):\n        \"\"\"Check widget's scorer after disconnecting scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(len(self.widget.scorers), 1)\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.widget.scorers, {})\n\n    def test_output_data(self):\n        \"\"\"Check data on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.reduced_data)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(len(output.X), len(self.iris))\n        self.assertEqual(output.domain.class_var, self.iris.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.reduced_data))\n\n    def test_output_scores(self):\n        \"\"\"Check scores on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 2))\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n    def test_output_scores_with_scorer(self):\n        \"\"\"Check scores on the output after apply with scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 5))\n\n    def test_output_features(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.features)\n        self.assertIsInstance(output, AttributeList)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_scoring_method_problem_type(self):\n        \"\"\"Check scoring methods check boxes\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.CLASSIFICATION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.CLASSIFICATION)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.REGRESSION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.REGRESSION)\n\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.UNSUPERVISED)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.UNSUPERVISED)\n\n    def test_scoring_method_defaults(self):\n        \"\"\"Check default scoring methods are selected\"\"\"\n        self.send_signal(self.widget.Inputs.data, None)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        for method in REG_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n    def test_cls_scorer_reg_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 16))\n\n    def test_reg_scorer_cls_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 7))\n\n    def test_scores_updates_cls(self):\n        \"\"\"Check arbitrary workflow with classification data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self._get_checkbox('Gini').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 4))\n        self._get_checkbox('Gini').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 3)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 9))\n\n    def test_scores_updates_reg(self):\n        \"\"\"Check arbitrary workflow with regression data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self._get_checkbox('Univar. reg.').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self._get_checkbox('Univar. reg.').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n    def test_scores_updates_no_class(self):\n        \"\"\"Check arbitrary workflow with no class variable dataset\"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 1))\n\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 7))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 8))\n\n    def test_scores_sorting(self):\n        \"\"\"Check clicking on header column orders scores in a different way\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        order1 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self._get_checkbox('FCBF').setChecked(True)\n        self.widget.ranksView.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder)\n        order2 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self.assertNotEqual(order1, order2)\n\n    def test_scores_nan_sorting(self):\n        \"\"\"Check NaNs are sorted last\"\"\"\n        data = self.iris.copy()\n        data.get_column_view('petal length')[0][:] = np.nan\n        self.send_signal(self.widget.Inputs.data, data)\n\n        # Assert last row is all nan\n        for order in (Qt.AscendingOrder,\n                      Qt.DescendingOrder):\n            self.widget.ranksView.horizontalHeader().setSortIndicator(1, order)\n            last_row = self.widget.ranksModel[self.widget.ranksModel.mapToSourceRows(...)[-1]]\n            np.testing.assert_array_equal(last_row, np.repeat(np.nan, 3))\n\n    def test_default_sort_indicator(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertNotEqual(\n            0, self.widget.ranksView.horizontalHeader().sortIndicatorSection())\n\n    def test_data_which_make_scorer_nan(self):\n        \"\"\"\n        Tests if widget crashes due to too high (Infinite) calculated values.\n        GH-2168\n        \"\"\"\n        table = Table.from_list(\n            Domain(\n                [ContinuousVariable(\"c\")],\n                [DiscreteVariable(\"d\", values=\"01\")]\n            ),\n            # false positive, pylint: disable=invalid-unary-operand-type\n            list(zip(\n                [-np.power(10, 10), 1, 1],\n                [0, 1, 1]\n            )))\n        self.widget.selected_methods.add('ANOVA')\n        self.send_signal(self.widget.Inputs.data, table)\n\n    def test_setting_migration_fixes_header_state(self):\n        # Settings as of version 3.3.5\n        settings = {\n            '__version__': 1,\n            'auto_apply': True,\n            'headerState': (\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xd0\\x00'\n                b'\\x00\\x00\\x08\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xbc\\x00\\x00\\x00\\x07\\x00'\n                b'\\x00\\x00\\x00',\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x01\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xdc\\x00'\n                b'\\x00\\x00\\x03\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xc8\\x00\\x00\\x00\\x02\\x00'\n                b'\\x00\\x00\\x00'),\n            'nSelected': 5,\n            'selectMethod': 3\n        }\n\n        w = self.create_widget(OWRank, stored_settings=settings)\n\n        self.assertEqual(w.sorting, (0, Qt.AscendingOrder))\n\n    def test_auto_send(self):\n        widget = self.widget\n        model = widget.ranksModel\n        selectionModel = widget.ranksView.selectionModel()\n\n        # Auto-send disabled\n        widget.controls.auto_apply.setChecked(False)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Make selection, but auto-send disabled\n        selection = QItemSelection(model.index(1, 0),\n                                   model.index(1, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Enable auto-send: should output data\n        widget.controls.auto_apply.setChecked(True)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal width\"], ))\n\n        # Change selection: should change the output immediately\n        selection = QItemSelection(model.index(0, 0),\n                                   model.index(0, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal length\"], ))\n\n    def test_no_attributes(self):\n        \"\"\"\n        Rank should not fail on data with no attributes.\n        GH-2745\n        \"\"\"\n        data = Table(\"iris\")[::30]\n        domain = Domain(attributes=[], class_vars=data.domain.class_vars)\n        new_data = data.transform(domain)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, new_data)\n        self.assertTrue(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n\n    def test_dataset(self):\n        for method in CLS_SCORES + REG_SCORES:\n            self._get_checkbox(method.shortname).setChecked(True)\n        with patch(\"Orange.widgets.data.owrank.log.warning\"), \\\n                patch(\"Orange.widgets.data.owrank.log.error\"),\\\n                warnings.catch_warnings():\n            warnings.filterwarnings(\"ignore\", \"Features .* are constant\",\n                                    UserWarning)\n            for ds in datasets.datasets():\n                self.send_signal(self.widget.Inputs.data, ds)\n\n    def test_selected_rows(self):\n        w = self.widget\n        self.send_signal(w.Inputs.data, self.iris)\n\n        # select first and second row\n        w.selected_rows = [1, 2]\n        output = self.get_output(w.Outputs.reduced_data)\n\n        self.assertEqual(len(output), len(self.iris))\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n",
            "new_file_content": "import warnings\nimport unittest\nfrom unittest.mock import patch\n\nimport numpy as np\nfrom sklearn.exceptions import ConvergenceWarning\n\nfrom AnyQt.QtCore import Qt, QItemSelection\nfrom AnyQt.QtWidgets import QCheckBox\n\nfrom Orange.data import Table, Domain, ContinuousVariable, DiscreteVariable\nfrom Orange.modelling import RandomForestLearner, SGDLearner\nfrom Orange.preprocess.score import Scorer\nfrom Orange.classification import LogisticRegressionLearner\nfrom Orange.regression import LinearRegressionLearner\nfrom Orange.projection import PCA\nfrom Orange.widgets.data.owrank import OWRank, ProblemType, CLS_SCORES, REG_SCORES\nfrom Orange.widgets.tests.base import WidgetTest, datasets\nfrom Orange.widgets.widget import AttributeList\n\n\nclass TestOWRank(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWRank)  # type: OWRank\n        self.iris = Table(\"iris\")\n        self.housing = Table(\"housing\")\n        self.log_reg = LogisticRegressionLearner()\n        self.lin_reg = LinearRegressionLearner()\n        self.pca = PCA()\n\n    def _get_checkbox(self, method_shortname):\n        return self.widget.controlArea.findChild(QCheckBox, method_shortname)\n\n    def test_input_data(self):\n        \"\"\"Check widget's data with data on the input\"\"\"\n        self.assertEqual(self.widget.data, None)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n\n    def test_input_data_disconnect(self):\n        \"\"\"Check widget's data after disconnecting data on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertEqual(self.widget.data, None)\n\n    def test_input_scorer(self):\n        \"\"\"Check widget's scorer with scorer on the input\"\"\"\n        self.assertEqual(self.widget.scorers, {})\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        value = self.widget.scorers[1]\n        self.assertEqual(self.log_reg, value.scorer)\n        self.assertIsInstance(value.scorer, Scorer)\n\n    def test_input_scorer_fitter(self):\n        heart_disease = Table('heart_disease')\n        self.assertEqual(self.widget.scorers, {})\n\n        model = self.widget.ranksModel\n\n        for fitter, name in ((RandomForestLearner(), 'random forest'),\n                             (SGDLearner(), 'sgd')):\n            with self.subTest(fitter=fitter),\\\n                    warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", \".*\", ConvergenceWarning)\n                self.send_signal(\"Scorer\", fitter, 1)\n\n                for data in (self.housing,\n                             heart_disease):\n                    with self.subTest(data=data.name):\n                        self.send_signal('Data', data)\n                        scores = [model.data(model.index(row, model.columnCount() - 1))\n                                  for row in range(model.rowCount())]\n                        self.assertEqual(len(scores), len(data.domain.attributes))\n                        self.assertFalse(np.isnan(scores).any())\n\n                        last_column = model.headerData(\n                            model.columnCount() - 1, Qt.Horizontal).lower()\n                        self.assertIn(name, last_column)\n\n                self.send_signal(\"Scorer\", None, 1)\n                self.assertEqual(self.widget.scorers, {})\n\n    def test_input_scorer_disconnect(self):\n        \"\"\"Check widget's scorer after disconnecting scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(len(self.widget.scorers), 1)\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.widget.scorers, {})\n\n    def test_output_data(self):\n        \"\"\"Check data on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.reduced_data)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(len(output.X), len(self.iris))\n        self.assertEqual(output.domain.class_var, self.iris.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.reduced_data))\n\n    def test_output_scores(self):\n        \"\"\"Check scores on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 2))\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n    def test_output_scores_with_scorer(self):\n        \"\"\"Check scores on the output after apply with scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 5))\n\n    def test_output_features(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.features)\n        self.assertIsInstance(output, AttributeList)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_scoring_method_problem_type(self):\n        \"\"\"Check scoring methods check boxes\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.CLASSIFICATION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.CLASSIFICATION)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.REGRESSION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.REGRESSION)\n\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.UNSUPERVISED)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.UNSUPERVISED)\n\n    def test_scoring_method_defaults(self):\n        \"\"\"Check default scoring methods are selected\"\"\"\n        self.send_signal(self.widget.Inputs.data, None)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        for method in REG_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n    def test_cls_scorer_reg_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 16))\n\n    def test_reg_scorer_cls_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 7))\n\n    def test_scores_updates_cls(self):\n        \"\"\"Check arbitrary workflow with classification data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self._get_checkbox('Gini').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 4))\n        self._get_checkbox('Gini').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 3)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 9))\n\n    def test_scores_updates_reg(self):\n        \"\"\"Check arbitrary workflow with regression data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self._get_checkbox('Univar. reg.').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self._get_checkbox('Univar. reg.').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n    def test_scores_updates_no_class(self):\n        \"\"\"Check arbitrary workflow with no class variable dataset\"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 1))\n\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 7))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 8))\n\n    def test_no_class_data_learner_class_reg(self):\n        \"\"\"\n        Check workflow with learners that can be both classifier\n        or regressor and data have no class variable. This test should not\n        fail.\n        \"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        random_forest = RandomForestLearner()\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, random_forest, 1)\n            log.assert_called()\n\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 1))\n\n    def test_scores_sorting(self):\n        \"\"\"Check clicking on header column orders scores in a different way\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        order1 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self._get_checkbox('FCBF').setChecked(True)\n        self.widget.ranksView.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder)\n        order2 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self.assertNotEqual(order1, order2)\n\n    def test_scores_nan_sorting(self):\n        \"\"\"Check NaNs are sorted last\"\"\"\n        data = self.iris.copy()\n        data.get_column_view('petal length')[0][:] = np.nan\n        self.send_signal(self.widget.Inputs.data, data)\n\n        # Assert last row is all nan\n        for order in (Qt.AscendingOrder,\n                      Qt.DescendingOrder):\n            self.widget.ranksView.horizontalHeader().setSortIndicator(1, order)\n            last_row = self.widget.ranksModel[self.widget.ranksModel.mapToSourceRows(...)[-1]]\n            np.testing.assert_array_equal(last_row, np.repeat(np.nan, 3))\n\n    def test_default_sort_indicator(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertNotEqual(\n            0, self.widget.ranksView.horizontalHeader().sortIndicatorSection())\n\n    def test_data_which_make_scorer_nan(self):\n        \"\"\"\n        Tests if widget crashes due to too high (Infinite) calculated values.\n        GH-2168\n        \"\"\"\n        table = Table.from_list(\n            Domain(\n                [ContinuousVariable(\"c\")],\n                [DiscreteVariable(\"d\", values=\"01\")]\n            ),\n            # false positive, pylint: disable=invalid-unary-operand-type\n            list(zip(\n                [-np.power(10, 10), 1, 1],\n                [0, 1, 1]\n            )))\n        self.widget.selected_methods.add('ANOVA')\n        self.send_signal(self.widget.Inputs.data, table)\n\n    def test_setting_migration_fixes_header_state(self):\n        # Settings as of version 3.3.5\n        settings = {\n            '__version__': 1,\n            'auto_apply': True,\n            'headerState': (\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xd0\\x00'\n                b'\\x00\\x00\\x08\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xbc\\x00\\x00\\x00\\x07\\x00'\n                b'\\x00\\x00\\x00',\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x01\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xdc\\x00'\n                b'\\x00\\x00\\x03\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xc8\\x00\\x00\\x00\\x02\\x00'\n                b'\\x00\\x00\\x00'),\n            'nSelected': 5,\n            'selectMethod': 3\n        }\n\n        w = self.create_widget(OWRank, stored_settings=settings)\n\n        self.assertEqual(w.sorting, (0, Qt.AscendingOrder))\n\n    def test_auto_send(self):\n        widget = self.widget\n        model = widget.ranksModel\n        selectionModel = widget.ranksView.selectionModel()\n\n        # Auto-send disabled\n        widget.controls.auto_apply.setChecked(False)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Make selection, but auto-send disabled\n        selection = QItemSelection(model.index(1, 0),\n                                   model.index(1, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Enable auto-send: should output data\n        widget.controls.auto_apply.setChecked(True)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal width\"], ))\n\n        # Change selection: should change the output immediately\n        selection = QItemSelection(model.index(0, 0),\n                                   model.index(0, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal length\"], ))\n\n    def test_no_attributes(self):\n        \"\"\"\n        Rank should not fail on data with no attributes.\n        GH-2745\n        \"\"\"\n        data = Table(\"iris\")[::30]\n        domain = Domain(attributes=[], class_vars=data.domain.class_vars)\n        new_data = data.transform(domain)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, new_data)\n        self.assertTrue(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n\n    def test_dataset(self):\n        for method in CLS_SCORES + REG_SCORES:\n            self._get_checkbox(method.shortname).setChecked(True)\n        with patch(\"Orange.widgets.data.owrank.log.warning\"), \\\n                patch(\"Orange.widgets.data.owrank.log.error\"),\\\n                warnings.catch_warnings():\n            warnings.filterwarnings(\"ignore\", \"Features .* are constant\",\n                                    UserWarning)\n            for ds in datasets.datasets():\n                self.send_signal(self.widget.Inputs.data, ds)\n\n    def test_selected_rows(self):\n        w = self.widget\n        self.send_signal(w.Inputs.data, self.iris)\n\n        # select first and second row\n        w.selected_rows = [1, 2]\n        output = self.get_output(w.Outputs.reduced_data)\n\n        self.assertEqual(len(output), len(self.iris))\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n",
            "header": {
                "file": {
                    "path": "Orange/widgets/data/tests/test_owrank.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "050ee3a0e",
                "new_commit_hash": "7a3dba35b",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Orange/widgets/data/tests/test_owrank.py"
            },
            "plus_file": {
                "path": "b/Orange/widgets/data/tests/test_owrank.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 247,
                            "length": 6
                        },
                        "new_range": {
                            "start": 247,
                            "length": 24
                        },
                        "section": "class TestOWRank(WidgetTest):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,",
                                "type": "context"
                            },
                            {
                                "content": "                         (len(self.iris.domain.variables), 8))",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_no_class_data_learner_class_reg(self):",
                                "type": "added"
                            },
                            {
                                "content": "        \"\"\"",
                                "type": "added"
                            },
                            {
                                "content": "        Check workflow with learners that can be both classifier",
                                "type": "added"
                            },
                            {
                                "content": "        or regressor and data have no class variable. This test should not",
                                "type": "added"
                            },
                            {
                                "content": "        fail.",
                                "type": "added"
                            },
                            {
                                "content": "        \"\"\"",
                                "type": "added"
                            },
                            {
                                "content": "        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)",
                                "type": "added"
                            },
                            {
                                "content": "        random_forest = RandomForestLearner()",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertIsNone(data.domain.class_var)",
                                "type": "added"
                            },
                            {
                                "content": "        self.send_signal(self.widget.Inputs.data, data)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        with patch(\"Orange.widgets.data.owrank.log.error\") as log:",
                                "type": "added"
                            },
                            {
                                "content": "            self.send_signal(self.widget.Inputs.scorer, random_forest, 1)",
                                "type": "added"
                            },
                            {
                                "content": "            log.assert_called()",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,",
                                "type": "added"
                            },
                            {
                                "content": "                         (len(self.iris.domain.variables), 1))",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_scores_sorting(self):",
                                "type": "context"
                            },
                            {
                                "content": "        \"\"\"Check clicking on header column orders scores in a different way\"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "        self.send_signal(self.widget.Inputs.data, self.iris)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/widgets/data/tests/test_owrank.py",
                            "type": "class",
                            "name": "TestOWRank",
                            "content": "class TestOWRank(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWRank)  # type: OWRank\n        self.iris = Table(\"iris\")\n        self.housing = Table(\"housing\")\n        self.log_reg = LogisticRegressionLearner()\n        self.lin_reg = LinearRegressionLearner()\n        self.pca = PCA()\n\n    def _get_checkbox(self, method_shortname):\n        return self.widget.controlArea.findChild(QCheckBox, method_shortname)\n\n    def test_input_data(self):\n        \"\"\"Check widget's data with data on the input\"\"\"\n        self.assertEqual(self.widget.data, None)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n\n    def test_input_data_disconnect(self):\n        \"\"\"Check widget's data after disconnecting data on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertEqual(self.widget.data, None)\n\n    def test_input_scorer(self):\n        \"\"\"Check widget's scorer with scorer on the input\"\"\"\n        self.assertEqual(self.widget.scorers, {})\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        value = self.widget.scorers[1]\n        self.assertEqual(self.log_reg, value.scorer)\n        self.assertIsInstance(value.scorer, Scorer)\n\n    def test_input_scorer_fitter(self):\n        heart_disease = Table('heart_disease')\n        self.assertEqual(self.widget.scorers, {})\n\n        model = self.widget.ranksModel\n\n        for fitter, name in ((RandomForestLearner(), 'random forest'),\n                             (SGDLearner(), 'sgd')):\n            with self.subTest(fitter=fitter),\\\n                    warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", \".*\", ConvergenceWarning)\n                self.send_signal(\"Scorer\", fitter, 1)\n\n                for data in (self.housing,\n                             heart_disease):\n                    with self.subTest(data=data.name):\n                        self.send_signal('Data', data)\n                        scores = [model.data(model.index(row, model.columnCount() - 1))\n                                  for row in range(model.rowCount())]\n                        self.assertEqual(len(scores), len(data.domain.attributes))\n                        self.assertFalse(np.isnan(scores).any())\n\n                        last_column = model.headerData(\n                            model.columnCount() - 1, Qt.Horizontal).lower()\n                        self.assertIn(name, last_column)\n\n                self.send_signal(\"Scorer\", None, 1)\n                self.assertEqual(self.widget.scorers, {})\n\n    def test_input_scorer_disconnect(self):\n        \"\"\"Check widget's scorer after disconnecting scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(len(self.widget.scorers), 1)\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.widget.scorers, {})\n\n    def test_output_data(self):\n        \"\"\"Check data on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.reduced_data)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(len(output.X), len(self.iris))\n        self.assertEqual(output.domain.class_var, self.iris.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.reduced_data))\n\n    def test_output_scores(self):\n        \"\"\"Check scores on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 2))\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n    def test_output_scores_with_scorer(self):\n        \"\"\"Check scores on the output after apply with scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 5))\n\n    def test_output_features(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.features)\n        self.assertIsInstance(output, AttributeList)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_scoring_method_problem_type(self):\n        \"\"\"Check scoring methods check boxes\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.CLASSIFICATION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.CLASSIFICATION)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.REGRESSION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.REGRESSION)\n\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.UNSUPERVISED)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.UNSUPERVISED)\n\n    def test_scoring_method_defaults(self):\n        \"\"\"Check default scoring methods are selected\"\"\"\n        self.send_signal(self.widget.Inputs.data, None)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        for method in REG_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n    def test_cls_scorer_reg_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 16))\n\n    def test_reg_scorer_cls_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 7))\n\n    def test_scores_updates_cls(self):\n        \"\"\"Check arbitrary workflow with classification data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self._get_checkbox('Gini').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 4))\n        self._get_checkbox('Gini').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 3)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 9))\n\n    def test_scores_updates_reg(self):\n        \"\"\"Check arbitrary workflow with regression data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self._get_checkbox('Univar. reg.').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self._get_checkbox('Univar. reg.').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n    def test_scores_updates_no_class(self):\n        \"\"\"Check arbitrary workflow with no class variable dataset\"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 1))\n\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 7))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 8))\n\n    def test_no_class_data_learner_class_reg(self):\n        \"\"\"\n        Check workflow with learners that can be both classifier\n        or regressor and data have no class variable. This test should not\n        fail.\n        \"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        random_forest = RandomForestLearner()\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, random_forest, 1)\n            log.assert_called()\n\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 1))\n\n    def test_scores_sorting(self):\n        \"\"\"Check clicking on header column orders scores in a different way\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        order1 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self._get_checkbox('FCBF').setChecked(True)\n        self.widget.ranksView.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder)\n        order2 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self.assertNotEqual(order1, order2)\n\n    def test_scores_nan_sorting(self):\n        \"\"\"Check NaNs are sorted last\"\"\"\n        data = self.iris.copy()\n        data.get_column_view('petal length')[0][:] = np.nan\n        self.send_signal(self.widget.Inputs.data, data)\n\n        # Assert last row is all nan\n        for order in (Qt.AscendingOrder,\n                      Qt.DescendingOrder):\n            self.widget.ranksView.horizontalHeader().setSortIndicator(1, order)\n            last_row = self.widget.ranksModel[self.widget.ranksModel.mapToSourceRows(...)[-1]]\n            np.testing.assert_array_equal(last_row, np.repeat(np.nan, 3))\n\n    def test_default_sort_indicator(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertNotEqual(\n            0, self.widget.ranksView.horizontalHeader().sortIndicatorSection())\n\n    def test_data_which_make_scorer_nan(self):\n        \"\"\"\n        Tests if widget crashes due to too high (Infinite) calculated values.\n        GH-2168\n        \"\"\"\n        table = Table.from_list(\n            Domain(\n                [ContinuousVariable(\"c\")],\n                [DiscreteVariable(\"d\", values=\"01\")]\n            ),\n            # false positive, pylint: disable=invalid-unary-operand-type\n            list(zip(\n                [-np.power(10, 10), 1, 1],\n                [0, 1, 1]\n            )))\n        self.widget.selected_methods.add('ANOVA')\n        self.send_signal(self.widget.Inputs.data, table)\n\n    def test_setting_migration_fixes_header_state(self):\n        # Settings as of version 3.3.5\n        settings = {\n            '__version__': 1,\n            'auto_apply': True,\n            'headerState': (\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xd0\\x00'\n                b'\\x00\\x00\\x08\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xbc\\x00\\x00\\x00\\x07\\x00'\n                b'\\x00\\x00\\x00',\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x01\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xdc\\x00'\n                b'\\x00\\x00\\x03\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xc8\\x00\\x00\\x00\\x02\\x00'\n                b'\\x00\\x00\\x00'),\n            'nSelected': 5,\n            'selectMethod': 3\n        }\n\n        w = self.create_widget(OWRank, stored_settings=settings)\n\n        self.assertEqual(w.sorting, (0, Qt.AscendingOrder))\n\n    def test_auto_send(self):\n        widget = self.widget\n        model = widget.ranksModel\n        selectionModel = widget.ranksView.selectionModel()\n\n        # Auto-send disabled\n        widget.controls.auto_apply.setChecked(False)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Make selection, but auto-send disabled\n        selection = QItemSelection(model.index(1, 0),\n                                   model.index(1, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Enable auto-send: should output data\n        widget.controls.auto_apply.setChecked(True)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal width\"], ))\n\n        # Change selection: should change the output immediately\n        selection = QItemSelection(model.index(0, 0),\n                                   model.index(0, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal length\"], ))\n\n    def test_no_attributes(self):\n        \"\"\"\n        Rank should not fail on data with no attributes.\n        GH-2745\n        \"\"\"\n        data = Table(\"iris\")[::30]\n        domain = Domain(attributes=[], class_vars=data.domain.class_vars)\n        new_data = data.transform(domain)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, new_data)\n        self.assertTrue(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n\n    def test_dataset(self):\n        for method in CLS_SCORES + REG_SCORES:\n            self._get_checkbox(method.shortname).setChecked(True)\n        with patch(\"Orange.widgets.data.owrank.log.warning\"), \\\n                patch(\"Orange.widgets.data.owrank.log.error\"),\\\n                warnings.catch_warnings():\n            warnings.filterwarnings(\"ignore\", \"Features .* are constant\",\n                                    UserWarning)\n            for ds in datasets.datasets():\n                self.send_signal(self.widget.Inputs.data, ds)\n\n    def test_selected_rows(self):\n        w = self.widget\n        self.send_signal(w.Inputs.data, self.iris)\n\n        # select first and second row\n        w.selected_rows = [1, 2]\n        output = self.get_output(w.Outputs.reduced_data)\n\n        self.assertEqual(len(output), len(self.iris))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 22,
                            "end_lineno": 406,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "Orange/widgets/data/tests/test_owrank.py",
                            "type": "method",
                            "name": "TestOWRank.test_no_class_data_learner_class_reg",
                            "content": "class TestOWRank(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWRank)  # type: OWRank\n        self.iris = Table(\"iris\")\n        self.housing = Table(\"housing\")\n        self.log_reg = LogisticRegressionLearner()\n        self.lin_reg = LinearRegressionLearner()\n        self.pca = PCA()\n\n    def _get_checkbox(self, method_shortname):\n        return self.widget.controlArea.findChild(QCheckBox, method_shortname)\n\n    def test_input_data(self):\n        \"\"\"Check widget's data with data on the input\"\"\"\n        self.assertEqual(self.widget.data, None)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n\n    def test_input_data_disconnect(self):\n        \"\"\"Check widget's data after disconnecting data on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertEqual(self.widget.data, None)\n\n    def test_input_scorer(self):\n        \"\"\"Check widget's scorer with scorer on the input\"\"\"\n        self.assertEqual(self.widget.scorers, {})\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        value = self.widget.scorers[1]\n        self.assertEqual(self.log_reg, value.scorer)\n        self.assertIsInstance(value.scorer, Scorer)\n\n    def test_input_scorer_fitter(self):\n        heart_disease = Table('heart_disease')\n        self.assertEqual(self.widget.scorers, {})\n\n        model = self.widget.ranksModel\n\n        for fitter, name in ((RandomForestLearner(), 'random forest'),\n                             (SGDLearner(), 'sgd')):\n            with self.subTest(fitter=fitter),\\\n                    warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", \".*\", ConvergenceWarning)\n                self.send_signal(\"Scorer\", fitter, 1)\n\n                for data in (self.housing,\n                             heart_disease):\n                    with self.subTest(data=data.name):\n                        self.send_signal('Data', data)\n                        scores = [model.data(model.index(row, model.columnCount() - 1))\n                                  for row in range(model.rowCount())]\n                        self.assertEqual(len(scores), len(data.domain.attributes))\n                        self.assertFalse(np.isnan(scores).any())\n\n                        last_column = model.headerData(\n                            model.columnCount() - 1, Qt.Horizontal).lower()\n                        self.assertIn(name, last_column)\n\n                self.send_signal(\"Scorer\", None, 1)\n                self.assertEqual(self.widget.scorers, {})\n\n    def test_input_scorer_disconnect(self):\n        \"\"\"Check widget's scorer after disconnecting scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(len(self.widget.scorers), 1)\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.widget.scorers, {})\n\n    def test_output_data(self):\n        \"\"\"Check data on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.reduced_data)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(len(output.X), len(self.iris))\n        self.assertEqual(output.domain.class_var, self.iris.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.reduced_data))\n\n    def test_output_scores(self):\n        \"\"\"Check scores on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 2))\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n    def test_output_scores_with_scorer(self):\n        \"\"\"Check scores on the output after apply with scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 5))\n\n    def test_output_features(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.features)\n        self.assertIsInstance(output, AttributeList)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_scoring_method_problem_type(self):\n        \"\"\"Check scoring methods check boxes\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.CLASSIFICATION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.CLASSIFICATION)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.REGRESSION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.REGRESSION)\n\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.UNSUPERVISED)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.UNSUPERVISED)\n\n    def test_scoring_method_defaults(self):\n        \"\"\"Check default scoring methods are selected\"\"\"\n        self.send_signal(self.widget.Inputs.data, None)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        for method in REG_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n    def test_cls_scorer_reg_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 16))\n\n    def test_reg_scorer_cls_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 7))\n\n    def test_scores_updates_cls(self):\n        \"\"\"Check arbitrary workflow with classification data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self._get_checkbox('Gini').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 4))\n        self._get_checkbox('Gini').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 3)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 9))\n\n    def test_scores_updates_reg(self):\n        \"\"\"Check arbitrary workflow with regression data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self._get_checkbox('Univar. reg.').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self._get_checkbox('Univar. reg.').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n    def test_scores_updates_no_class(self):\n        \"\"\"Check arbitrary workflow with no class variable dataset\"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 1))\n\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 7))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 8))\n\n    def test_no_class_data_learner_class_reg(self):\n        \"\"\"\n        Check workflow with learners that can be both classifier\n        or regressor and data have no class variable. This test should not\n        fail.\n        \"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        random_forest = RandomForestLearner()\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, random_forest, 1)\n            log.assert_called()\n\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 1))\n\n    def test_scores_sorting(self):\n        \"\"\"Check clicking on header column orders scores in a different way\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        order1 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self._get_checkbox('FCBF').setChecked(True)\n        self.widget.ranksView.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder)\n        order2 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self.assertNotEqual(order1, order2)\n\n    def test_scores_nan_sorting(self):\n        \"\"\"Check NaNs are sorted last\"\"\"\n        data = self.iris.copy()\n        data.get_column_view('petal length')[0][:] = np.nan\n        self.send_signal(self.widget.Inputs.data, data)\n\n        # Assert last row is all nan\n        for order in (Qt.AscendingOrder,\n                      Qt.DescendingOrder):\n            self.widget.ranksView.horizontalHeader().setSortIndicator(1, order)\n            last_row = self.widget.ranksModel[self.widget.ranksModel.mapToSourceRows(...)[-1]]\n            np.testing.assert_array_equal(last_row, np.repeat(np.nan, 3))\n\n    def test_default_sort_indicator(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertNotEqual(\n            0, self.widget.ranksView.horizontalHeader().sortIndicatorSection())\n\n    def test_data_which_make_scorer_nan(self):\n        \"\"\"\n        Tests if widget crashes due to too high (Infinite) calculated values.\n        GH-2168\n        \"\"\"\n        table = Table.from_list(\n            Domain(\n                [ContinuousVariable(\"c\")],\n                [DiscreteVariable(\"d\", values=\"01\")]\n            ),\n            # false positive, pylint: disable=invalid-unary-operand-type\n            list(zip(\n                [-np.power(10, 10), 1, 1],\n                [0, 1, 1]\n            )))\n        self.widget.selected_methods.add('ANOVA')\n        self.send_signal(self.widget.Inputs.data, table)\n\n    def test_setting_migration_fixes_header_state(self):\n        # Settings as of version 3.3.5\n        settings = {\n            '__version__': 1,\n            'auto_apply': True,\n            'headerState': (\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xd0\\x00'\n                b'\\x00\\x00\\x08\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xbc\\x00\\x00\\x00\\x07\\x00'\n                b'\\x00\\x00\\x00',\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x01\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xdc\\x00'\n                b'\\x00\\x00\\x03\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xc8\\x00\\x00\\x00\\x02\\x00'\n                b'\\x00\\x00\\x00'),\n            'nSelected': 5,\n            'selectMethod': 3\n        }\n\n        w = self.create_widget(OWRank, stored_settings=settings)\n\n        self.assertEqual(w.sorting, (0, Qt.AscendingOrder))\n\n    def test_auto_send(self):\n        widget = self.widget\n        model = widget.ranksModel\n        selectionModel = widget.ranksView.selectionModel()\n\n        # Auto-send disabled\n        widget.controls.auto_apply.setChecked(False)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Make selection, but auto-send disabled\n        selection = QItemSelection(model.index(1, 0),\n                                   model.index(1, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Enable auto-send: should output data\n        widget.controls.auto_apply.setChecked(True)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal width\"], ))\n\n        # Change selection: should change the output immediately\n        selection = QItemSelection(model.index(0, 0),\n                                   model.index(0, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal length\"], ))\n\n    def test_no_attributes(self):\n        \"\"\"\n        Rank should not fail on data with no attributes.\n        GH-2745\n        \"\"\"\n        data = Table(\"iris\")[::30]\n        domain = Domain(attributes=[], class_vars=data.domain.class_vars)\n        new_data = data.transform(domain)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, new_data)\n        self.assertTrue(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n\n    def test_dataset(self):\n        for method in CLS_SCORES + REG_SCORES:\n            self._get_checkbox(method.shortname).setChecked(True)\n        with patch(\"Orange.widgets.data.owrank.log.warning\"), \\\n                patch(\"Orange.widgets.data.owrank.log.error\"),\\\n                warnings.catch_warnings():\n            warnings.filterwarnings(\"ignore\", \"Features .* are constant\",\n                                    UserWarning)\n            for ds in datasets.datasets():\n                self.send_signal(self.widget.Inputs.data, ds)\n\n    def test_selected_rows(self):\n        w = self.widget\n        self.send_signal(w.Inputs.data, self.iris)\n\n        # select first and second row\n        w.selected_rows = [1, 2]\n        output = self.get_output(w.Outputs.reduced_data)\n\n        self.assertEqual(len(output), len(self.iris))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 250,
                            "end_lineno": 266,
                            "parent": {
                                "file_name": "Orange/widgets/data/tests/test_owrank.py",
                                "type": "class",
                                "name": "TestOWRank",
                                "content": "class TestOWRank(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWRank)  # type: OWRank\n        self.iris = Table(\"iris\")\n        self.housing = Table(\"housing\")\n        self.log_reg = LogisticRegressionLearner()\n        self.lin_reg = LinearRegressionLearner()\n        self.pca = PCA()\n\n    def _get_checkbox(self, method_shortname):\n        return self.widget.controlArea.findChild(QCheckBox, method_shortname)\n\n    def test_input_data(self):\n        \"\"\"Check widget's data with data on the input\"\"\"\n        self.assertEqual(self.widget.data, None)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n\n    def test_input_data_disconnect(self):\n        \"\"\"Check widget's data after disconnecting data on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertEqual(self.widget.data, None)\n\n    def test_input_scorer(self):\n        \"\"\"Check widget's scorer with scorer on the input\"\"\"\n        self.assertEqual(self.widget.scorers, {})\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        value = self.widget.scorers[1]\n        self.assertEqual(self.log_reg, value.scorer)\n        self.assertIsInstance(value.scorer, Scorer)\n\n    def test_input_scorer_fitter(self):\n        heart_disease = Table('heart_disease')\n        self.assertEqual(self.widget.scorers, {})\n\n        model = self.widget.ranksModel\n\n        for fitter, name in ((RandomForestLearner(), 'random forest'),\n                             (SGDLearner(), 'sgd')):\n            with self.subTest(fitter=fitter),\\\n                    warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", \".*\", ConvergenceWarning)\n                self.send_signal(\"Scorer\", fitter, 1)\n\n                for data in (self.housing,\n                             heart_disease):\n                    with self.subTest(data=data.name):\n                        self.send_signal('Data', data)\n                        scores = [model.data(model.index(row, model.columnCount() - 1))\n                                  for row in range(model.rowCount())]\n                        self.assertEqual(len(scores), len(data.domain.attributes))\n                        self.assertFalse(np.isnan(scores).any())\n\n                        last_column = model.headerData(\n                            model.columnCount() - 1, Qt.Horizontal).lower()\n                        self.assertIn(name, last_column)\n\n                self.send_signal(\"Scorer\", None, 1)\n                self.assertEqual(self.widget.scorers, {})\n\n    def test_input_scorer_disconnect(self):\n        \"\"\"Check widget's scorer after disconnecting scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(len(self.widget.scorers), 1)\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.widget.scorers, {})\n\n    def test_output_data(self):\n        \"\"\"Check data on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.reduced_data)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(len(output.X), len(self.iris))\n        self.assertEqual(output.domain.class_var, self.iris.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.reduced_data))\n\n    def test_output_scores(self):\n        \"\"\"Check scores on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 2))\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n    def test_output_scores_with_scorer(self):\n        \"\"\"Check scores on the output after apply with scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 5))\n\n    def test_output_features(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.features)\n        self.assertIsInstance(output, AttributeList)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_scoring_method_problem_type(self):\n        \"\"\"Check scoring methods check boxes\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.CLASSIFICATION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.CLASSIFICATION)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.REGRESSION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.REGRESSION)\n\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.UNSUPERVISED)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.UNSUPERVISED)\n\n    def test_scoring_method_defaults(self):\n        \"\"\"Check default scoring methods are selected\"\"\"\n        self.send_signal(self.widget.Inputs.data, None)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        for method in REG_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n    def test_cls_scorer_reg_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 16))\n\n    def test_reg_scorer_cls_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 7))\n\n    def test_scores_updates_cls(self):\n        \"\"\"Check arbitrary workflow with classification data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self._get_checkbox('Gini').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 4))\n        self._get_checkbox('Gini').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 3)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 9))\n\n    def test_scores_updates_reg(self):\n        \"\"\"Check arbitrary workflow with regression data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self._get_checkbox('Univar. reg.').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self._get_checkbox('Univar. reg.').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n    def test_scores_updates_no_class(self):\n        \"\"\"Check arbitrary workflow with no class variable dataset\"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 1))\n\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 7))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 8))\n\n    def test_no_class_data_learner_class_reg(self):\n        \"\"\"\n        Check workflow with learners that can be both classifier\n        or regressor and data have no class variable. This test should not\n        fail.\n        \"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        random_forest = RandomForestLearner()\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, random_forest, 1)\n            log.assert_called()\n\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 1))\n\n    def test_scores_sorting(self):\n        \"\"\"Check clicking on header column orders scores in a different way\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        order1 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self._get_checkbox('FCBF').setChecked(True)\n        self.widget.ranksView.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder)\n        order2 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self.assertNotEqual(order1, order2)\n\n    def test_scores_nan_sorting(self):\n        \"\"\"Check NaNs are sorted last\"\"\"\n        data = self.iris.copy()\n        data.get_column_view('petal length')[0][:] = np.nan\n        self.send_signal(self.widget.Inputs.data, data)\n\n        # Assert last row is all nan\n        for order in (Qt.AscendingOrder,\n                      Qt.DescendingOrder):\n            self.widget.ranksView.horizontalHeader().setSortIndicator(1, order)\n            last_row = self.widget.ranksModel[self.widget.ranksModel.mapToSourceRows(...)[-1]]\n            np.testing.assert_array_equal(last_row, np.repeat(np.nan, 3))\n\n    def test_default_sort_indicator(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertNotEqual(\n            0, self.widget.ranksView.horizontalHeader().sortIndicatorSection())\n\n    def test_data_which_make_scorer_nan(self):\n        \"\"\"\n        Tests if widget crashes due to too high (Infinite) calculated values.\n        GH-2168\n        \"\"\"\n        table = Table.from_list(\n            Domain(\n                [ContinuousVariable(\"c\")],\n                [DiscreteVariable(\"d\", values=\"01\")]\n            ),\n            # false positive, pylint: disable=invalid-unary-operand-type\n            list(zip(\n                [-np.power(10, 10), 1, 1],\n                [0, 1, 1]\n            )))\n        self.widget.selected_methods.add('ANOVA')\n        self.send_signal(self.widget.Inputs.data, table)\n\n    def test_setting_migration_fixes_header_state(self):\n        # Settings as of version 3.3.5\n        settings = {\n            '__version__': 1,\n            'auto_apply': True,\n            'headerState': (\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xd0\\x00'\n                b'\\x00\\x00\\x08\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xbc\\x00\\x00\\x00\\x07\\x00'\n                b'\\x00\\x00\\x00',\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x01\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xdc\\x00'\n                b'\\x00\\x00\\x03\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xc8\\x00\\x00\\x00\\x02\\x00'\n                b'\\x00\\x00\\x00'),\n            'nSelected': 5,\n            'selectMethod': 3\n        }\n\n        w = self.create_widget(OWRank, stored_settings=settings)\n\n        self.assertEqual(w.sorting, (0, Qt.AscendingOrder))\n\n    def test_auto_send(self):\n        widget = self.widget\n        model = widget.ranksModel\n        selectionModel = widget.ranksView.selectionModel()\n\n        # Auto-send disabled\n        widget.controls.auto_apply.setChecked(False)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Make selection, but auto-send disabled\n        selection = QItemSelection(model.index(1, 0),\n                                   model.index(1, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Enable auto-send: should output data\n        widget.controls.auto_apply.setChecked(True)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal width\"], ))\n\n        # Change selection: should change the output immediately\n        selection = QItemSelection(model.index(0, 0),\n                                   model.index(0, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal length\"], ))\n\n    def test_no_attributes(self):\n        \"\"\"\n        Rank should not fail on data with no attributes.\n        GH-2745\n        \"\"\"\n        data = Table(\"iris\")[::30]\n        domain = Domain(attributes=[], class_vars=data.domain.class_vars)\n        new_data = data.transform(domain)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, new_data)\n        self.assertTrue(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n\n    def test_dataset(self):\n        for method in CLS_SCORES + REG_SCORES:\n            self._get_checkbox(method.shortname).setChecked(True)\n        with patch(\"Orange.widgets.data.owrank.log.warning\"), \\\n                patch(\"Orange.widgets.data.owrank.log.error\"),\\\n                warnings.catch_warnings():\n            warnings.filterwarnings(\"ignore\", \"Features .* are constant\",\n                                    UserWarning)\n            for ds in datasets.datasets():\n                self.send_signal(self.widget.Inputs.data, ds)\n\n    def test_selected_rows(self):\n        w = self.widget\n        self.send_signal(w.Inputs.data, self.iris)\n\n        # select first and second row\n        w.selected_rows = [1, 2]\n        output = self.get_output(w.Outputs.reduced_data)\n\n        self.assertEqual(len(output), len(self.iris))",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 22,
                                "end_lineno": 406,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "14c32060dfeb30ed0c16ffb17794a39ee0f93706^",
    "new_commit_hash": "14c32060dfeb30ed0c16ffb17794a39ee0f93706",
    "commit_message": "Merge pull request #4457 from PrimozGodec/rank-fix\n\n[FIX] Rank: Fix error with Random forest",
    "commit_date": "2020-02-26T17:31:20+01:00",
    "metadata": {}
}
{
    "repo_name": "orange3",
    "new_commit_hash": "14c32060dfeb30ed0c16ffb17794a39ee0f93706",
    "test_file_codes": [
        "import warnings\nimport unittest\nfrom unittest.mock import patch\n\nimport numpy as np\nfrom sklearn.exceptions import ConvergenceWarning\n\nfrom AnyQt.QtCore import Qt, QItemSelection\nfrom AnyQt.QtWidgets import QCheckBox\n\nfrom Orange.data import Table, Domain, ContinuousVariable, DiscreteVariable\nfrom Orange.modelling import RandomForestLearner, SGDLearner\nfrom Orange.preprocess.score import Scorer\nfrom Orange.classification import LogisticRegressionLearner\nfrom Orange.regression import LinearRegressionLearner\nfrom Orange.projection import PCA\nfrom Orange.widgets.data.owrank import OWRank, ProblemType, CLS_SCORES, REG_SCORES\nfrom Orange.widgets.tests.base import WidgetTest, datasets\nfrom Orange.widgets.widget import AttributeList\n\n\nclass TestOWRank(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWRank)  # type: OWRank\n        self.iris = Table(\"iris\")\n        self.housing = Table(\"housing\")\n        self.log_reg = LogisticRegressionLearner()\n        self.lin_reg = LinearRegressionLearner()\n        self.pca = PCA()\n\n    def _get_checkbox(self, method_shortname):\n        return self.widget.controlArea.findChild(QCheckBox, method_shortname)\n\n    def test_input_data(self):\n        \"\"\"Check widget's data with data on the input\"\"\"\n        self.assertEqual(self.widget.data, None)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n\n    def test_input_data_disconnect(self):\n        \"\"\"Check widget's data after disconnecting data on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.data, self.iris)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertEqual(self.widget.data, None)\n\n    def test_input_scorer(self):\n        \"\"\"Check widget's scorer with scorer on the input\"\"\"\n        self.assertEqual(self.widget.scorers, {})\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        value = self.widget.scorers[1]\n        self.assertEqual(self.log_reg, value.scorer)\n        self.assertIsInstance(value.scorer, Scorer)\n\n    def test_input_scorer_fitter(self):\n        heart_disease = Table('heart_disease')\n        self.assertEqual(self.widget.scorers, {})\n\n        model = self.widget.ranksModel\n\n        for fitter, name in ((RandomForestLearner(), 'random forest'),\n                             (SGDLearner(), 'sgd')):\n            with self.subTest(fitter=fitter),\\\n                    warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", \".*\", ConvergenceWarning)\n                self.send_signal(\"Scorer\", fitter, 1)\n\n                for data in (self.housing,\n                             heart_disease):\n                    with self.subTest(data=data.name):\n                        self.send_signal('Data', data)\n                        scores = [model.data(model.index(row, model.columnCount() - 1))\n                                  for row in range(model.rowCount())]\n                        self.assertEqual(len(scores), len(data.domain.attributes))\n                        self.assertFalse(np.isnan(scores).any())\n\n                        last_column = model.headerData(\n                            model.columnCount() - 1, Qt.Horizontal).lower()\n                        self.assertIn(name, last_column)\n\n                self.send_signal(\"Scorer\", None, 1)\n                self.assertEqual(self.widget.scorers, {})\n\n    def test_input_scorer_disconnect(self):\n        \"\"\"Check widget's scorer after disconnecting scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(len(self.widget.scorers), 1)\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.widget.scorers, {})\n\n    def test_output_data(self):\n        \"\"\"Check data on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.reduced_data)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(len(output.X), len(self.iris))\n        self.assertEqual(output.domain.class_var, self.iris.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.reduced_data))\n\n    def test_output_scores(self):\n        \"\"\"Check scores on the output after apply\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 2))\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n    def test_output_scores_with_scorer(self):\n        \"\"\"Check scores on the output after apply with scorer on the input\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        output = self.get_output(self.widget.Outputs.scores)\n        self.assertIsInstance(output, Table)\n        self.assertEqual(output.X.shape, (len(self.iris.domain.attributes), 5))\n\n    def test_output_features(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        output = self.get_output(self.widget.Outputs.features)\n        self.assertIsInstance(output, AttributeList)\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_scoring_method_problem_type(self):\n        \"\"\"Check scoring methods check boxes\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.CLASSIFICATION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.CLASSIFICATION)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.REGRESSION)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.REGRESSION)\n\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertEqual(self.widget.problem_type_mode, ProblemType.UNSUPERVISED)\n        self.assertEqual(self.widget.measuresStack.currentIndex(), ProblemType.UNSUPERVISED)\n\n    def test_scoring_method_defaults(self):\n        \"\"\"Check default scoring methods are selected\"\"\"\n        self.send_signal(self.widget.Inputs.data, None)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        for method in REG_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        for method in CLS_SCORES:\n            checkbox = self._get_checkbox(method.shortname)\n            self.assertEqual(checkbox.isChecked(), method.is_default)\n\n    def test_cls_scorer_reg_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 16))\n\n    def test_reg_scorer_cls_data(self):\n        \"\"\"Check scores on the output with inadequate scorer\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 7))\n\n    def test_scores_updates_cls(self):\n        \"\"\"Check arbitrary workflow with classification data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self._get_checkbox('Gini').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 4))\n        self._get_checkbox('Gini').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 2)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 5))\n        self.send_signal(self.widget.Inputs.scorer, self.log_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 8))\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 3)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.attributes), 9))\n\n    def test_scores_updates_reg(self):\n        \"\"\"Check arbitrary workflow with regression data\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.housing)\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self._get_checkbox('Univar. reg.').setChecked(False)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self._get_checkbox('Univar. reg.').setChecked(True)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n        self.send_signal(self.widget.Inputs.scorer, None, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 2))\n\n        self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.housing.domain.attributes), 3))\n\n    def test_scores_updates_no_class(self):\n        \"\"\"Check arbitrary workflow with no class variable dataset\"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertIsNone(self.get_output(self.widget.Outputs.scores))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 1)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 1))\n\n        self.send_signal(self.widget.Inputs.scorer, self.pca, 1)\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 7))\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, self.lin_reg, 2)\n            log.assert_called()\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 8))\n\n    def test_no_class_data_learner_class_reg(self):\n        \"\"\"\n        Check workflow with learners that can be both classifier\n        or regressor and data have no class variable. This test should not\n        fail.\n        \"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        random_forest = RandomForestLearner()\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n\n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n            self.send_signal(self.widget.Inputs.scorer, random_forest, 1)\n            log.assert_called()\n\n        self.assertEqual(self.get_output(self.widget.Outputs.scores).X.shape,\n                         (len(self.iris.domain.variables), 1))\n\n    def test_scores_sorting(self):\n        \"\"\"Check clicking on header column orders scores in a different way\"\"\"\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        order1 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self._get_checkbox('FCBF').setChecked(True)\n        self.widget.ranksView.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder)\n        order2 = self.widget.ranksModel.mapToSourceRows(...).tolist()\n        self.assertNotEqual(order1, order2)\n\n    def test_scores_nan_sorting(self):\n        \"\"\"Check NaNs are sorted last\"\"\"\n        data = self.iris.copy()\n        data.get_column_view('petal length')[0][:] = np.nan\n        self.send_signal(self.widget.Inputs.data, data)\n\n        # Assert last row is all nan\n        for order in (Qt.AscendingOrder,\n                      Qt.DescendingOrder):\n            self.widget.ranksView.horizontalHeader().setSortIndicator(1, order)\n            last_row = self.widget.ranksModel[self.widget.ranksModel.mapToSourceRows(...)[-1]]\n            np.testing.assert_array_equal(last_row, np.repeat(np.nan, 3))\n\n    def test_default_sort_indicator(self):\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertNotEqual(\n            0, self.widget.ranksView.horizontalHeader().sortIndicatorSection())\n\n    def test_data_which_make_scorer_nan(self):\n        \"\"\"\n        Tests if widget crashes due to too high (Infinite) calculated values.\n        GH-2168\n        \"\"\"\n        table = Table.from_list(\n            Domain(\n                [ContinuousVariable(\"c\")],\n                [DiscreteVariable(\"d\", values=\"01\")]\n            ),\n            # false positive, pylint: disable=invalid-unary-operand-type\n            list(zip(\n                [-np.power(10, 10), 1, 1],\n                [0, 1, 1]\n            )))\n        self.widget.selected_methods.add('ANOVA')\n        self.send_signal(self.widget.Inputs.data, table)\n\n    def test_setting_migration_fixes_header_state(self):\n        # Settings as of version 3.3.5\n        settings = {\n            '__version__': 1,\n            'auto_apply': True,\n            'headerState': (\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xd0\\x00'\n                b'\\x00\\x00\\x08\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\xbc\\x00\\x00\\x00\\x07\\x00'\n                b'\\x00\\x00\\x00',\n                b'\\x00\\x00\\x00\\xff\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x00'\n                b'\\x00\\x01\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xdc\\x00'\n                b'\\x00\\x00\\x03\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00d\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x84\\x00'\n                b'\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x14\\x00\\x00\\x00'\n                b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xc8\\x00\\x00\\x00\\x02\\x00'\n                b'\\x00\\x00\\x00'),\n            'nSelected': 5,\n            'selectMethod': 3\n        }\n\n        w = self.create_widget(OWRank, stored_settings=settings)\n\n        self.assertEqual(w.sorting, (0, Qt.AscendingOrder))\n\n    def test_auto_send(self):\n        widget = self.widget\n        model = widget.ranksModel\n        selectionModel = widget.ranksView.selectionModel()\n\n        # Auto-send disabled\n        widget.controls.auto_apply.setChecked(False)\n        self.send_signal(self.widget.Inputs.data, self.iris)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Make selection, but auto-send disabled\n        selection = QItemSelection(model.index(1, 0),\n                                   model.index(1, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        self.assertIsNone(self.get_output(widget.Outputs.reduced_data))\n\n        # Enable auto-send: should output data\n        widget.controls.auto_apply.setChecked(True)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal width\"], ))\n\n        # Change selection: should change the output immediately\n        selection = QItemSelection(model.index(0, 0),\n                                   model.index(0, model.columnCount() - 1))\n        selectionModel.select(selection, selectionModel.ClearAndSelect)\n        reduced_data = self.get_output(widget.Outputs.reduced_data)\n        self.assertEqual(reduced_data.domain.attributes,\n                         (self.iris.domain[\"petal length\"], ))\n\n    def test_no_attributes(self):\n        \"\"\"\n        Rank should not fail on data with no attributes.\n        GH-2745\n        \"\"\"\n        data = Table(\"iris\")[::30]\n        domain = Domain(attributes=[], class_vars=data.domain.class_vars)\n        new_data = data.transform(domain)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, new_data)\n        self.assertTrue(self.widget.Error.no_attributes.is_shown())\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertFalse(self.widget.Error.no_attributes.is_shown())\n\n    def test_dataset(self):\n        for method in CLS_SCORES + REG_SCORES:\n            self._get_checkbox(method.shortname).setChecked(True)\n        with patch(\"Orange.widgets.data.owrank.log.warning\"), \\\n                patch(\"Orange.widgets.data.owrank.log.error\"),\\\n                warnings.catch_warnings():\n            warnings.filterwarnings(\"ignore\", \"Features .* are constant\",\n                                    UserWarning)\n            for ds in datasets.datasets():\n                self.send_signal(self.widget.Inputs.data, ds)\n\n    def test_selected_rows(self):\n        w = self.widget\n        self.send_signal(w.Inputs.data, self.iris)\n\n        # select first and second row\n        w.selected_rows = [1, 2]\n        output = self.get_output(w.Outputs.reduced_data)\n\n        self.assertEqual(len(output), len(self.iris))\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Starting Orange installation attempts...\nAttempting installation with Python 3.7...\nrunning build_ext\nrunning build_src\nbuild_src\nbuilding extension \"Orange.classification._simple_tree\" sources\nbuilding extension \"Orange.classification._tree_scorers\" sources\nbuilding extension \"Orange.data._valuecount\" sources\nbuilding extension \"Orange.data._contingency\" sources\nbuilding extension \"Orange.data._io\" sources\nbuilding extension \"Orange.data._variable\" sources\nbuilding extension \"Orange.distance._distance\" sources\nbuilding extension \"Orange.preprocess._discretize\" sources\nbuilding extension \"Orange.preprocess._relieff\" sources\nbuilding extension \"Orange.projection._som\" sources\nbuilding extension \"Orange.widgets.utils._grid_density\" sources\nbuild_src: building npy-pkg config files\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmpjllyk1sv/tmp\ncreating /tmp/tmpjllyk1sv/tmp/tmpjllyk1sv\ncompile options: '-MMD -MF /tmp/tmpjllyk1sv/file.c.d -c'\ncc: /tmp/tmpjllyk1sv/file.c\ncustomize UnixCCompiler using build_ext\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmpidfyzn1u/tmp\ncreating /tmp/tmpidfyzn1u/tmp/tmpidfyzn1u\ncompile options: '-MMD -MF /tmp/tmpidfyzn1u/file.c.d -c'\ncc: /tmp/tmpidfyzn1u/file.c\ncustomize UnixCCompiler using build_ext\nbuilding 'Orange.classification._simple_tree' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange\ncreating build/temp.linux-x86_64-3.7/Orange/classification\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/classification/_simple_tree.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/classification/_simple_tree.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/classification/_simple_tree.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.classification._tree_scorers' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/classification/_tree_scorers.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/classification/_tree_scorers.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/classification/_tree_scorers.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._valuecount' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/data\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_valuecount.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_valuecount.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_valuecount.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._contingency' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_contingency.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_contingency.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_contingency.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._io' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_io.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_io.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_io.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._variable' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/data/_variable.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_variable.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/data/_variable.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.distance._distance' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/distance\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/distance/_distance.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/distance/_distance.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/distance/_distance.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._discretize' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/preprocess\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/preprocess/_discretize.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/preprocess/_discretize.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/preprocess/_discretize.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._relieff' extension\ncompiling C++ sources\nC compiler: c++ -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\nc++: Orange/preprocess/_relieff.cpp\nc++ -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/preprocess/_relieff.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/preprocess/_relieff.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.projection._som' extension\ncompiling C sources\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/projection\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\ncc: Orange/projection/_som.c\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/projection/_som.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/projection/_som.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.widgets.utils._grid_density' extension\ncompiling C++ sources\nC compiler: c++ -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating build/temp.linux-x86_64-3.7/Orange/widgets\ncreating build/temp.linux-x86_64-3.7/Orange/widgets/utils\ncompile options: '-I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c'\nc++: Orange/widgets/utils/_grid_density.cpp\nc++ -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o Orange/widgets/utils/_grid_density.cpython-37m-x86_64-linux-gnu.so\nrunning develop\nrunning build_scripts\nrunning egg_info\nrunning build_src\nbuild_src\nbuilding extension \"Orange.classification._simple_tree\" sources\nbuilding extension \"Orange.classification._tree_scorers\" sources\nbuilding extension \"Orange.data._valuecount\" sources\nbuilding extension \"Orange.data._contingency\" sources\nbuilding extension \"Orange.data._io\" sources\nbuilding extension \"Orange.data._variable\" sources\nbuilding extension \"Orange.distance._distance\" sources\nbuilding extension \"Orange.preprocess._discretize\" sources\nbuilding extension \"Orange.preprocess._relieff\" sources\nbuilding extension \"Orange.projection._som\" sources\nbuilding extension \"Orange.widgets.utils._grid_density\" sources\nbuild_src: building npy-pkg config files\ncreating Orange3.egg-info\nwriting Orange3.egg-info/PKG-INFO\nwriting dependency_links to Orange3.egg-info/dependency_links.txt\nwriting entry points to Orange3.egg-info/entry_points.txt\nwriting requirements to Orange3.egg-info/requires.txt\nwriting top-level names to Orange3.egg-info/top_level.txt\nwriting manifest file 'Orange3.egg-info/SOURCES.txt'\nreading manifest file 'Orange3.egg-info/SOURCES.txt'\nreading manifest template 'MANIFEST.in'\nwarning: no files found matching 'README*' under directory 'Orange'\nwarning: no files found matching 'LICENSE' under directory 'Orange'\nwarning: no files found matching '*.basket' under directory 'Orange/datasets'\nwarning: no files found matching '*.js' under directory 'Orange/widgets'\nwarning: no files found matching '*.css' under directory 'Orange/widgets'\nwarning: no files found matching '*.html' under directory 'Orange/widgets'\nwarning: no files found matching 'COPYING'\nadding license file 'LICENSE'\nwriting manifest file 'Orange3.egg-info/SOURCES.txt'\nrunning build_ext\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmp2h_4ylq4/tmp\ncreating /tmp/tmp2h_4ylq4/tmp/tmp2h_4ylq4\ncompile options: '-MMD -MF /tmp/tmp2h_4ylq4/file.c.d -c'\ncc: /tmp/tmp2h_4ylq4/file.c\ncustomize UnixCCompiler using build_ext\ncustomize UnixCCompiler\nC compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC\n\ncreating /tmp/tmpzbyb1jvx/tmp\ncreating /tmp/tmpzbyb1jvx/tmp/tmpzbyb1jvx\ncompile options: '-MMD -MF /tmp/tmpzbyb1jvx/file.c.d -c'\ncc: /tmp/tmpzbyb1jvx/file.c\ncustomize UnixCCompiler using build_ext\nCreating /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/Orange3.egg-link (link to .)\nAdding Orange3 3.25.0.dev0+14c3206 to easy-install.pth file\nInstalling orange-canvas script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\n\nInstalled /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706\nProcessing dependencies for Orange3==3.25.0.dev0+14c3206\nSearching for XlsxWriter==3.2.0\nBest match: XlsxWriter 3.2.0\nAdding XlsxWriter 3.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for xlrd==2.0.1\nBest match: xlrd 2.0.1\nAdding xlrd 2.0.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for setuptools==59.8.0\nBest match: setuptools 59.8.0\nAdding setuptools 59.8.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for serverfiles==0.3.1\nBest match: serverfiles 0.3.1\nAdding serverfiles 0.3.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for scipy==1.7.3\nBest match: scipy 1.7.3\nAdding scipy 1.7.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for scikit-learn==1.0.2\nBest match: scikit-learn 1.0.2\nAdding scikit-learn 1.0.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for requests==2.31.0\nBest match: requests 2.31.0\nAdding requests 2.31.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for PyYAML==6.0.1\nBest match: PyYAML 6.0.1\nAdding PyYAML 6.0.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for python-louvain==0.16\nBest match: python-louvain 0.16\nAdding python-louvain 0.16 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for pyqtgraph==0.10.0\nBest match: pyqtgraph 0.10.0\nAdding pyqtgraph 0.10.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for pip==24.0\nBest match: pip 24.0\nAdding pip 24.0 to easy-install.pth file\nInstalling pip script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\nInstalling pip3 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\nInstalling pip3.10 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for pandas==1.3.5\nBest match: pandas 1.3.5\nAdding pandas 1.3.5 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for orange-widget-base==4.22.0\nBest match: orange-widget-base 4.22.0\nAdding orange-widget-base 4.22.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for orange-canvas-core==0.1.35\nBest match: orange-canvas-core 0.1.35\nAdding orange-canvas-core 0.1.35 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for openpyxl==3.1.3\nBest match: openpyxl 3.1.3\nAdding openpyxl 3.1.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for openTSNE==1.0.1\nBest match: openTSNE 1.0.1\nAdding openTSNE 1.0.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for numpy==1.17.5\nBest match: numpy 1.17.5\nAdding numpy 1.17.5 to easy-install.pth file\nInstalling f2py script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\nInstalling f2py3 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\nInstalling f2py3.7 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for networkx==2.6.3\nBest match: networkx 2.6.3\nAdding networkx 2.6.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for matplotlib==3.5.3\nBest match: matplotlib 3.5.3\nAdding matplotlib 3.5.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for keyrings.alt==4.2.0\nBest match: keyrings.alt 4.2.0\nAdding keyrings.alt 4.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for keyring==24.1.1\nBest match: keyring 24.1.1\nAdding keyring 24.1.1 to easy-install.pth file\nInstalling keyring script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for joblib==1.3.2\nBest match: joblib 1.3.2\nAdding joblib 1.3.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for docutils==0.20.1\nBest match: docutils 0.20.1\nAdding docutils 0.20.1 to easy-install.pth file\nInstalling docutils script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for chardet==5.2.0\nBest match: chardet 5.2.0\nAdding chardet 5.2.0 to easy-install.pth file\nInstalling chardetect script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for Bottleneck==1.4.0\nBest match: Bottleneck 1.4.0\nAdding Bottleneck 1.4.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for baycomp==1.0.3\nBest match: baycomp 1.0.3\nAdding baycomp 1.0.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for AnyQt==0.2.0\nBest match: AnyQt 0.2.0\nAdding AnyQt 0.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for threadpoolctl==3.1.0\nBest match: threadpoolctl 3.1.0\nAdding threadpoolctl 3.1.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for certifi==2024.12.14\nBest match: certifi 2024.12.14\nAdding certifi 2024.12.14 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for idna==3.10\nBest match: idna 3.10\nAdding idna 3.10 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for charset-normalizer==3.4.1\nBest match: charset-normalizer 3.4.1\nAdding charset-normalizer 3.4.1 to easy-install.pth file\nInstalling normalizer script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for urllib3==2.0.7\nBest match: urllib3 2.0.7\nAdding urllib3 2.0.7 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for pytz==2024.2\nBest match: pytz 2024.2\nAdding pytz 2024.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for python-dateutil==2.9.0.post0\nBest match: python-dateutil 2.9.0.post0\nAdding python-dateutil 2.9.0.post0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for typing-extensions==4.7.1\nBest match: typing-extensions 4.7.1\nAdding typing-extensions 4.7.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for importlib-metadata==6.7.0\nBest match: importlib-metadata 6.7.0\nAdding importlib-metadata 6.7.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for packaging==24.0\nBest match: packaging 24.0\nAdding packaging 24.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for dictdiffer==0.9.0\nBest match: dictdiffer 0.9.0\nAdding dictdiffer 0.9.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for requests-cache==1.1.1\nBest match: requests-cache 1.1.1\nAdding requests-cache 1.1.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for commonmark==0.9.1\nBest match: commonmark 0.9.1\nAdding commonmark 0.9.1 to easy-install.pth file\nInstalling cmark script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for qasync==0.25.0\nBest match: qasync 0.25.0\nAdding qasync 0.25.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for et-xmlfile==1.1.0\nBest match: et-xmlfile 1.1.0\nAdding et-xmlfile 1.1.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for fonttools==4.38.0\nBest match: fonttools 4.38.0\nAdding fonttools 4.38.0 to easy-install.pth file\nInstalling fonttools script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\nInstalling pyftmerge script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\nInstalling pyftsubset script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\nInstalling ttx script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for Pillow==9.5.0\nBest match: Pillow 9.5.0\nAdding Pillow 9.5.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for pyparsing==3.1.4\nBest match: pyparsing 3.1.4\nAdding pyparsing 3.1.4 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for cycler==0.11.0\nBest match: cycler 0.11.0\nAdding cycler 0.11.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for kiwisolver==1.4.5\nBest match: kiwisolver 1.4.5\nAdding kiwisolver 1.4.5 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for jaraco.classes==3.2.3\nBest match: jaraco.classes 3.2.3\nAdding jaraco.classes 3.2.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for importlib-resources==5.12.0\nBest match: importlib-resources 5.12.0\nAdding importlib-resources 5.12.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for jeepney==0.8.0\nBest match: jeepney 0.8.0\nAdding jeepney 0.8.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for SecretStorage==3.3.3\nBest match: SecretStorage 3.3.3\nAdding SecretStorage 3.3.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for six==1.17.0\nBest match: six 1.17.0\nAdding six 1.17.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for zipp==3.15.0\nBest match: zipp 3.15.0\nAdding zipp 3.15.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for attrs==24.2.0\nBest match: attrs 24.2.0\nAdding attrs 24.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for cattrs==23.1.2\nBest match: cattrs 23.1.2\nAdding cattrs 23.1.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for platformdirs==4.0.0\nBest match: platformdirs 4.0.0\nAdding platformdirs 4.0.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for url-normalize==1.4.3\nBest match: url-normalize 1.4.3\nAdding url-normalize 1.4.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for more-itertools==9.1.0\nBest match: more-itertools 9.1.0\nAdding more-itertools 9.1.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for cryptography==44.0.0\nBest match: cryptography 44.0.0\nAdding cryptography 44.0.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for exceptiongroup==1.2.2\nBest match: exceptiongroup 1.2.2\nAdding exceptiongroup 1.2.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for cffi==1.15.1\nBest match: cffi 1.15.1\nAdding cffi 1.15.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nSearching for pycparser==2.21\nBest match: pycparser 2.21\nAdding pycparser 2.21 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages\nFinished processing dependencies for Orange3==3.25.0.dev0+14c3206\nVerifying Orange installation...\n✅ Orange installation successful!\nSuccessfully installed orange using Python 3.7\n",
    "setup_res_stderr": "Using CPython 3.7.9\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 18 packages in 111ms\nPrepared 18 packages in 14ms\nInstalled 18 packages in 142ms\n + cython==0.29.37\n + exceptiongroup==1.2.2\n + importlib-metadata==6.7.0\n + iniconfig==2.0.0\n + numpy==1.17.5\n + packaging==24.0\n + pluggy==1.2.0\n + pyqt5==5.15.10\n + pyqt5-qt5==5.15.16\n + pyqt5-sip==12.13.0\n + pyqtwebengine==5.15.6\n + pyqtwebengine-qt5==5.15.16\n + pytest==7.4.4\n + setuptools==59.8.0\n + tomli==2.0.1\n + typing-extensions==4.7.1\n + wheel==0.42.0\n + zipp==3.15.0\nResolved 48 packages in 268ms\nInstalled 42 packages in 329ms\n + baycomp==1.0.3\n + bottleneck==1.4.0\n + certifi==2024.12.14\n + cffi==1.15.1\n + chardet==5.2.0\n + charset-normalizer==3.4.1\n + cryptography==44.0.0\n + cycler==0.11.0\n + et-xmlfile==1.1.0\n + fonttools==4.38.0\n + idna==3.10\n + importlib-resources==5.12.0\n + jaraco-classes==3.2.3\n + jeepney==0.8.0\n + joblib==1.3.2\n + keyring==24.1.1\n + keyrings-alt==4.2.0\n + kiwisolver==1.4.5\n + matplotlib==3.5.3\n + more-itertools==9.1.0\n + networkx==2.6.3\n + openpyxl==3.1.3\n + opentsne==1.0.1\n + pandas==1.3.5\n + pillow==9.5.0\n + pip==24.0\n + pycparser==2.21\n + pyparsing==3.1.4\n + python-dateutil==2.9.0.post0\n + python-louvain==0.16\n + pytz==2024.2\n + pyyaml==6.0.1\n + requests==2.31.0\n + scikit-learn==1.0.2\n + scipy==1.7.3\n + secretstorage==3.3.3\n + serverfiles==0.3.1\n + six==1.17.0\n + threadpoolctl==3.1.0\n + urllib3==2.0.7\n + xlrd==2.0.1\n + xlsxwriter==3.2.0\nResolved 34 packages in 125ms\nInstalled 13 packages in 132ms\n + anyqt==0.2.0\n + attrs==24.2.0\n + cattrs==23.1.2\n + commonmark==0.9.1\n + dictdiffer==0.9.0\n + docutils==0.20.1\n + orange-canvas-core==0.1.35\n + orange-widget-base==4.22.0\n + platformdirs==4.0.0\n + pyqtgraph==0.10.0\n + qasync==0.25.0\n + requests-cache==1.1.1\n + url-normalize==1.4.3\nResolved 2 packages in 2ms\nInstalled 2 packages in 13ms\n + psycopg2==2.9.9\n + pymssql==2.3.2\nAudited 1 package in 22ms\nAudited 2 packages in 2ms\nOrange/classification/_simple_tree.c: In function ‘gain_ratio_c’:\nOrange/classification/_simple_tree.c:63:9: warning: implicit declaration of function ‘qsort_r’; did you mean ‘qsort’? [-Wimplicit-function-declaration]\n   63 |         qsort_r(base, nel, size, compar, thunk)\n      |         ^~~~~~~\nOrange/classification/_simple_tree.c:147:9: note: in expansion of macro ‘QSORT_R_FUNC’\n  147 |         QSORT_R_FUNC(examples, size, sizeof(struct Example), (void*) &compar_attr, compar_examples);\n      |         ^~~~~~~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/classification/_tree_scorers.c:567:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_2find_threshold_entropy’:\nOrange/classification/_tree_scorers.c:3115:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 3115 |   __pyx_t_7 = ((__pyx_v_N <= __pyx_v_min_leaf) != 0);\n      |                           ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_6find_threshold_MSE’:\nOrange/classification/_tree_scorers.c:4619:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 4619 |   __pyx_t_1 = ((__pyx_v_N <= __pyx_v_min_leaf) != 0);\n      |                           ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_8find_binarization_MSE’:\nOrange/classification/_tree_scorers.c:5396:43: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5396 |           for (__pyx_t_22 = 0; __pyx_t_22 < __pyx_t_21; __pyx_t_22+=1) {\n      |                                           ^\nOrange/classification/_tree_scorers.c:5517:39: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5517 |           __pyx_t_27 = ((__pyx_v_left >= __pyx_v_min_leaf) != 0);\n      |                                       ^~\nOrange/classification/_tree_scorers.c:5523:53: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5523 |           __pyx_t_27 = (((__pyx_v_N - __pyx_v_left) >= __pyx_v_min_leaf) != 0);\n      |                                                     ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_14compute_predictions_csr’:\nOrange/classification/_tree_scorers.c:7051:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7051 |         for (__pyx_t_11 = 0; __pyx_t_11 < __pyx_t_10; __pyx_t_11+=1) {\n      |                                         ^\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_16compute_predictions_csc’:\nOrange/classification/_tree_scorers.c:7741:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7741 |         for (__pyx_t_11 = 0; __pyx_t_11 < __pyx_t_10; __pyx_t_11+=1) {\n      |                                         ^\nOrange/classification/_tree_scorers.c:7801:143: warning: comparison of integer expressions of different signedness: ‘__pyx_t_5numpy_int32_t’ {aka ‘int’} and ‘unsigned int’ [-Wsign-compare]\n 7801 |               __pyx_t_17 = (((*((__pyx_t_5numpy_int32_t *) ( /* dim=0 */ (__pyx_v_indices.data + __pyx_t_18 * __pyx_v_indices.strides[0]) ))) != __pyx_v_i) != 0);\n      |                                                                                                                                               ^~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/data/_valuecount.c:567:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/data/_contingency.c:598:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/data/_io.c: In function ‘__pyx_pf_6Orange_4data_3_io_sparse_read_float.constprop’:\nOrange/data/_io.c:3881:24: warning: ‘__pyx_v_decs’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3881 |           __pyx_v_decs = (__pyx_v_decs / 10.0);\n      |           ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:4070:24: warning: ‘__pyx_v_value’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4070 |           __pyx_t_10 = PyFloat_FromDouble(__pyx_v_value); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 221, __pyx_L5_error)\n      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:480:40: warning: ‘__pyx_v_attr_index’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n  480 |   #define PyInt_FromLong               PyLong_FromLong\n      |                                        ^~~~~~~~~~~~~~~\nOrange/data/_io.c:1301:7: note: ‘__pyx_v_attr_index’ was declared here\n 1301 |   int __pyx_v_attr_index;\n      |       ^~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:2935:25: warning: ‘__pyx_v_atomp’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 2935 |           __pyx_v_atomp = (__pyx_v_atomp + 1);\n      |           ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/distance/_distance.c:598:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/preprocess/_discretize.c:567:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/preprocess/_relieff.cpp:581:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/projection/_som.c:598:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_5update_hex’:\nOrange/projection/_som.c:3655:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3655 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:3654:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3654 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_7get_winners_sparse’:\nOrange/projection/_som.c:4547:223: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4547 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_38, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_39, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_y;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:4114:7: note: ‘__pyx_v_win_y’ was declared here\n 4114 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:4536:223: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4536 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_36, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_37, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_x;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:4113:7: note: ‘__pyx_v_win_x’ was declared here\n 4113 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pf_6Orange_10projection_4_som_8update_sparse.constprop’:\nOrange/projection/_som.c:4746:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4746 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:4745:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4745 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_3update’:\nOrange/projection/_som.c:3141:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3141 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_1get_winners’:\nOrange/projection/_som.c:2964:223: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 2964 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_27, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_28, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_y;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:2665:7: note: ‘__pyx_v_win_y’ was declared here\n 2665 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:2953:223: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 2953 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_25, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_26, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_x;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:2664:7: note: ‘__pyx_v_win_x’ was declared here\n 2664 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pf_6Orange_10projection_4_som_10update_sparse_hex.constprop’:\nOrange/projection/_som.c:5515:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 5515 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:5514:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 5514 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/setuptools/command/install.py:37: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n  setuptools.SetuptoolsDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/setuptools/command/easy_install.py:159: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.\n  EasyInstallDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/setuptools/command/install.py:37: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n  setuptools.SetuptoolsDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706/.venv/lib/python3.7/site-packages/setuptools/command/egg_info.py:628: SetuptoolsDeprecationWarning: Custom 'build_py' does not implement 'get_data_files_without_manifest'.\nPlease extend command classes from setuptools instead of distutils.\n  SetuptoolsDeprecationWarning\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706\ncollected 32 items\n\nr2e_tests/test_1.py sss.............................                     [100%]\n\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestOWRank::test_auto_send\nPASSED r2e_tests/test_1.py::TestOWRank::test_cls_scorer_reg_data\nPASSED r2e_tests/test_1.py::TestOWRank::test_data_which_make_scorer_nan\nPASSED r2e_tests/test_1.py::TestOWRank::test_dataset\nPASSED r2e_tests/test_1.py::TestOWRank::test_default_sort_indicator\nPASSED r2e_tests/test_1.py::TestOWRank::test_image_export\nPASSED r2e_tests/test_1.py::TestOWRank::test_input_data\nPASSED r2e_tests/test_1.py::TestOWRank::test_input_data_disconnect\nPASSED r2e_tests/test_1.py::TestOWRank::test_input_scorer\nPASSED r2e_tests/test_1.py::TestOWRank::test_input_scorer_disconnect\nPASSED r2e_tests/test_1.py::TestOWRank::test_input_scorer_fitter\nPASSED r2e_tests/test_1.py::TestOWRank::test_minimum_size\nPASSED r2e_tests/test_1.py::TestOWRank::test_msg_base_class\nPASSED r2e_tests/test_1.py::TestOWRank::test_no_attributes\nPASSED r2e_tests/test_1.py::TestOWRank::test_no_class_data_learner_class_reg\nPASSED r2e_tests/test_1.py::TestOWRank::test_output_data\nPASSED r2e_tests/test_1.py::TestOWRank::test_output_features\nPASSED r2e_tests/test_1.py::TestOWRank::test_output_scores\nPASSED r2e_tests/test_1.py::TestOWRank::test_output_scores_with_scorer\nPASSED r2e_tests/test_1.py::TestOWRank::test_reg_scorer_cls_data\nPASSED r2e_tests/test_1.py::TestOWRank::test_scores_nan_sorting\nPASSED r2e_tests/test_1.py::TestOWRank::test_scores_sorting\nPASSED r2e_tests/test_1.py::TestOWRank::test_scores_updates_cls\nPASSED r2e_tests/test_1.py::TestOWRank::test_scores_updates_no_class\nPASSED r2e_tests/test_1.py::TestOWRank::test_scores_updates_reg\nPASSED r2e_tests/test_1.py::TestOWRank::test_scoring_method_defaults\nPASSED r2e_tests/test_1.py::TestOWRank::test_scoring_method_problem_type\nPASSED r2e_tests/test_1.py::TestOWRank::test_selected_rows\nPASSED r2e_tests/test_1.py::TestOWRank::test_setting_migration_fixes_header_state\nSKIPPED [1] .venv/lib/python3.7/site-packages/orangewidget/tests/base.py:244: image exporting not tested as .widget was not set\nSKIPPED [1] .venv/lib/python3.7/site-packages/orangewidget/tests/base.py:238: minimum size not tested as .widget was not set\nSKIPPED [1] .venv/lib/python3.7/site-packages/orangewidget/tests/base.py:250: msg base class not tested as .widget was not set\n======================== 29 passed, 3 skipped in 5.08s =========================\nWidgets left: 0    Max widgets: 2640 \n\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_14c32060dfeb30ed0c16ffb17794a39ee0f93706\ncollected 32 items\n\nr2e_tests/test_1.py sss..............F..............                     [100%]\n\n=================================== FAILURES ===================================\n_______________ TestOWRank.test_no_class_data_learner_class_reg ________________\n\nself = <r2e_tests.test_1.TestOWRank testMethod=test_no_class_data_learner_class_reg>\n\n    def test_no_class_data_learner_class_reg(self):\n        \"\"\"\n        Check workflow with learners that can be both classifier\n        or regressor and data have no class variable. This test should not\n        fail.\n        \"\"\"\n        data = Table.from_table(Domain(self.iris.domain.variables), self.iris)\n        random_forest = RandomForestLearner()\n        self.assertIsNone(data.domain.class_var)\n        self.send_signal(self.widget.Inputs.data, data)\n    \n        with patch(\"Orange.widgets.data.owrank.log.error\") as log:\n>           self.send_signal(self.widget.Inputs.scorer, random_forest, 1)\n\nr2e_tests/test_1.py:262: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n.venv/lib/python3.7/site-packages/orangewidget/tests/base.py:446: in send_signal\n    widget=widget, wait=wait)\n.venv/lib/python3.7/site-packages/orangewidget/tests/base.py:472: in send_signals\n    widget.handleNewSignals()\nOrange/widgets/data/owrank.py:355: in handleNewSignals\n    self.updateScores()\nOrange/widgets/data/owrank.py:435: in updateScores\n    for scorer in scorers))\nOrange/widgets/data/owrank.py:435: in <genexpr>\n    for scorer in scorers))\nOrange/misc/cache.py:50: in _wrapped_func\n    return _cached_method(weakref.ref(self), *args, **kwargs)\nOrange/misc/cache.py:46: in _cached_method\n    return func(self_weak(), *args, **kwargs)\nOrange/widgets/data/owrank.py:397: in get_scorer_scores\n    scores = scorer.scorer.score_data(self.data).T\nOrange/preprocess/score.py:182: in score_data\n    scores, model_attributes = self.score(data)\nOrange/modelling/randomforest.py:16: in score\n    model = self.get_learner(data)(data)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = RandomForestLearner(), problem_type = None\n\n    def get_learner(self, problem_type):\n        \"\"\"Get the learner for a given problem type.\n    \n        Parameters\n        ----------\n        problem_type: str or Table or Domain\n            If str, one of ``'classification'`` or ``'regression'``. If Table\n            or Domain, the type is inferred from Domain's first class variable.\n    \n        Returns\n        -------\n        Learner\n            The appropriate learner for the given problem type.\n    \n        Raises\n        ------\n        TypeError\n            When (inferred) problem type not one of ``'classification'``\n            or ``'regression'``.\n        \"\"\"\n        if isinstance(problem_type, Table):\n            problem_type = problem_type.domain\n        if isinstance(problem_type, Domain):\n            problem_type = (self.CLASSIFICATION if problem_type.has_discrete_class else\n                            self.REGRESSION if problem_type.has_continuous_class else\n                            None)\n        # Prevent trying to access the learner when problem type is None\n        if problem_type not in self.__fits__:\n>           raise TypeError(\"No learner to handle '{}'\".format(problem_type))\nE           TypeError: No learner to handle 'None'\n\nOrange/modelling/base.py:75: TypeError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestOWRank::test_auto_send\nPASSED r2e_tests/test_1.py::TestOWRank::test_cls_scorer_reg_data\nPASSED r2e_tests/test_1.py::TestOWRank::test_data_which_make_scorer_nan\nPASSED r2e_tests/test_1.py::TestOWRank::test_dataset\nPASSED r2e_tests/test_1.py::TestOWRank::test_default_sort_indicator\nPASSED r2e_tests/test_1.py::TestOWRank::test_image_export\nPASSED r2e_tests/test_1.py::TestOWRank::test_input_data\nPASSED r2e_tests/test_1.py::TestOWRank::test_input_data_disconnect\nPASSED r2e_tests/test_1.py::TestOWRank::test_input_scorer\nPASSED r2e_tests/test_1.py::TestOWRank::test_input_scorer_disconnect\nPASSED r2e_tests/test_1.py::TestOWRank::test_input_scorer_fitter\nPASSED r2e_tests/test_1.py::TestOWRank::test_minimum_size\nPASSED r2e_tests/test_1.py::TestOWRank::test_msg_base_class\nPASSED r2e_tests/test_1.py::TestOWRank::test_no_attributes\nPASSED r2e_tests/test_1.py::TestOWRank::test_output_data\nPASSED r2e_tests/test_1.py::TestOWRank::test_output_features\nPASSED r2e_tests/test_1.py::TestOWRank::test_output_scores\nPASSED r2e_tests/test_1.py::TestOWRank::test_output_scores_with_scorer\nPASSED r2e_tests/test_1.py::TestOWRank::test_reg_scorer_cls_data\nPASSED r2e_tests/test_1.py::TestOWRank::test_scores_nan_sorting\nPASSED r2e_tests/test_1.py::TestOWRank::test_scores_sorting\nPASSED r2e_tests/test_1.py::TestOWRank::test_scores_updates_cls\nPASSED r2e_tests/test_1.py::TestOWRank::test_scores_updates_no_class\nPASSED r2e_tests/test_1.py::TestOWRank::test_scores_updates_reg\nPASSED r2e_tests/test_1.py::TestOWRank::test_scoring_method_defaults\nPASSED r2e_tests/test_1.py::TestOWRank::test_scoring_method_problem_type\nPASSED r2e_tests/test_1.py::TestOWRank::test_selected_rows\nPASSED r2e_tests/test_1.py::TestOWRank::test_setting_migration_fixes_header_state\nSKIPPED [1] .venv/lib/python3.7/site-packages/orangewidget/tests/base.py:244: image exporting not tested as .widget was not set\nSKIPPED [1] .venv/lib/python3.7/site-packages/orangewidget/tests/base.py:238: minimum size not tested as .widget was not set\nSKIPPED [1] .venv/lib/python3.7/site-packages/orangewidget/tests/base.py:250: msg base class not tested as .widget was not set\nFAILED r2e_tests/test_1.py::TestOWRank::test_no_class_data_learner_class_reg\n=================== 1 failed, 28 passed, 3 skipped in 4.01s ====================\nWidgets left: 0    Max widgets: 2640 \n\n",
    "old_commit_res_stderr": ""
}
Orange/widgets/data/owrank.py Orange/widgets/data/tests/test_owrank.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Error When Using RandomForestLearner with Data Lacking a Class Variable

**Description:**
When attempting to use the `RandomForestLearner` as a scorer in the `OWRank` widget with a dataset that does not have a class variable, an unexpected error occurs.

**Example Code:**
```python
from Orange.data import Table, Domain
from Orange.modelling import RandomForestLearner

# Create data without a class variable
data = Table.from_table(Domain(attributes=Table('iris').domain.attributes), Table('iris'))

# Initialize the RandomForestLearner
random_forest = RandomForestLearner()

# Attempt to use the learner as a scorer
scores = random_forest.score_data(data)
```

**Expected Behavior:**
The `OWRank` widget should gracefully handle datasets without a class variable when using learners like `RandomForestLearner`. Instead of raising an error, it should log the issue and assign `NaN` values to the scores, indicating that scoring could not be performed due to the absence of a class variable.

**Actual Behavior:**
Using the `RandomForestLearner` with data lacking a class variable results in the following error:
```
TypeError: No learner to handle 'None'
```
This error disrupts the workflow and prevents the ranking process from completing successfully.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### Orange/widgets/data/owrank.py
"""
Rank
====

Rank (score) features for prediction.

"""
import warnings
from collections import namedtuple, OrderedDict
import logging
from functools import partial
from itertools import chain

import numpy as np
from scipy.sparse import issparse

from AnyQt.QtGui import QFontMetrics
from AnyQt.QtWidgets import (
    QTableView, QRadioButton, QButtonGroup, QGridLayout,
    QStackedWidget, QHeaderView, QCheckBox, QItemDelegate,
)
from AnyQt.QtCore import (
    Qt, QItemSelection, QItemSelectionRange, QItemSelectionModel,
)

from Orange.data import (Table, Domain, ContinuousVariable, DiscreteVariable,
                         StringVariable)
from Orange.misc.cache import memoize_method
from Orange.preprocess import score
from Orange.widgets import report
from Orange.widgets import gui
from Orange.widgets.settings import (DomainContextHandler, Setting,
                                     ContextSetting)
from Orange.widgets.utils.itemmodels import PyTableModel
from Orange.widgets.utils.sql import check_sql_input
from Orange.widgets.utils.widgetpreview import WidgetPreview
from Orange.widgets.widget import (
    OWWidget, Msg, Input, Output, AttributeList
)


log = logging.getLogger(__name__)


class ProblemType:
    CLASSIFICATION, REGRESSION, UNSUPERVISED = range(3)

    @classmethod
    def from_variable(cls, variable):
        return (cls.CLASSIFICATION if isinstance(variable, DiscreteVariable) else
                cls.REGRESSION if isinstance(variable, ContinuousVariable) else
                cls.UNSUPERVISED)

ScoreMeta = namedtuple("score_meta", ["name", "shortname", "scorer", 'problem_type', 'is_default'])

# Default scores.
CLS_SCORES = [
    ScoreMeta("Information Gain", "Info. gain",
              score.InfoGain, ProblemType.CLASSIFICATION, False),
    ScoreMeta("Information Gain Ratio", "Gain ratio",
              score.GainRatio, ProblemType.CLASSIFICATION, True),
    ScoreMeta("Gini Decrease", "Gini",
              score.Gini, ProblemType.CLASSIFICATION, True),
    ScoreMeta("ANOVA", "ANOVA",
              score.ANOVA, ProblemType.CLASSIFICATION, False),
    ScoreMeta("χ²", "χ²",
              score.Chi2, ProblemType.CLASSIFICATION, False),
    ScoreMeta("ReliefF", "ReliefF",
              score.ReliefF, ProblemType.CLASSIFICATION, False),
    ScoreMeta("FCBF", "FCBF",
              score.FCBF, ProblemType.CLASSIFICATION, False)
]
REG_SCORES = [
    ScoreMeta("Univariate Regression", "Univar. reg.",
              score.UnivariateLinearRegression, ProblemType.REGRESSION, True),
    ScoreMeta("RReliefF", "RReliefF",
              score.RReliefF, ProblemType.REGRESSION, True)
]
SCORES = CLS_SCORES + REG_SCORES


class TableView(QTableView):
    def __init__(self, parent=None, **kwargs):
        super().__init__(parent=parent,
                         selectionBehavior=QTableView.SelectRows,
                         selectionMode=QTableView.ExtendedSelection,
                         sortingEnabled=True,
                         showGrid=True,
                         cornerButtonEnabled=False,
                         alternatingRowColors=False,
                         **kwargs)
        self.setItemDelegate(gui.ColoredBarItemDelegate(self))
        self.setItemDelegateForColumn(0, QItemDelegate())

        header = self.verticalHeader()
        header.setSectionResizeMode(header.Fixed)
        header.setFixedWidth(50)
        header.setDefaultSectionSize(22)
        header.setTextElideMode(Qt.ElideMiddle)  # Note: https://bugreports.qt.io/browse/QTBUG-62091

        header = self.horizontalHeader()
        header.setSectionResizeMode(header.Fixed)
        header.setFixedHeight(24)
        header.setDefaultSectionSize(80)
        header.setTextElideMode(Qt.ElideMiddle)

    def setVHeaderFixedWidthFromLabel(self, max_label):
        header = self.verticalHeader()
        width = QFontMetrics(header.font()).width(max_label)
        header.setFixedWidth(min(width + 40, 400))


class TableModel(PyTableModel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._extremes = {}

    def data(self, index, role=Qt.DisplayRole):
        if role == gui.BarRatioRole and index.isValid():
            value = super().data(index, Qt.EditRole)
            if not isinstance(value, float):
                return None
            vmin, vmax = self._extremes.get(index.column(), (-np.inf, np.inf))
            value = (value - vmin) / ((vmax - vmin) or 1)
            return value

        if role == Qt.DisplayRole:
            role = Qt.EditRole

        value = super().data(index, role)

        # Display nothing for non-existent attr value counts in the first column
        if role == Qt.EditRole and index.column() == 0 and np.isnan(value):
            return ''

        return value

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role == Qt.InitialSortOrderRole:
            return Qt.DescendingOrder
        return super().headerData(section, orientation, role)

    def setExtremesFrom(self, column, values):
        """Set extremes for columnn's ratio bars from values"""
        try:
            with warnings.catch_warnings():
                warnings.filterwarnings(
                    "ignore", ".*All-NaN slice encountered.*", RuntimeWarning)
                vmin = np.nanmin(values)
            if np.isnan(vmin):
                raise TypeError
        except TypeError:
            vmin, vmax = -np.inf, np.inf
        else:
            vmax = np.nanmax(values)
        self._extremes[column] = (vmin, vmax)

    def resetSorting(self, yes_reset=False):
        # pylint: disable=arguments-differ
        """We don't want to invalidate our sort proxy model everytime we
        wrap a new list. Our proxymodel only invalidates explicitly
        (i.e. when new data is set)"""
        if yes_reset:
            super().resetSorting()

    def _argsortData(self, data, order):
        """Always sort NaNs last"""
        indices = np.argsort(data, kind='mergesort')
        if order == Qt.DescendingOrder:
            return np.roll(indices[::-1], -np.isnan(data).sum())
        return indices


class OWRank(OWWidget):
    name = "Rank"
    description = "Rank and filter data features by their relevance."
    icon = "icons/Rank.svg"
    priority = 1102
    keywords = []

    buttons_area_orientation = Qt.Vertical

    class Inputs:
        data = Input("Data", Table)
        scorer = Input("Scorer", score.Scorer, multiple=True)

    class Outputs:
        reduced_data = Output("Reduced Data", Table, default=True)
        scores = Output("Scores", Table)
        features = Output("Features", AttributeList, dynamic=False)

    SelectNone, SelectAll, SelectManual, SelectNBest = range(4)

    nSelected = ContextSetting(5)
    auto_apply = Setting(True)

    sorting = Setting((0, Qt.DescendingOrder))
    selected_methods = Setting(set())

    settings_version = 2
    settingsHandler = DomainContextHandler()
    selected_rows = ContextSetting([])
    selectionMethod = ContextSetting(SelectNBest)

    class Information(OWWidget.Information):
        no_target_var = Msg("Data does not have a single target variable. "
                            "You can still connect in unsupervised scorers "
                            "such as PCA.")
        missings_imputed = Msg('Missing values will be imputed as needed.')

    class Error(OWWidget.Error):
        invalid_type = Msg("Cannot handle target variable type {}")
        inadequate_learner = Msg("Scorer {} inadequate: {}")
        no_attributes = Msg("Data does not have a single attribute.")

    def __init__(self):
        super().__init__()
        self.scorers = OrderedDict()
        self.out_domain_desc = None
        self.data = None
        self.problem_type_mode = ProblemType.CLASSIFICATION

        if not self.selected_methods:
            self.selected_methods = {method.name for method in SCORES
                                     if method.is_default}

        # GUI

        self.ranksModel = model = TableModel(parent=self)  # type: TableModel
        self.ranksView = view = TableView(self)            # type: TableView
        self.mainArea.layout().addWidget(view)
        view.setModel(model)
        view.setColumnWidth(0, 30)
        view.selectionModel().selectionChanged.connect(self.on_select)

        def _set_select_manual():
            self.setSelectionMethod(OWRank.SelectManual)

        view.pressed.connect(_set_select_manual)
        view.verticalHeader().sectionClicked.connect(_set_select_manual)
        view.horizontalHeader().sectionClicked.connect(self.headerClick)

        self.measuresStack = stacked = QStackedWidget(self)
        self.controlArea.layout().addWidget(stacked)

        for scoring_methods in (CLS_SCORES,
                                REG_SCORES,
                                []):
            box = gui.vBox(None, "Scoring Methods" if scoring_methods else None)
            stacked.addWidget(box)
            for method in scoring_methods:
                box.layout().addWidget(QCheckBox(
                    method.name, self,
                    objectName=method.shortname,  # To be easily found in tests
                    checked=method.name in self.selected_methods,
                    stateChanged=partial(self.methodSelectionChanged, method_name=method.name)))
            gui.rubber(box)

        gui.rubber(self.controlArea)
        self.switchProblemType(ProblemType.CLASSIFICATION)

        selMethBox = gui.vBox(self.controlArea, "Select Attributes", addSpace=True)

        grid = QGridLayout()
        grid.setContentsMargins(6, 0, 6, 0)
        self.selectButtons = QButtonGroup()
        self.selectButtons.buttonClicked[int].connect(self.setSelectionMethod)

        def button(text, buttonid, toolTip=None):
            b = QRadioButton(text)
            self.selectButtons.addButton(b, buttonid)
            if toolTip is not None:
                b.setToolTip(toolTip)
            return b

        b1 = button(self.tr("None"), OWRank.SelectNone)
        b2 = button(self.tr("All"), OWRank.SelectAll)
        b3 = button(self.tr("Manual"), OWRank.SelectManual)
        b4 = button(self.tr("Best ranked:"), OWRank.SelectNBest)

        s = gui.spin(selMethBox, self, "nSelected", 1, 999,
                     callback=lambda: self.setSelectionMethod(OWRank.SelectNBest))

        grid.addWidget(b1, 0, 0)
        grid.addWidget(b2, 1, 0)
        grid.addWidget(b3, 2, 0)
        grid.addWidget(b4, 3, 0)
        grid.addWidget(s, 3, 1)

        self.selectButtons.button(self.selectionMethod).setChecked(True)

        selMethBox.layout().addLayout(grid)

        gui.auto_send(selMethBox, self, "auto_apply", box=False)

        self.resize(690, 500)

    def switchProblemType(self, index):
        """
        Switch between discrete/continuous/no_class mode
        """
        self.measuresStack.setCurrentIndex(index)
        self.problem_type_mode = index

    @Inputs.data
    @check_sql_input
    def set_data(self, data):
        self.closeContext()
        self.selected_rows = []
        self.ranksModel.clear()
        self.ranksModel.resetSorting(True)

        self.get_method_scores.cache_clear()  # pylint: disable=no-member
        self.get_scorer_scores.cache_clear()  # pylint: disable=no-member

        self.Error.clear()
        self.Information.clear()
        self.Information.missings_imputed(
            shown=data is not None and data.has_missing())

        if data is not None and not data.domain.attributes:
            data = None
            self.Error.no_attributes()
        self.data = data
        self.switchProblemType(ProblemType.CLASSIFICATION)
        if self.data is not None:
            domain = self.data.domain

            if domain.has_discrete_class:
                problem_type = ProblemType.CLASSIFICATION
            elif domain.has_continuous_class:
                problem_type = ProblemType.REGRESSION
            elif not domain.class_var:
                self.Information.no_target_var()
                problem_type = ProblemType.UNSUPERVISED
            else:
                # This can happen?
                self.Error.invalid_type(type(domain.class_var).__name__)
                problem_type = None

            if problem_type is not None:
                self.switchProblemType(problem_type)

            self.ranksModel.setVerticalHeaderLabels(domain.attributes)
            self.ranksView.setVHeaderFixedWidthFromLabel(
                max((a.name for a in domain.attributes), key=len))

            self.selectionMethod = OWRank.SelectNBest

        self.openContext(data)
        self.selectButtons.button(self.selectionMethod).setChecked(True)

    def handleNewSignals(self):
        self.setStatusMessage('Running')
        self.updateScores()
        self.setStatusMessage('')
        self.on_select()

    @Inputs.scorer
    def set_learner(self, scorer, id):  # pylint: disable=redefined-builtin
        if scorer is None:
            self.scorers.pop(id, None)
        else:
            # Avoid caching a (possibly stale) previous instance of the same
            # Scorer passed via the same signal
            if id in self.scorers:
                # pylint: disable=no-member
                self.get_scorer_scores.cache_clear()

            self.scorers[id] = ScoreMeta(scorer.name, scorer.name, scorer,
                                         ProblemType.from_variable(scorer.class_type),
                                         False)

    @memoize_method()
    def get_method_scores(self, method):
        # These errors often happen, but they result in nans, which
        # are handled correctly by the widget
        estimator = method.scorer()
        data = self.data
        try:
            scores = np.asarray(estimator(data))
        except ValueError:
            try:
                scores = np.array([estimator(data, attr)
                                   for attr in data.domain.attributes])
            except ValueError:
                log.error("%s doesn't work on this data", method.name)
                scores = np.full(len(data.domain.attributes), np.nan)
            else:
                log.warning("%s had to be computed separately for each "
                            "variable", method.name)
        return scores

    @memoize_method()
    def get_scorer_scores(self, scorer):
        try:
            scores = scorer.scorer.score_data(self.data).T
        except ValueError:
            log.error("%s doesn't work on this data", scorer.name)
            scores = np.full((len(self.data.domain.attributes), 1), np.nan)

        labels = ((scorer.shortname,)
                  if scores.shape[1] == 1 else
                  tuple(scorer.shortname + '_' + str(i)
                        for i in range(1, 1 + scores.shape[1])))
        return scores, labels

    def updateScores(self):
        if self.data is None:
            self.ranksModel.clear()
            self.Outputs.scores.send(None)
            return

        methods = [method
                   for method in SCORES
                   if (method.name in self.selected_methods and
                       method.problem_type == self.problem_type_mode and
                       (not issparse(self.data.X) or
                        method.scorer.supports_sparse_data))]

        scorers = []
        self.Error.inadequate_learner.clear()
        for scorer in self.scorers.values():
            if scorer.problem_type in (self.problem_type_mode, ProblemType.UNSUPERVISED):
                scorers.append(scorer)
            else:
                self.Error.inadequate_learner(scorer.name, scorer.learner_adequacy_err_msg)

        method_scores = tuple(self.get_method_scores(method)
                              for method in methods)

        scorer_scores, scorer_labels = (), ()
        if scorers:
            scorer_scores, scorer_labels = zip(*(self.get_scorer_scores(scorer)
                                                 for scorer in scorers))
            scorer_labels = tuple(chain.from_iterable(scorer_labels))

        labels = tuple(method.shortname for method in methods) + scorer_labels
        model_array = np.column_stack(
            ([len(a.values) if a.is_discrete else np.nan
              for a in self.data.domain.attributes],) +
            (method_scores if method_scores else ()) +
            (scorer_scores if scorer_scores else ())
        )
        for column, values in enumerate(model_array.T):
            self.ranksModel.setExtremesFrom(column, values)

        self.ranksModel.wrap(model_array.tolist())
        self.ranksModel.setHorizontalHeaderLabels(('#',) + labels)
        self.ranksView.setColumnWidth(0, 40)

        # Re-apply sort
        try:
            sort_column, sort_order = self.sorting
            if sort_column < len(labels):
                # adds 1 for '#' (discrete count) column
                self.ranksModel.sort(sort_column + 1, sort_order)
                self.ranksView.horizontalHeader().setSortIndicator(sort_column + 1, sort_order)
        except ValueError:
            pass

        self.autoSelection()
        self.Outputs.scores.send(self.create_scores_table(labels))

    def on_select(self):
        # Save indices of attributes in the original, unsorted domain
        self.selected_rows = list(self.ranksModel.mapToSourceRows([
            i.row() for i in self.ranksView.selectionModel().selectedRows(0)]))
        self.commit()

    def setSelectionMethod(self, method):
        self.selectionMethod = method
        self.selectButtons.button(method).setChecked(True)
        self.autoSelection()

    def autoSelection(self):
        selModel = self.ranksView.selectionModel()
        model = self.ranksModel
        rowCount = model.rowCount()
        columnCount = model.columnCount()

        if self.selectionMethod == OWRank.SelectNone:
            selection = QItemSelection()
        elif self.selectionMethod == OWRank.SelectAll:
            selection = QItemSelection(
                model.index(0, 0),
                model.index(rowCount - 1, columnCount - 1)
            )
        elif self.selectionMethod == OWRank.SelectNBest:
            nSelected = min(self.nSelected, rowCount)
            selection = QItemSelection(
                model.index(0, 0),
                model.index(nSelected - 1, columnCount - 1)
            )
        else:
            selection = QItemSelection()
            if self.selected_rows is not None:
                for row in model.mapFromSourceRows(self.selected_rows):
                    selection.append(QItemSelectionRange(
                        model.index(row, 0), model.index(row, columnCount - 1)))

        selModel.select(selection, QItemSelectionModel.ClearAndSelect)

    def headerClick(self, index):
        if index >= 1 and self.selectionMethod == OWRank.SelectNBest:
            # Reselect the top ranked attributes
            self.autoSelection()

        # Store the header states
        sort_order = self.ranksModel.sortOrder()
        sort_column = self.ranksModel.sortColumn() - 1  # -1 for '#' (discrete count) column
        self.sorting = (sort_column, sort_order)

    def methodSelectionChanged(self, state, method_name):
        if state == Qt.Checked:
            self.selected_methods.add(method_name)
        elif method_name in self.selected_methods:
            self.selected_methods.remove(method_name)

        self.updateScores()

    def send_report(self):
        if not self.data:
            return
        self.report_domain("Input", self.data.domain)
        self.report_table("Ranks", self.ranksView, num_format="{:.3f}")
        if self.out_domain_desc is not None:
            self.report_items("Output", self.out_domain_desc)

    def commit(self):
        selected_attrs = []
        if self.data is not None:
            selected_attrs = [self.data.domain.attributes[i]
                              for i in self.selected_rows]
        if not selected_attrs:
            self.Outputs.reduced_data.send(None)
            self.Outputs.features.send(None)
            self.out_domain_desc = None
        else:
            reduced_domain = Domain(
                selected_attrs, self.data.domain.class_var, self.data.domain.metas)
            data = self.data.transform(reduced_domain)
            self.Outputs.reduced_data.send(data)
            self.Outputs.features.send(AttributeList(selected_attrs))
            self.out_domain_desc = report.describe_domain(data.domain)

    def create_scores_table(self, labels):
        model_list = self.ranksModel.tolist()
        if not model_list or len(model_list[0]) == 1:  # Empty or just n_values column
            return None

        domain = Domain([ContinuousVariable(label) for label in labels],
                        metas=[StringVariable("Feature")])

        # Prevent np.inf scores
        finfo = np.finfo(np.float64)
        scores = np.clip(np.array(model_list)[:, 1:], finfo.min, finfo.max)

        feature_names = np.array([a.name for a in self.data.domain.attributes])
        # Reshape to 2d array as Table does not like 1d arrays
        feature_names = feature_names[:, None]

        new_table = Table(domain, scores, metas=feature_names)
        new_table.name = "Feature Scores"
        return new_table

    @classmethod
    def migrate_settings(cls, settings, version):
        # If older settings, restore sort header to default
        # Saved selected_rows will likely be incorrect
        if version is None or version < 2:
            column, order = 0, Qt.DescendingOrder
            headerState = settings.pop("headerState", None)

            # Lacking knowledge of last problemType, use discrete ranks view's ordering
            if isinstance(headerState, (tuple, list)):
                headerState = headerState[0]

            if isinstance(headerState, bytes):
                hview = QHeaderView(Qt.Horizontal)
                hview.restoreState(headerState)
                column, order = hview.sortIndicatorSection() - 1, hview.sortIndicatorOrder()
            settings["sorting"] = (column, order)

    @classmethod
    def migrate_context(cls, context, version):
        if version is None or version < 2:
            # Old selection was saved as sorted indices. New selection is original indices.
            # Since we can't devise the latter without first computing the ranks,
            # just reset the selection to avoid confusion.
            context.values['selected_rows'] = []


if __name__ == "__main__":  # pragma: no cover
    from Orange.classification import RandomForestLearner
    previewer = WidgetPreview(OWRank)
    previewer.run(Table("heart_disease.tab"), no_exit=True)
    previewer.send_signals(
        set_learner=(RandomForestLearner(), (3, 'Learner', None)))
    previewer.run()

    # pylint: disable=pointless-string-statement
    """
    WidgetPreview(OWRank).run(
        set_learner=(RandomForestLearner(), (3, 'Learner', None)),
        set_data=Table("heart_disease.tab"))
"""

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** Error When Using RandomForestLearner with Data Lacking a Class Variable

**Description:**
When attempting to use the `RandomForestLearner` as a scorer in the `OWRank` widget with a dataset that does not have a class variable, an unexpected error occurs.

**Example Code:**
```python
from Orange.data import Table, Domain
from Orange.modelling import RandomForestLearner

# Create data without a class variable
data = Table.from_table(Domain(attributes=Table('iris').domain.attributes), Table('iris'))

# Initialize the RandomForestLearner
random_forest = RandomForestLearner()

# Attempt to use the learner as a scorer
scores = random_forest.score_data(data)
```

**Expected Behavior:**
The `OWRank` widget should gracefully handle datasets without a class variable when using learners like `RandomForestLearner`. Instead of raising an error, it should log the issue and assign `NaN` values to the scores, indicating that scoring could not be performed due to the absence of a class variable.

**Actual Behavior:**
Using the `RandomForestLearner` with data lacking a class variable results in the following error:
```
TypeError: No learner to handle 'None'
```
This error disrupts the workflow and prevents the ranking process from completing successfully.

[/ISSUE]
{
    "TestOWRank.test_auto_send": "PASSED",
    "TestOWRank.test_cls_scorer_reg_data": "PASSED",
    "TestOWRank.test_data_which_make_scorer_nan": "PASSED",
    "TestOWRank.test_dataset": "PASSED",
    "TestOWRank.test_default_sort_indicator": "PASSED",
    "TestOWRank.test_image_export": "PASSED",
    "TestOWRank.test_input_data": "PASSED",
    "TestOWRank.test_input_data_disconnect": "PASSED",
    "TestOWRank.test_input_scorer": "PASSED",
    "TestOWRank.test_input_scorer_disconnect": "PASSED",
    "TestOWRank.test_input_scorer_fitter": "PASSED",
    "TestOWRank.test_minimum_size": "PASSED",
    "TestOWRank.test_msg_base_class": "PASSED",
    "TestOWRank.test_no_attributes": "PASSED",
    "TestOWRank.test_no_class_data_learner_class_reg": "PASSED",
    "TestOWRank.test_output_data": "PASSED",
    "TestOWRank.test_output_features": "PASSED",
    "TestOWRank.test_output_scores": "PASSED",
    "TestOWRank.test_output_scores_with_scorer": "PASSED",
    "TestOWRank.test_reg_scorer_cls_data": "PASSED",
    "TestOWRank.test_scores_nan_sorting": "PASSED",
    "TestOWRank.test_scores_sorting": "PASSED",
    "TestOWRank.test_scores_updates_cls": "PASSED",
    "TestOWRank.test_scores_updates_no_class": "PASSED",
    "TestOWRank.test_scores_updates_reg": "PASSED",
    "TestOWRank.test_scoring_method_defaults": "PASSED",
    "TestOWRank.test_scoring_method_problem_type": "PASSED",
    "TestOWRank.test_selected_rows": "PASSED",
    "TestOWRank.test_setting_migration_fixes_header_state": "PASSED"
}
diff --git a/Orange/widgets/data/owrank.py b/Orange/widgets/data/owrank.py
index edbf5ffb9..d84d3e79f 100644
--- a/Orange/widgets/data/owrank.py
+++ b/Orange/widgets/data/owrank.py
@@ -395,7 +395,7 @@ class OWRank(OWWidget):
     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)
 

{"Orange/widgets/data/owrank.py": "\"\"\"\nRank\n====\n\nRank (score) features for prediction.\n\n\"\"\"\nimport warnings\nfrom collections import namedtuple, OrderedDict\nimport logging\nfrom functools import partial\nfrom itertools import chain\n\nimport numpy as np\nfrom scipy.sparse import issparse\n\nfrom AnyQt.QtGui import QFontMetrics\nfrom AnyQt.QtWidgets import (\n    QTableView, QRadioButton, QButtonGroup, QGridLayout,\n    QStackedWidget, QHeaderView, QCheckBox, QItemDelegate,\n)\nfrom AnyQt.QtCore import (\n    Qt, QItemSelection, QItemSelectionRange, QItemSelectionModel,\n)\n\nfrom Orange.data import (Table, Domain, ContinuousVariable, DiscreteVariable,\n                         StringVariable)\nfrom Orange.misc.cache import memoize_method\nfrom Orange.preprocess import score\nfrom Orange.widgets import report\nfrom Orange.widgets import gui\nfrom Orange.widgets.settings import (DomainContextHandler, Setting,\n                                     ContextSetting)\nfrom Orange.widgets.utils.itemmodels import PyTableModel\nfrom Orange.widgets.utils.sql import check_sql_input\nfrom Orange.widgets.utils.widgetpreview import WidgetPreview\nfrom Orange.widgets.widget import (\n    OWWidget, Msg, Input, Output, AttributeList\n)\n\n\nlog = logging.getLogger(__name__)\n\n\nclass ProblemType:\n    CLASSIFICATION, REGRESSION, UNSUPERVISED = range(3)\n\n    @classmethod\n    def from_variable(cls, variable):\n        return (cls.CLASSIFICATION if isinstance(variable, DiscreteVariable) else\n                cls.REGRESSION if isinstance(variable, ContinuousVariable) else\n                cls.UNSUPERVISED)\n\nScoreMeta = namedtuple(\"score_meta\", [\"name\", \"shortname\", \"scorer\", 'problem_type', 'is_default'])\n\n# Default scores.\nCLS_SCORES = [\n    ScoreMeta(\"Information Gain\", \"Info. gain\",\n              score.InfoGain, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"Information Gain Ratio\", \"Gain ratio\",\n              score.GainRatio, ProblemType.CLASSIFICATION, True),\n    ScoreMeta(\"Gini Decrease\", \"Gini\",\n              score.Gini, ProblemType.CLASSIFICATION, True),\n    ScoreMeta(\"ANOVA\", \"ANOVA\",\n              score.ANOVA, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"\u03c7\u00b2\", \"\u03c7\u00b2\",\n              score.Chi2, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"ReliefF\", \"ReliefF\",\n              score.ReliefF, ProblemType.CLASSIFICATION, False),\n    ScoreMeta(\"FCBF\", \"FCBF\",\n              score.FCBF, ProblemType.CLASSIFICATION, False)\n]\nREG_SCORES = [\n    ScoreMeta(\"Univariate Regression\", \"Univar. reg.\",\n              score.UnivariateLinearRegression, ProblemType.REGRESSION, True),\n    ScoreMeta(\"RReliefF\", \"RReliefF\",\n              score.RReliefF, ProblemType.REGRESSION, True)\n]\nSCORES = CLS_SCORES + REG_SCORES\n\n\nclass TableView(QTableView):\n    def __init__(self, parent=None, **kwargs):\n        super().__init__(parent=parent,\n                         selectionBehavior=QTableView.SelectRows,\n                         selectionMode=QTableView.ExtendedSelection,\n                         sortingEnabled=True,\n                         showGrid=True,\n                         cornerButtonEnabled=False,\n                         alternatingRowColors=False,\n                         **kwargs)\n        self.setItemDelegate(gui.ColoredBarItemDelegate(self))\n        self.setItemDelegateForColumn(0, QItemDelegate())\n\n        header = self.verticalHeader()\n        header.setSectionResizeMode(header.Fixed)\n        header.setFixedWidth(50)\n        header.setDefaultSectionSize(22)\n        header.setTextElideMode(Qt.ElideMiddle)  # Note: https://bugreports.qt.io/browse/QTBUG-62091\n\n        header = self.horizontalHeader()\n        header.setSectionResizeMode(header.Fixed)\n        header.setFixedHeight(24)\n        header.setDefaultSectionSize(80)\n        header.setTextElideMode(Qt.ElideMiddle)\n\n    def setVHeaderFixedWidthFromLabel(self, max_label):\n        header = self.verticalHeader()\n        width = QFontMetrics(header.font()).width(max_label)\n        header.setFixedWidth(min(width + 40, 400))\n\n\nclass TableModel(PyTableModel):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._extremes = {}\n\n    def data(self, index, role=Qt.DisplayRole):\n        if role == gui.BarRatioRole and index.isValid():\n            value = super().data(index, Qt.EditRole)\n            if not isinstance(value, float):\n                return None\n            vmin, vmax = self._extremes.get(index.column(), (-np.inf, np.inf))\n            value = (value - vmin) / ((vmax - vmin) or 1)\n            return value\n\n        if role == Qt.DisplayRole:\n            role = Qt.EditRole\n\n        value = super().data(index, role)\n\n        # Display nothing for non-existent attr value counts in the first column\n        if role == Qt.EditRole and index.column() == 0 and np.isnan(value):\n            return ''\n\n        return value\n\n    def headerData(self, section, orientation, role=Qt.DisplayRole):\n        if role == Qt.InitialSortOrderRole:\n            return Qt.DescendingOrder\n        return super().headerData(section, orientation, role)\n\n    def setExtremesFrom(self, column, values):\n        \"\"\"Set extremes for columnn's ratio bars from values\"\"\"\n        try:\n            with warnings.catch_warnings():\n                warnings.filterwarnings(\n                    \"ignore\", \".*All-NaN slice encountered.*\", RuntimeWarning)\n                vmin = np.nanmin(values)\n            if np.isnan(vmin):\n                raise TypeError\n        except TypeError:\n            vmin, vmax = -np.inf, np.inf\n        else:\n            vmax = np.nanmax(values)\n        self._extremes[column] = (vmin, vmax)\n\n    def resetSorting(self, yes_reset=False):\n        # pylint: disable=arguments-differ\n        \"\"\"We don't want to invalidate our sort proxy model everytime we\n        wrap a new list. Our proxymodel only invalidates explicitly\n        (i.e. when new data is set)\"\"\"\n        if yes_reset:\n            super().resetSorting()\n\n    def _argsortData(self, data, order):\n        \"\"\"Always sort NaNs last\"\"\"\n        indices = np.argsort(data, kind='mergesort')\n        if order == Qt.DescendingOrder:\n            return np.roll(indices[::-1], -np.isnan(data).sum())\n        return indices\n\n\nclass OWRank(OWWidget):\n    name = \"Rank\"\n    description = \"Rank and filter data features by their relevance.\"\n    icon = \"icons/Rank.svg\"\n    priority = 1102\n    keywords = []\n\n    buttons_area_orientation = Qt.Vertical\n\n    class Inputs:\n        data = Input(\"Data\", Table)\n        scorer = Input(\"Scorer\", score.Scorer, multiple=True)\n\n    class Outputs:\n        reduced_data = Output(\"Reduced Data\", Table, default=True)\n        scores = Output(\"Scores\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    SelectNone, SelectAll, SelectManual, SelectNBest = range(4)\n\n    nSelected = ContextSetting(5)\n    auto_apply = Setting(True)\n\n    sorting = Setting((0, Qt.DescendingOrder))\n    selected_methods = Setting(set())\n\n    settings_version = 2\n    settingsHandler = DomainContextHandler()\n    selected_rows = ContextSetting([])\n    selectionMethod = ContextSetting(SelectNBest)\n\n    class Information(OWWidget.Information):\n        no_target_var = Msg(\"Data does not have a single target variable. \"\n                            \"You can still connect in unsupervised scorers \"\n                            \"such as PCA.\")\n        missings_imputed = Msg('Missing values will be imputed as needed.')\n\n    class Error(OWWidget.Error):\n        invalid_type = Msg(\"Cannot handle target variable type {}\")\n        inadequate_learner = Msg(\"Scorer {} inadequate: {}\")\n        no_attributes = Msg(\"Data does not have a single attribute.\")\n\n    def __init__(self):\n        super().__init__()\n        self.scorers = OrderedDict()\n        self.out_domain_desc = None\n        self.data = None\n        self.problem_type_mode = ProblemType.CLASSIFICATION\n\n        if not self.selected_methods:\n            self.selected_methods = {method.name for method in SCORES\n                                     if method.is_default}\n\n        # GUI\n\n        self.ranksModel = model = TableModel(parent=self)  # type: TableModel\n        self.ranksView = view = TableView(self)            # type: TableView\n        self.mainArea.layout().addWidget(view)\n        view.setModel(model)\n        view.setColumnWidth(0, 30)\n        view.selectionModel().selectionChanged.connect(self.on_select)\n\n        def _set_select_manual():\n            self.setSelectionMethod(OWRank.SelectManual)\n\n        view.pressed.connect(_set_select_manual)\n        view.verticalHeader().sectionClicked.connect(_set_select_manual)\n        view.horizontalHeader().sectionClicked.connect(self.headerClick)\n\n        self.measuresStack = stacked = QStackedWidget(self)\n        self.controlArea.layout().addWidget(stacked)\n\n        for scoring_methods in (CLS_SCORES,\n                                REG_SCORES,\n                                []):\n            box = gui.vBox(None, \"Scoring Methods\" if scoring_methods else None)\n            stacked.addWidget(box)\n            for method in scoring_methods:\n                box.layout().addWidget(QCheckBox(\n                    method.name, self,\n                    objectName=method.shortname,  # To be easily found in tests\n                    checked=method.name in self.selected_methods,\n                    stateChanged=partial(self.methodSelectionChanged, method_name=method.name)))\n            gui.rubber(box)\n\n        gui.rubber(self.controlArea)\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n\n        selMethBox = gui.vBox(self.controlArea, \"Select Attributes\", addSpace=True)\n\n        grid = QGridLayout()\n        grid.setContentsMargins(6, 0, 6, 0)\n        self.selectButtons = QButtonGroup()\n        self.selectButtons.buttonClicked[int].connect(self.setSelectionMethod)\n\n        def button(text, buttonid, toolTip=None):\n            b = QRadioButton(text)\n            self.selectButtons.addButton(b, buttonid)\n            if toolTip is not None:\n                b.setToolTip(toolTip)\n            return b\n\n        b1 = button(self.tr(\"None\"), OWRank.SelectNone)\n        b2 = button(self.tr(\"All\"), OWRank.SelectAll)\n        b3 = button(self.tr(\"Manual\"), OWRank.SelectManual)\n        b4 = button(self.tr(\"Best ranked:\"), OWRank.SelectNBest)\n\n        s = gui.spin(selMethBox, self, \"nSelected\", 1, 999,\n                     callback=lambda: self.setSelectionMethod(OWRank.SelectNBest))\n\n        grid.addWidget(b1, 0, 0)\n        grid.addWidget(b2, 1, 0)\n        grid.addWidget(b3, 2, 0)\n        grid.addWidget(b4, 3, 0)\n        grid.addWidget(s, 3, 1)\n\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n        selMethBox.layout().addLayout(grid)\n\n        gui.auto_send(selMethBox, self, \"auto_apply\", box=False)\n\n        self.resize(690, 500)\n\n    def switchProblemType(self, index):\n        \"\"\"\n        Switch between discrete/continuous/no_class mode\n        \"\"\"\n        self.measuresStack.setCurrentIndex(index)\n        self.problem_type_mode = index\n\n    @Inputs.data\n    @check_sql_input\n    def set_data(self, data):\n        self.closeContext()\n        self.selected_rows = []\n        self.ranksModel.clear()\n        self.ranksModel.resetSorting(True)\n\n        self.get_method_scores.cache_clear()  # pylint: disable=no-member\n        self.get_scorer_scores.cache_clear()  # pylint: disable=no-member\n\n        self.Error.clear()\n        self.Information.clear()\n        self.Information.missings_imputed(\n            shown=data is not None and data.has_missing())\n\n        if data is not None and not data.domain.attributes:\n            data = None\n            self.Error.no_attributes()\n        self.data = data\n        self.switchProblemType(ProblemType.CLASSIFICATION)\n        if self.data is not None:\n            domain = self.data.domain\n\n            if domain.has_discrete_class:\n                problem_type = ProblemType.CLASSIFICATION\n            elif domain.has_continuous_class:\n                problem_type = ProblemType.REGRESSION\n            elif not domain.class_var:\n                self.Information.no_target_var()\n                problem_type = ProblemType.UNSUPERVISED\n            else:\n                # This can happen?\n                self.Error.invalid_type(type(domain.class_var).__name__)\n                problem_type = None\n\n            if problem_type is not None:\n                self.switchProblemType(problem_type)\n\n            self.ranksModel.setVerticalHeaderLabels(domain.attributes)\n            self.ranksView.setVHeaderFixedWidthFromLabel(\n                max((a.name for a in domain.attributes), key=len))\n\n            self.selectionMethod = OWRank.SelectNBest\n\n        self.openContext(data)\n        self.selectButtons.button(self.selectionMethod).setChecked(True)\n\n    def handleNewSignals(self):\n        self.setStatusMessage('Running')\n        self.updateScores()\n        self.setStatusMessage('')\n        self.on_select()\n\n    @Inputs.scorer\n    def set_learner(self, scorer, id):  # pylint: disable=redefined-builtin\n        if scorer is None:\n            self.scorers.pop(id, None)\n        else:\n            # Avoid caching a (possibly stale) previous instance of the same\n            # Scorer passed via the same signal\n            if id in self.scorers:\n                # pylint: disable=no-member\n                self.get_scorer_scores.cache_clear()\n\n            self.scorers[id] = ScoreMeta(scorer.name, scorer.name, scorer,\n                                         ProblemType.from_variable(scorer.class_type),\n                                         False)\n\n    @memoize_method()\n    def get_method_scores(self, method):\n        # These errors often happen, but they result in nans, which\n        # are handled correctly by the widget\n        estimator = method.scorer()\n        data = self.data\n        try:\n            scores = np.asarray(estimator(data))\n        except ValueError:\n            try:\n                scores = np.array([estimator(data, attr)\n                                   for attr in data.domain.attributes])\n            except ValueError:\n                log.error(\"%s doesn't work on this data\", method.name)\n                scores = np.full(len(data.domain.attributes), np.nan)\n            else:\n                log.warning(\"%s had to be computed separately for each \"\n                            \"variable\", method.name)\n        return scores\n\n    @memoize_method()\n    def get_scorer_scores(self, scorer):\n        try:\n            scores = scorer.scorer.score_data(self.data).T\n        except ValueError:\n            log.error(\"%s doesn't work on this data\", scorer.name)\n            scores = np.full((len(self.data.domain.attributes), 1), np.nan)\n\n        labels = ((scorer.shortname,)\n                  if scores.shape[1] == 1 else\n                  tuple(scorer.shortname + '_' + str(i)\n                        for i in range(1, 1 + scores.shape[1])))\n        return scores, labels\n\n    def updateScores(self):\n        if self.data is None:\n            self.ranksModel.clear()\n            self.Outputs.scores.send(None)\n            return\n\n        methods = [method\n                   for method in SCORES\n                   if (method.name in self.selected_methods and\n                       method.problem_type == self.problem_type_mode and\n                       (not issparse(self.data.X) or\n                        method.scorer.supports_sparse_data))]\n\n        scorers = []\n        self.Error.inadequate_learner.clear()\n        for scorer in self.scorers.values():\n            if scorer.problem_type in (self.problem_type_mode, ProblemType.UNSUPERVISED):\n                scorers.append(scorer)\n            else:\n                self.Error.inadequate_learner(scorer.name, scorer.learner_adequacy_err_msg)\n\n        method_scores = tuple(self.get_method_scores(method)\n                              for method in methods)\n\n        scorer_scores, scorer_labels = (), ()\n        if scorers:\n            scorer_scores, scorer_labels = zip(*(self.get_scorer_scores(scorer)\n                                                 for scorer in scorers))\n            scorer_labels = tuple(chain.from_iterable(scorer_labels))\n\n        labels = tuple(method.shortname for method in methods) + scorer_labels\n        model_array = np.column_stack(\n            ([len(a.values) if a.is_discrete else np.nan\n              for a in self.data.domain.attributes],) +\n            (method_scores if method_scores else ()) +\n            (scorer_scores if scorer_scores else ())\n        )\n        for column, values in enumerate(model_array.T):\n            self.ranksModel.setExtremesFrom(column, values)\n\n        self.ranksModel.wrap(model_array.tolist())\n        self.ranksModel.setHorizontalHeaderLabels(('#',) + labels)\n        self.ranksView.setColumnWidth(0, 40)\n\n        # Re-apply sort\n        try:\n            sort_column, sort_order = self.sorting\n            if sort_column < len(labels):\n                # adds 1 for '#' (discrete count) column\n                self.ranksModel.sort(sort_column + 1, sort_order)\n                self.ranksView.horizontalHeader().setSortIndicator(sort_column + 1, sort_order)\n        except ValueError:\n            pass\n\n        self.autoSelection()\n        self.Outputs.scores.send(self.create_scores_table(labels))\n\n    def on_select(self):\n        # Save indices of attributes in the original, unsorted domain\n        self.selected_rows = list(self.ranksModel.mapToSourceRows([\n            i.row() for i in self.ranksView.selectionModel().selectedRows(0)]))\n        self.commit()\n\n    def setSelectionMethod(self, method):\n        self.selectionMethod = method\n        self.selectButtons.button(method).setChecked(True)\n        self.autoSelection()\n\n    def autoSelection(self):\n        selModel = self.ranksView.selectionModel()\n        model = self.ranksModel\n        rowCount = model.rowCount()\n        columnCount = model.columnCount()\n\n        if self.selectionMethod == OWRank.SelectNone:\n            selection = QItemSelection()\n        elif self.selectionMethod == OWRank.SelectAll:\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(rowCount - 1, columnCount - 1)\n            )\n        elif self.selectionMethod == OWRank.SelectNBest:\n            nSelected = min(self.nSelected, rowCount)\n            selection = QItemSelection(\n                model.index(0, 0),\n                model.index(nSelected - 1, columnCount - 1)\n            )\n        else:\n            selection = QItemSelection()\n            if self.selected_rows is not None:\n                for row in model.mapFromSourceRows(self.selected_rows):\n                    selection.append(QItemSelectionRange(\n                        model.index(row, 0), model.index(row, columnCount - 1)))\n\n        selModel.select(selection, QItemSelectionModel.ClearAndSelect)\n\n    def headerClick(self, index):\n        if index >= 1 and self.selectionMethod == OWRank.SelectNBest:\n            # Reselect the top ranked attributes\n            self.autoSelection()\n\n        # Store the header states\n        sort_order = self.ranksModel.sortOrder()\n        sort_column = self.ranksModel.sortColumn() - 1  # -1 for '#' (discrete count) column\n        self.sorting = (sort_column, sort_order)\n\n    def methodSelectionChanged(self, state, method_name):\n        if state == Qt.Checked:\n            self.selected_methods.add(method_name)\n        elif method_name in self.selected_methods:\n            self.selected_methods.remove(method_name)\n\n        self.updateScores()\n\n    def send_report(self):\n        if not self.data:\n            return\n        self.report_domain(\"Input\", self.data.domain)\n        self.report_table(\"Ranks\", self.ranksView, num_format=\"{:.3f}\")\n        if self.out_domain_desc is not None:\n            self.report_items(\"Output\", self.out_domain_desc)\n\n    def commit(self):\n        selected_attrs = []\n        if self.data is not None:\n            selected_attrs = [self.data.domain.attributes[i]\n                              for i in self.selected_rows]\n        if not selected_attrs:\n            self.Outputs.reduced_data.send(None)\n            self.Outputs.features.send(None)\n            self.out_domain_desc = None\n        else:\n            reduced_domain = Domain(\n                selected_attrs, self.data.domain.class_var, self.data.domain.metas)\n            data = self.data.transform(reduced_domain)\n            self.Outputs.reduced_data.send(data)\n            self.Outputs.features.send(AttributeList(selected_attrs))\n            self.out_domain_desc = report.describe_domain(data.domain)\n\n    def create_scores_table(self, labels):\n        model_list = self.ranksModel.tolist()\n        if not model_list or len(model_list[0]) == 1:  # Empty or just n_values column\n            return None\n\n        domain = Domain([ContinuousVariable(label) for label in labels],\n                        metas=[StringVariable(\"Feature\")])\n\n        # Prevent np.inf scores\n        finfo = np.finfo(np.float64)\n        scores = np.clip(np.array(model_list)[:, 1:], finfo.min, finfo.max)\n\n        feature_names = np.array([a.name for a in self.data.domain.attributes])\n        # Reshape to 2d array as Table does not like 1d arrays\n        feature_names = feature_names[:, None]\n\n        new_table = Table(domain, scores, metas=feature_names)\n        new_table.name = \"Feature Scores\"\n        return new_table\n\n    @classmethod\n    def migrate_settings(cls, settings, version):\n        # If older settings, restore sort header to default\n        # Saved selected_rows will likely be incorrect\n        if version is None or version < 2:\n            column, order = 0, Qt.DescendingOrder\n            headerState = settings.pop(\"headerState\", None)\n\n            # Lacking knowledge of last problemType, use discrete ranks view's ordering\n            if isinstance(headerState, (tuple, list)):\n                headerState = headerState[0]\n\n            if isinstance(headerState, bytes):\n                hview = QHeaderView(Qt.Horizontal)\n                hview.restoreState(headerState)\n                column, order = hview.sortIndicatorSection() - 1, hview.sortIndicatorOrder()\n            settings[\"sorting\"] = (column, order)\n\n    @classmethod\n    def migrate_context(cls, context, version):\n        if version is None or version < 2:\n            # Old selection was saved as sorted indices. New selection is original indices.\n            # Since we can't devise the latter without first computing the ranks,\n            # just reset the selection to avoid confusion.\n            context.values['selected_rows'] = []\n\n\nif __name__ == \"__main__\":  # pragma: no cover\n    from Orange.classification import RandomForestLearner\n    previewer = WidgetPreview(OWRank)\n    previewer.run(Table(\"heart_disease.tab\"), no_exit=True)\n    previewer.send_signals(\n        set_learner=(RandomForestLearner(), (3, 'Learner', None)))\n    previewer.run()\n\n    # pylint: disable=pointless-string-statement\n    \"\"\"\n    WidgetPreview(OWRank).run(\n        set_learner=(RandomForestLearner(), (3, 'Learner', None)),\n        set_data=Table(\"heart_disease.tab\"))\n\"\"\"\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Error When Using RandomForestLearner with Data Lacking a Class Variable

**Description:**
When attempting to use the `RandomForestLearner` as a scorer in the `OWRank` widget with a dataset that does not have a class variable, an unexpected error occurs.

**Example Code:**
```python
from Orange.data import Table, Domain
from Orange.modelling import RandomForestLearner

# Create data without a class variable
data = Table.from_table(Domain(attributes=Table('iris').domain.attributes), Table('iris'))

# Initialize the RandomForestLearner
random_forest = RandomForestLearner()

# Attempt to use the learner as a scorer
scores = random_forest.score_data(data)
```

**Expected Behavior:**
The `OWRank` widget should gracefully handle datasets without a class variable when using learners like `RandomForestLearner`. Instead of raising an error, it should log the issue and assign `NaN` values to the scores, indicating that scoring could not be performed due to the absence of a class variable.

**Actual Behavior:**
Using the `RandomForestLearner` with data lacking a class variable results in the following error:
```
TypeError: No learner to handle 'None'
```
This error disrupts the workflow and prevents the ranking process from completing successfully.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### Orange/widgets/data/owrank.py
"""
Rank
====

Rank (score) features for prediction.

"""
import warnings
from collections import namedtuple, OrderedDict
import logging
from functools import partial
from itertools import chain

import numpy as np
from scipy.sparse import issparse

from AnyQt.QtGui import QFontMetrics
from AnyQt.QtWidgets import (
    QTableView, QRadioButton, QButtonGroup, QGridLayout,
    QStackedWidget, QHeaderView, QCheckBox, QItemDelegate,
)
from AnyQt.QtCore import (
    Qt, QItemSelection, QItemSelectionRange, QItemSelectionModel,
)

from Orange.data import (Table, Domain, ContinuousVariable, DiscreteVariable,
                         StringVariable)
from Orange.misc.cache import memoize_method
from Orange.preprocess import score
from Orange.widgets import report
from Orange.widgets import gui
from Orange.widgets.settings import (DomainContextHandler, Setting,
                                     ContextSetting)
from Orange.widgets.utils.itemmodels import PyTableModel
from Orange.widgets.utils.sql import check_sql_input
from Orange.widgets.utils.widgetpreview import WidgetPreview
from Orange.widgets.widget import (
    OWWidget, Msg, Input, Output, AttributeList
)


log = logging.getLogger(__name__)


class ProblemType:
    CLASSIFICATION, REGRESSION, UNSUPERVISED = range(3)

    @classmethod
    def from_variable(cls, variable):
        return (cls.CLASSIFICATION if isinstance(variable, DiscreteVariable) else
                cls.REGRESSION if isinstance(variable, ContinuousVariable) else
                cls.UNSUPERVISED)

ScoreMeta = namedtuple("score_meta", ["name", "shortname", "scorer", 'problem_type', 'is_default'])

# Default scores.
CLS_SCORES = [
    ScoreMeta("Information Gain", "Info. gain",
              score.InfoGain, ProblemType.CLASSIFICATION, False),
    ScoreMeta("Information Gain Ratio", "Gain ratio",
              score.GainRatio, ProblemType.CLASSIFICATION, True),
    ScoreMeta("Gini Decrease", "Gini",
              score.Gini, ProblemType.CLASSIFICATION, True),
    ScoreMeta("ANOVA", "ANOVA",
              score.ANOVA, ProblemType.CLASSIFICATION, False),
    ScoreMeta("χ²", "χ²",
              score.Chi2, ProblemType.CLASSIFICATION, False),
    ScoreMeta("ReliefF", "ReliefF",
              score.ReliefF, ProblemType.CLASSIFICATION, False),
    ScoreMeta("FCBF", "FCBF",
              score.FCBF, ProblemType.CLASSIFICATION, False)
]
REG_SCORES = [
    ScoreMeta("Univariate Regression", "Univar. reg.",
              score.UnivariateLinearRegression, ProblemType.REGRESSION, True),
    ScoreMeta("RReliefF", "RReliefF",
              score.RReliefF, ProblemType.REGRESSION, True)
]
SCORES = CLS_SCORES + REG_SCORES


class TableView(QTableView):
    def __init__(self, parent=None, **kwargs):
        super().__init__(parent=parent,
                         selectionBehavior=QTableView.SelectRows,
                         selectionMode=QTableView.ExtendedSelection,
                         sortingEnabled=True,
                         showGrid=True,
                         cornerButtonEnabled=False,
                         alternatingRowColors=False,
                         **kwargs)
        self.setItemDelegate(gui.ColoredBarItemDelegate(self))
        self.setItemDelegateForColumn(0, QItemDelegate())

        header = self.verticalHeader()
        header.setSectionResizeMode(header.Fixed)
        header.setFixedWidth(50)
        header.setDefaultSectionSize(22)
        header.setTextElideMode(Qt.ElideMiddle)  # Note: https://bugreports.qt.io/browse/QTBUG-62091

        header = self.horizontalHeader()
        header.setSectionResizeMode(header.Fixed)
        header.setFixedHeight(24)
        header.setDefaultSectionSize(80)
        header.setTextElideMode(Qt.ElideMiddle)

    def setVHeaderFixedWidthFromLabel(self, max_label):
        header = self.verticalHeader()
        width = QFontMetrics(header.font()).width(max_label)
        header.setFixedWidth(min(width + 40, 400))


class TableModel(PyTableModel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._extremes = {}

    def data(self, index, role=Qt.DisplayRole):
        if role == gui.BarRatioRole and index.isValid():
            value = super().data(index, Qt.EditRole)
            if not isinstance(value, float):
                return None
            vmin, vmax = self._extremes.get(index.column(), (-np.inf, np.inf))
            value = (value - vmin) / ((vmax - vmin) or 1)
            return value

        if role == Qt.DisplayRole:
            role = Qt.EditRole

        value = super().data(index, role)

        # Display nothing for non-existent attr value counts in the first column
        if role == Qt.EditRole and index.column() == 0 and np.isnan(value):
            return ''

        return value

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role == Qt.InitialSortOrderRole:
            return Qt.DescendingOrder
        return super().headerData(section, orientation, role)

    def setExtremesFrom(self, column, values):
        """Set extremes for columnn's ratio bars from values"""
        try:
            with warnings.catch_warnings():
                warnings.filterwarnings(
                    "ignore", ".*All-NaN slice encountered.*", RuntimeWarning)
                vmin = np.nanmin(values)
            if np.isnan(vmin):
                raise TypeError
        except TypeError:
            vmin, vmax = -np.inf, np.inf
        else:
            vmax = np.nanmax(values)
        self._extremes[column] = (vmin, vmax)

    def resetSorting(self, yes_reset=False):
        # pylint: disable=arguments-differ
        """We don't want to invalidate our sort proxy model everytime we
        wrap a new list. Our proxymodel only invalidates explicitly
        (i.e. when new data is set)"""
        if yes_reset:
            super().resetSorting()

    def _argsortData(self, data, order):
        """Always sort NaNs last"""
        indices = np.argsort(data, kind='mergesort')
        if order == Qt.DescendingOrder:
            return np.roll(indices[::-1], -np.isnan(data).sum())
        return indices


class OWRank(OWWidget):
    name = "Rank"
    description = "Rank and filter data features by their relevance."
    icon = "icons/Rank.svg"
    priority = 1102
    keywords = []

    buttons_area_orientation = Qt.Vertical

    class Inputs:
        data = Input("Data", Table)
        scorer = Input("Scorer", score.Scorer, multiple=True)

    class Outputs:
        reduced_data = Output("Reduced Data", Table, default=True)
        scores = Output("Scores", Table)
        features = Output("Features", AttributeList, dynamic=False)

    SelectNone, SelectAll, SelectManual, SelectNBest = range(4)

    nSelected = ContextSetting(5)
    auto_apply = Setting(True)

    sorting = Setting((0, Qt.DescendingOrder))
    selected_methods = Setting(set())

    settings_version = 2
    settingsHandler = DomainContextHandler()
    selected_rows = ContextSetting([])
    selectionMethod = ContextSetting(SelectNBest)

    class Information(OWWidget.Information):
        no_target_var = Msg("Data does not have a single target variable. "
                            "You can still connect in unsupervised scorers "
                            "such as PCA.")
        missings_imputed = Msg('Missing values will be imputed as needed.')

    class Error(OWWidget.Error):
        invalid_type = Msg("Cannot handle target variable type {}")
        inadequate_learner = Msg("Scorer {} inadequate: {}")
        no_attributes = Msg("Data does not have a single attribute.")

    def __init__(self):
        super().__init__()
        self.scorers = OrderedDict()
        self.out_domain_desc = None
        self.data = None
        self.problem_type_mode = ProblemType.CLASSIFICATION

        if not self.selected_methods:
            self.selected_methods = {method.name for method in SCORES
                                     if method.is_default}

        # GUI

        self.ranksModel = model = TableModel(parent=self)  # type: TableModel
        self.ranksView = view = TableView(self)            # type: TableView
        self.mainArea.layout().addWidget(view)
        view.setModel(model)
        view.setColumnWidth(0, 30)
        view.selectionModel().selectionChanged.connect(self.on_select)

        def _set_select_manual():
            self.setSelectionMethod(OWRank.SelectManual)

        view.pressed.connect(_set_select_manual)
        view.verticalHeader().sectionClicked.connect(_set_select_manual)
        view.horizontalHeader().sectionClicked.connect(self.headerClick)

        self.measuresStack = stacked = QStackedWidget(self)
        self.controlArea.layout().addWidget(stacked)

        for scoring_methods in (CLS_SCORES,
                                REG_SCORES,
                                []):
            box = gui.vBox(None, "Scoring Methods" if scoring_methods else None)
            stacked.addWidget(box)
            for method in scoring_methods:
                box.layout().addWidget(QCheckBox(
                    method.name, self,
                    objectName=method.shortname,  # To be easily found in tests
                    checked=method.name in self.selected_methods,
                    stateChanged=partial(self.methodSelectionChanged, method_name=method.name)))
            gui.rubber(box)

        gui.rubber(self.controlArea)
        self.switchProblemType(ProblemType.CLASSIFICATION)

        selMethBox = gui.vBox(self.controlArea, "Select Attributes", addSpace=True)

        grid = QGridLayout()
        grid.setContentsMargins(6, 0, 6, 0)
        self.selectButtons = QButtonGroup()
        self.selectButtons.buttonClicked[int].connect(self.setSelectionMethod)

        def button(text, buttonid, toolTip=None):
            b = QRadioButton(text)
            self.selectButtons.addButton(b, buttonid)
            if toolTip is not None:
                b.setToolTip(toolTip)
            return b

        b1 = button(self.tr("None"), OWRank.SelectNone)
        b2 = button(self.tr("All"), OWRank.SelectAll)
        b3 = button(self.tr("Manual"), OWRank.SelectManual)
        b4 = button(self.tr("Best ranked:"), OWRank.SelectNBest)

        s = gui.spin(selMethBox, self, "nSelected", 1, 999,
                     callback=lambda: self.setSelectionMethod(OWRank.SelectNBest))

        grid.addWidget(b1, 0, 0)
        grid.addWidget(b2, 1, 0)
        grid.addWidget(b3, 2, 0)
        grid.addWidget(b4, 3, 0)
        grid.addWidget(s, 3, 1)

        self.selectButtons.button(self.selectionMethod).setChecked(True)

        selMethBox.layout().addLayout(grid)

        gui.auto_send(selMethBox, self, "auto_apply", box=False)

        self.resize(690, 500)

    def switchProblemType(self, index):
        """
        Switch between discrete/continuous/no_class mode
        """
        self.measuresStack.setCurrentIndex(index)
        self.problem_type_mode = index

    @Inputs.data
    @check_sql_input
    def set_data(self, data):
        self.closeContext()
        self.selected_rows = []
        self.ranksModel.clear()
        self.ranksModel.resetSorting(True)

        self.get_method_scores.cache_clear()  # pylint: disable=no-member
        self.get_scorer_scores.cache_clear()  # pylint: disable=no-member

        self.Error.clear()
        self.Information.clear()
        self.Information.missings_imputed(
            shown=data is not None and data.has_missing())

        if data is not None and not data.domain.attributes:
            data = None
            self.Error.no_attributes()
        self.data = data
        self.switchProblemType(ProblemType.CLASSIFICATION)
        if self.data is not None:
            domain = self.data.domain

            if domain.has_discrete_class:
                problem_type = ProblemType.CLASSIFICATION
            elif domain.has_continuous_class:
                problem_type = ProblemType.REGRESSION
            elif not domain.class_var:
                self.Information.no_target_var()
                problem_type = ProblemType.UNSUPERVISED
            else:
                # This can happen?
                self.Error.invalid_type(type(domain.class_var).__name__)
                problem_type = None

            if problem_type is not None:
                self.switchProblemType(problem_type)

            self.ranksModel.setVerticalHeaderLabels(domain.attributes)
            self.ranksView.setVHeaderFixedWidthFromLabel(
                max((a.name for a in domain.attributes), key=len))

            self.selectionMethod = OWRank.SelectNBest

        self.openContext(data)
        self.selectButtons.button(self.selectionMethod).setChecked(True)

    def handleNewSignals(self):
        self.setStatusMessage('Running')
        self.updateScores()
        self.setStatusMessage('')
        self.on_select()

    @Inputs.scorer
    def set_learner(self, scorer, id):  # pylint: disable=redefined-builtin
        if scorer is None:
            self.scorers.pop(id, None)
        else:
            # Avoid caching a (possibly stale) previous instance of the same
            # Scorer passed via the same signal
            if id in self.scorers:
                # pylint: disable=no-member
                self.get_scorer_scores.cache_clear()

            self.scorers[id] = ScoreMeta(scorer.name, scorer.name, scorer,
                                         ProblemType.from_variable(scorer.class_type),
                                         False)

    @memoize_method()
    def get_method_scores(self, method):
        # These errors often happen, but they result in nans, which
        # are handled correctly by the widget
        estimator = method.scorer()
        data = self.data
        try:
            scores = np.asarray(estimator(data))
        except ValueError:
            try:
                scores = np.array([estimator(data, attr)
                                   for attr in data.domain.attributes])
            except ValueError:
                log.error("%s doesn't work on this data", method.name)
                scores = np.full(len(data.domain.attributes), np.nan)
            else:
                log.warning("%s had to be computed separately for each "
                            "variable", method.name)
        return scores

    @memoize_method()
    def get_scorer_scores(self, scorer):
        try:
            scores = scorer.scorer.score_data(self.data).T
        except ValueError:
            log.error("%s doesn't work on this data", scorer.name)
            scores = np.full((len(self.data.domain.attributes), 1), np.nan)

        labels = ((scorer.shortname,)
                  if scores.shape[1] == 1 else
                  tuple(scorer.shortname + '_' + str(i)
                        for i in range(1, 1 + scores.shape[1])))
        return scores, labels

    def updateScores(self):
        if self.data is None:
            self.ranksModel.clear()
            self.Outputs.scores.send(None)
            return

        methods = [method
                   for method in SCORES
                   if (method.name in self.selected_methods and
                       method.problem_type == self.problem_type_mode and
                       (not issparse(self.data.X) or
                        method.scorer.supports_sparse_data))]

        scorers = []
        self.Error.inadequate_learner.clear()
        for scorer in self.scorers.values():
            if scorer.problem_type in (self.problem_type_mode, ProblemType.UNSUPERVISED):
                scorers.append(scorer)
            else:
                self.Error.inadequate_learner(scorer.name, scorer.learner_adequacy_err_msg)

        method_scores = tuple(self.get_method_scores(method)
                              for method in methods)

        scorer_scores, scorer_labels = (), ()
        if scorers:
            scorer_scores, scorer_labels = zip(*(self.get_scorer_scores(scorer)
                                                 for scorer in scorers))
            scorer_labels = tuple(chain.from_iterable(scorer_labels))

        labels = tuple(method.shortname for method in methods) + scorer_labels
        model_array = np.column_stack(
            ([len(a.values) if a.is_discrete else np.nan
              for a in self.data.domain.attributes],) +
            (method_scores if method_scores else ()) +
            (scorer_scores if scorer_scores else ())
        )
        for column, values in enumerate(model_array.T):
            self.ranksModel.setExtremesFrom(column, values)

        self.ranksModel.wrap(model_array.tolist())
        self.ranksModel.setHorizontalHeaderLabels(('#',) + labels)
        self.ranksView.setColumnWidth(0, 40)

        # Re-apply sort
        try:
            sort_column, sort_order = self.sorting
            if sort_column < len(labels):
                # adds 1 for '#' (discrete count) column
                self.ranksModel.sort(sort_column + 1, sort_order)
                self.ranksView.horizontalHeader().setSortIndicator(sort_column + 1, sort_order)
        except ValueError:
            pass

        self.autoSelection()
        self.Outputs.scores.send(self.create_scores_table(labels))

    def on_select(self):
        # Save indices of attributes in the original, unsorted domain
        self.selected_rows = list(self.ranksModel.mapToSourceRows([
            i.row() for i in self.ranksView.selectionModel().selectedRows(0)]))
        self.commit()

    def setSelectionMethod(self, method):
        self.selectionMethod = method
        self.selectButtons.button(method).setChecked(True)
        self.autoSelection()

    def autoSelection(self):
        selModel = self.ranksView.selectionModel()
        model = self.ranksModel
        rowCount = model.rowCount()
        columnCount = model.columnCount()

        if self.selectionMethod == OWRank.SelectNone:
            selection = QItemSelection()
        elif self.selectionMethod == OWRank.SelectAll:
            selection = QItemSelection(
                model.index(0, 0),
                model.index(rowCount - 1, columnCount - 1)
            )
        elif self.selectionMethod == OWRank.SelectNBest:
            nSelected = min(self.nSelected, rowCount)
            selection = QItemSelection(
                model.index(0, 0),
                model.index(nSelected - 1, columnCount - 1)
            )
        else:
            selection = QItemSelection()
            if self.selected_rows is not None:
                for row in model.mapFromSourceRows(self.selected_rows):
                    selection.append(QItemSelectionRange(
                        model.index(row, 0), model.index(row, columnCount - 1)))

        selModel.select(selection, QItemSelectionModel.ClearAndSelect)

    def headerClick(self, index):
        if index >= 1 and self.selectionMethod == OWRank.SelectNBest:
            # Reselect the top ranked attributes
            self.autoSelection()

        # Store the header states
        sort_order = self.ranksModel.sortOrder()
        sort_column = self.ranksModel.sortColumn() - 1  # -1 for '#' (discrete count) column
        self.sorting = (sort_column, sort_order)

    def methodSelectionChanged(self, state, method_name):
        if state == Qt.Checked:
            self.selected_methods.add(method_name)
        elif method_name in self.selected_methods:
            self.selected_methods.remove(method_name)

        self.updateScores()

    def send_report(self):
        if not self.data:
            return
        self.report_domain("Input", self.data.domain)
        self.report_table("Ranks", self.ranksView, num_format="{:.3f}")
        if self.out_domain_desc is not None:
            self.report_items("Output", self.out_domain_desc)

    def commit(self):
        selected_attrs = []
        if self.data is not None:
            selected_attrs = [self.data.domain.attributes[i]
                              for i in self.selected_rows]
        if not selected_attrs:
            self.Outputs.reduced_data.send(None)
            self.Outputs.features.send(None)
            self.out_domain_desc = None
        else:
            reduced_domain = Domain(
                selected_attrs, self.data.domain.class_var, self.data.domain.metas)
            data = self.data.transform(reduced_domain)
            self.Outputs.reduced_data.send(data)
            self.Outputs.features.send(AttributeList(selected_attrs))
            self.out_domain_desc = report.describe_domain(data.domain)

    def create_scores_table(self, labels):
        model_list = self.ranksModel.tolist()
        if not model_list or len(model_list[0]) == 1:  # Empty or just n_values column
            return None

        domain = Domain([ContinuousVariable(label) for label in labels],
                        metas=[StringVariable("Feature")])

        # Prevent np.inf scores
        finfo = np.finfo(np.float64)
        scores = np.clip(np.array(model_list)[:, 1:], finfo.min, finfo.max)

        feature_names = np.array([a.name for a in self.data.domain.attributes])
        # Reshape to 2d array as Table does not like 1d arrays
        feature_names = feature_names[:, None]

        new_table = Table(domain, scores, metas=feature_names)
        new_table.name = "Feature Scores"
        return new_table

    @classmethod
    def migrate_settings(cls, settings, version):
        # If older settings, restore sort header to default
        # Saved selected_rows will likely be incorrect
        if version is None or version < 2:
            column, order = 0, Qt.DescendingOrder
            headerState = settings.pop("headerState", None)

            # Lacking knowledge of last problemType, use discrete ranks view's ordering
            if isinstance(headerState, (tuple, list)):
                headerState = headerState[0]

            if isinstance(headerState, bytes):
                hview = QHeaderView(Qt.Horizontal)
                hview.restoreState(headerState)
                column, order = hview.sortIndicatorSection() - 1, hview.sortIndicatorOrder()
            settings["sorting"] = (column, order)

    @classmethod
    def migrate_context(cls, context, version):
        if version is None or version < 2:
            # Old selection was saved as sorted indices. New selection is original indices.
            # Since we can't devise the latter without first computing the ranks,
            # just reset the selection to avoid confusion.
            context.values['selected_rows'] = []


if __name__ == "__main__":  # pragma: no cover
    from Orange.classification import RandomForestLearner
    previewer = WidgetPreview(OWRank)
    previewer.run(Table("heart_disease.tab"), no_exit=True)
    previewer.send_signals(
        set_learner=(RandomForestLearner(), (3, 'Learner', None)))
    previewer.run()

    # pylint: disable=pointless-string-statement
    """
    WidgetPreview(OWRank).run(
        set_learner=(RandomForestLearner(), (3, 'Learner', None)),
        set_data=Table("heart_disease.tab"))
"""

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user