{
    "file_diffs": [
        {
            "old_file_content": "from functools import partial\nfrom typing import Optional, Dict, Tuple\n\nfrom AnyQt.QtWidgets import QWidget, QGridLayout\nfrom AnyQt.QtWidgets import QListView\nfrom AnyQt.QtCore import (\n    Qt, QTimer, QSortFilterProxyModel, QItemSelection, QItemSelectionModel,\n    QMimeData, QAbstractItemModel\n)\n\nfrom Orange.data import Domain, Variable\nfrom Orange.widgets import gui, widget\nfrom Orange.widgets.settings import (\n    ContextSetting, Setting, DomainContextHandler\n)\nfrom Orange.widgets.utils import vartype\nfrom Orange.widgets.utils.listfilter import (\n    VariablesListItemView, slices, variables_filter\n)\nfrom Orange.widgets.utils.widgetpreview import WidgetPreview\nfrom Orange.widgets.utils.state_summary import format_summary_details\nfrom Orange.widgets.widget import Input, Output, AttributeList, Msg\nfrom Orange.data.table import Table\nfrom Orange.widgets.utils.itemmodels import VariableListModel\nimport Orange\n\n\ndef source_model(view):\n    \"\"\" Return the source model for the Qt Item View if it uses\n    the QSortFilterProxyModel.\n    \"\"\"\n    if isinstance(view.model(), QSortFilterProxyModel):\n        return view.model().sourceModel()\n    else:\n        return view.model()\n\n\ndef source_indexes(indexes, view):\n    \"\"\" Map model indexes through a views QSortFilterProxyModel\n    \"\"\"\n    model = view.model()\n    if isinstance(model, QSortFilterProxyModel):\n        return list(map(model.mapToSource, indexes))\n    else:\n        return indexes\n\n\nclass VariablesListItemModel(VariableListModel):\n    \"\"\"\n    An Variable list item model specialized for Drag and Drop.\n    \"\"\"\n    MIME_TYPE = \"application/x-Orange-VariableListModelData\"\n\n    def flags(self, index):\n        flags = super().flags(index)\n        if index.isValid():\n            flags |= Qt.ItemIsDragEnabled\n        else:\n            flags |= Qt.ItemIsDropEnabled\n        return flags\n\n    @staticmethod\n    def supportedDropActions():\n        return Qt.MoveAction  # pragma: no cover\n\n    @staticmethod\n    def supportedDragActions():\n        return Qt.MoveAction  # pragma: no cover\n\n    def mimeTypes(self):\n        return [self.MIME_TYPE]\n\n    def mimeData(self, indexlist):\n        \"\"\"\n        Reimplemented.\n\n        For efficiency reasons only the variable instances are set on the\n        mime data (under `'_items'` property)\n        \"\"\"\n        items = [self[index.row()] for index in indexlist]\n        mime = QMimeData()\n        # the encoded 'data' is empty, variables are passed by properties\n        mime.setData(self.MIME_TYPE, b'')\n        mime.setProperty(\"_items\", items)\n        return mime\n\n    def dropMimeData(self, mime, action, row, column, parent):\n        \"\"\"\n        Reimplemented.\n        \"\"\"\n        if action == Qt.IgnoreAction:\n            return True  # pragma: no cover\n        if not mime.hasFormat(self.MIME_TYPE):\n            return False  # pragma: no cover\n        variables = mime.property(\"_items\")\n        if variables is None:\n            return False  # pragma: no cover\n        if row < 0:\n            row = self.rowCount()\n\n        self[row:row] = variables\n        return True\n\n\nclass SelectAttributesDomainContextHandler(DomainContextHandler):\n    def encode_setting(self, context, setting, value):\n        if setting.name == 'domain_role_hints':\n            value = {(var.name, vartype(var)): role_i\n                     for var, role_i in value.items()}\n        return super().encode_setting(context, setting, value)\n\n    def decode_setting(self, setting, value, domain=None, *_args):\n        decoded = super().decode_setting(setting, value, domain)\n        if setting.name == 'domain_role_hints':\n            decoded = {domain[name]: role_i\n                       for (name, _), role_i in decoded.items()}\n        return decoded\n\n    def match(self, context, domain, attrs, metas):\n        if context.attributes == attrs and context.metas == metas:\n            return self.PERFECT_MATCH\n\n        if not \"domain_role_hints\" in context.values:\n            return self.NO_MATCH\n\n        all_vars = attrs.copy()\n        all_vars.update(metas)\n        value = context.values[\"domain_role_hints\"][0]\n        assigned = [desc for desc, (role, _) in value.items()\n                    if role != \"available\"]\n        if not assigned:\n            return self.NO_MATCH\n        return sum(all_vars.get(attr) == vtype for attr, vtype in assigned) \\\n               / len(assigned)\n\n    def filter_value(self, setting, data, domain, attrs, metas):\n        if setting.name != \"domain_role_hints\":\n            return super().filter_value(setting, data, domain, attrs, metas)\n\n        all_vars = attrs.copy()\n        all_vars.update(metas)\n        value = data[\"domain_role_hints\"][0].items()\n        data[\"domain_role_hints\"] = {desc: role_i\n                                     for desc, role_i in value\n                                     if all_vars.get(desc[0]) == desc[1]}\n\n\nclass OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))\n\n\nif __name__ == \"__main__\":  # pragma: no cover\n    brown = Orange.data.Table(\"brown-selected\")\n    feats = AttributeList(brown.domain.attributes[:2])\n    WidgetPreview(OWSelectAttributes).run(set_data=brown, set_features=feats)\n",
            "new_file_content": "from functools import partial\nfrom typing import Optional, Dict, Tuple\n\nfrom AnyQt.QtWidgets import QWidget, QGridLayout\nfrom AnyQt.QtWidgets import QListView\nfrom AnyQt.QtCore import (\n    Qt, QTimer, QSortFilterProxyModel, QItemSelection, QItemSelectionModel,\n    QMimeData, QAbstractItemModel\n)\n\nfrom Orange.data import Domain, Variable\nfrom Orange.widgets import gui, widget\nfrom Orange.widgets.settings import (\n    ContextSetting, Setting, DomainContextHandler\n)\nfrom Orange.widgets.utils import vartype\nfrom Orange.widgets.utils.listfilter import (\n    VariablesListItemView, slices, variables_filter\n)\nfrom Orange.widgets.utils.widgetpreview import WidgetPreview\nfrom Orange.widgets.utils.state_summary import format_summary_details\nfrom Orange.widgets.widget import Input, Output, AttributeList, Msg\nfrom Orange.data.table import Table\nfrom Orange.widgets.utils.itemmodels import VariableListModel\nimport Orange\n\n\ndef source_model(view):\n    \"\"\" Return the source model for the Qt Item View if it uses\n    the QSortFilterProxyModel.\n    \"\"\"\n    if isinstance(view.model(), QSortFilterProxyModel):\n        return view.model().sourceModel()\n    else:\n        return view.model()\n\n\ndef source_indexes(indexes, view):\n    \"\"\" Map model indexes through a views QSortFilterProxyModel\n    \"\"\"\n    model = view.model()\n    if isinstance(model, QSortFilterProxyModel):\n        return list(map(model.mapToSource, indexes))\n    else:\n        return indexes\n\n\nclass VariablesListItemModel(VariableListModel):\n    \"\"\"\n    An Variable list item model specialized for Drag and Drop.\n    \"\"\"\n    MIME_TYPE = \"application/x-Orange-VariableListModelData\"\n\n    def flags(self, index):\n        flags = super().flags(index)\n        if index.isValid():\n            flags |= Qt.ItemIsDragEnabled\n        else:\n            flags |= Qt.ItemIsDropEnabled\n        return flags\n\n    @staticmethod\n    def supportedDropActions():\n        return Qt.MoveAction  # pragma: no cover\n\n    @staticmethod\n    def supportedDragActions():\n        return Qt.MoveAction  # pragma: no cover\n\n    def mimeTypes(self):\n        return [self.MIME_TYPE]\n\n    def mimeData(self, indexlist):\n        \"\"\"\n        Reimplemented.\n\n        For efficiency reasons only the variable instances are set on the\n        mime data (under `'_items'` property)\n        \"\"\"\n        items = [self[index.row()] for index in indexlist]\n        mime = QMimeData()\n        # the encoded 'data' is empty, variables are passed by properties\n        mime.setData(self.MIME_TYPE, b'')\n        mime.setProperty(\"_items\", items)\n        return mime\n\n    def dropMimeData(self, mime, action, row, column, parent):\n        \"\"\"\n        Reimplemented.\n        \"\"\"\n        if action == Qt.IgnoreAction:\n            return True  # pragma: no cover\n        if not mime.hasFormat(self.MIME_TYPE):\n            return False  # pragma: no cover\n        variables = mime.property(\"_items\")\n        if variables is None:\n            return False  # pragma: no cover\n        if row < 0:\n            row = self.rowCount()\n\n        self[row:row] = variables\n        return True\n\n\nclass SelectAttributesDomainContextHandler(DomainContextHandler):\n    def encode_setting(self, context, setting, value):\n        if setting.name == 'domain_role_hints':\n            value = {(var.name, vartype(var)): role_i\n                     for var, role_i in value.items()}\n        return super().encode_setting(context, setting, value)\n\n    def decode_setting(self, setting, value, domain=None, *_args):\n        decoded = super().decode_setting(setting, value, domain)\n        if setting.name == 'domain_role_hints':\n            decoded = {domain[name]: role_i\n                       for (name, _), role_i in decoded.items()}\n        return decoded\n\n    def match(self, context, domain, attrs, metas):\n        if context.attributes == attrs and context.metas == metas:\n            return self.PERFECT_MATCH\n\n        if not \"domain_role_hints\" in context.values:\n            return self.NO_MATCH\n\n        all_vars = attrs.copy()\n        all_vars.update(metas)\n        value = context.values[\"domain_role_hints\"][0]\n        assigned = [desc for desc, (role, _) in value.items()\n                    if role != \"available\"]\n        if not assigned:\n            return self.NO_MATCH\n        return sum(all_vars.get(attr) == vtype for attr, vtype in assigned) \\\n               / len(assigned)\n\n    def filter_value(self, setting, data, domain, attrs, metas):\n        if setting.name != \"domain_role_hints\":\n            return super().filter_value(setting, data, domain, attrs, metas)\n\n        all_vars = attrs.copy()\n        all_vars.update(metas)\n        value = data[\"domain_role_hints\"][0].items()\n        data[\"domain_role_hints\"] = {desc: role_i\n                                     for desc, role_i in value\n                                     if all_vars.get(desc[0]) == desc[1]}\n\n\nclass OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    ignore_new_features = Setting(False)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"ignore_new_features\", \"Ignore new variables by default\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          ignore_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if not self.ignore_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and ignore_new_features selected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))\n\n\nif __name__ == \"__main__\":  # pragma: no cover\n    brown = Orange.data.Table(\"brown-selected\")\n    feats = AttributeList(brown.domain.attributes[:2])\n    WidgetPreview(OWSelectAttributes).run(set_data=brown, set_features=feats)\n",
            "header": {
                "file": {
                    "path": "Orange/widgets/data/owselectcolumns.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "af11f3668",
                "new_commit_hash": "3a385ba69",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Orange/widgets/data/owselectcolumns.py"
            },
            "plus_file": {
                "path": "b/Orange/widgets/data/owselectcolumns.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 168,
                            "length": 7
                        },
                        "new_range": {
                            "start": 168,
                            "length": 7
                        },
                        "section": "class OWSelectAttributes(widget.OWWidget):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)",
                                "type": "context"
                            },
                            {
                                "content": "    domain_role_hints = ContextSetting({})",
                                "type": "context"
                            },
                            {
                                "content": "    use_input_features = Setting(False)",
                                "type": "context"
                            },
                            {
                                "content": "    select_new_features = Setting(True)",
                                "type": "deleted"
                            },
                            {
                                "content": "    ignore_new_features = Setting(False)",
                                "type": "added"
                            },
                            {
                                "content": "    auto_commit = Setting(True)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    class Warning(widget.OWWidget.Warning):",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/widgets/data/owselectcolumns.py",
                            "type": "class",
                            "name": "OWSelectAttributes",
                            "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 148,
                            "end_lineno": 633,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 301,
                            "length": 7
                        },
                        "new_range": {
                            "start": 301,
                            "length": 7
                        },
                        "section": "class OWSelectAttributes(widget.OWWidget):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)",
                                "type": "context"
                            },
                            {
                                "content": "        gui.checkBox(",
                                "type": "context"
                            },
                            {
                                "content": "            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"",
                                "type": "deleted"
                            },
                            {
                                "content": "            bbox, self, \"ignore_new_features\", \"Ignore new variables by default\"",
                                "type": "added"
                            },
                            {
                                "content": "        )",
                                "type": "context"
                            },
                            {
                                "content": "        layout.addWidget(bbox, 3, 0, 1, 3)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/widgets/data/owselectcolumns.py",
                            "type": "class",
                            "name": "OWSelectAttributes",
                            "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 148,
                            "end_lineno": 633,
                            "parent": null
                        },
                        {
                            "file_name": "Orange/widgets/data/owselectcolumns.py",
                            "type": "method",
                            "name": "OWSelectAttributes.__init__",
                            "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 177,
                            "end_lineno": 326,
                            "parent": {
                                "file_name": "Orange/widgets/data/owselectcolumns.py",
                                "type": "class",
                                "name": "OWSelectAttributes",
                                "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 148,
                                "end_lineno": 633,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 390,
                            "length": 7
                        },
                        "new_range": {
                            "start": 390,
                            "length": 7
                        },
                        "section": "class OWSelectAttributes(widget.OWWidget):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        Define hints for selected/unselected features.",
                                "type": "context"
                            },
                            {
                                "content": "        Rules:",
                                "type": "context"
                            },
                            {
                                "content": "        - if context available, restore new features based on checked/unchecked",
                                "type": "context"
                            },
                            {
                                "content": "          select_new_features, context hint should be took into account",
                                "type": "deleted"
                            },
                            {
                                "content": "          ignore_new_features, context hint should be took into account",
                                "type": "added"
                            },
                            {
                                "content": "        - in no context, restore features based on the domain (as selected)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        Parameters",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/widgets/data/owselectcolumns.py",
                            "type": "class",
                            "name": "OWSelectAttributes",
                            "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 148,
                            "end_lineno": 633,
                            "parent": null
                        },
                        {
                            "file_name": "Orange/widgets/data/owselectcolumns.py",
                            "type": "method",
                            "name": "OWSelectAttributes.restore_hints",
                            "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 388,
                            "end_lineno": 423,
                            "parent": {
                                "file_name": "Orange/widgets/data/owselectcolumns.py",
                                "type": "class",
                                "name": "OWSelectAttributes",
                                "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 148,
                                "end_lineno": 633,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 404,
                            "length": 7
                        },
                        "new_range": {
                            "start": 404,
                            "length": 7
                        },
                        "section": "class OWSelectAttributes(widget.OWWidget):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        should appear",
                                "type": "context"
                            },
                            {
                                "content": "        \"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "        domain_hints = {}",
                                "type": "context"
                            },
                            {
                                "content": "        if self.select_new_features or len(self.domain_role_hints) == 0:",
                                "type": "deleted"
                            },
                            {
                                "content": "        if not self.ignore_new_features or len(self.domain_role_hints) == 0:",
                                "type": "added"
                            },
                            {
                                "content": "            # select_new_features selected or no context - restore based on domain",
                                "type": "context"
                            },
                            {
                                "content": "            domain_hints.update(",
                                "type": "context"
                            },
                            {
                                "content": "                self._hints_from_seq(\"attribute\", domain.attributes)",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/widgets/data/owselectcolumns.py",
                            "type": "class",
                            "name": "OWSelectAttributes",
                            "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 148,
                            "end_lineno": 633,
                            "parent": null
                        },
                        {
                            "file_name": "Orange/widgets/data/owselectcolumns.py",
                            "type": "method",
                            "name": "OWSelectAttributes.restore_hints",
                            "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 388,
                            "end_lineno": 423,
                            "parent": {
                                "file_name": "Orange/widgets/data/owselectcolumns.py",
                                "type": "class",
                                "name": "OWSelectAttributes",
                                "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 148,
                                "end_lineno": 633,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 414,
                            "length": 7
                        },
                        "new_range": {
                            "start": 414,
                            "length": 7
                        },
                        "section": "class OWSelectAttributes(widget.OWWidget):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "                self._hints_from_seq(\"class\", domain.class_vars)",
                                "type": "context"
                            },
                            {
                                "content": "            )",
                                "type": "context"
                            },
                            {
                                "content": "        else:",
                                "type": "context"
                            },
                            {
                                "content": "            # if context restored and select_new_features unselected - restore",
                                "type": "deleted"
                            },
                            {
                                "content": "            # if context restored and ignore_new_features selected - restore",
                                "type": "added"
                            },
                            {
                                "content": "            # new features as available",
                                "type": "context"
                            },
                            {
                                "content": "            d = domain.attributes + domain.metas + domain.class_vars",
                                "type": "context"
                            },
                            {
                                "content": "            domain_hints.update(self._hints_from_seq(\"available\", d))",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/widgets/data/owselectcolumns.py",
                            "type": "class",
                            "name": "OWSelectAttributes",
                            "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 148,
                            "end_lineno": 633,
                            "parent": null
                        },
                        {
                            "file_name": "Orange/widgets/data/owselectcolumns.py",
                            "type": "method",
                            "name": "OWSelectAttributes.restore_hints",
                            "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 388,
                            "end_lineno": 423,
                            "parent": {
                                "file_name": "Orange/widgets/data/owselectcolumns.py",
                                "type": "class",
                                "name": "OWSelectAttributes",
                                "content": "class OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 148,
                                "end_lineno": 633,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "# pylint: disable=unsubscriptable-object\nimport unittest\nfrom unittest import TestCase\nfrom unittest.mock import Mock\n\nimport numpy as np\nfrom AnyQt.QtCore import QMimeData, QPoint, Qt\nfrom AnyQt.QtGui import QDragEnterEvent\n\nfrom Orange.data import Table, ContinuousVariable, DiscreteVariable, Domain\nfrom Orange.widgets.settings import ContextSetting\nfrom Orange.widgets.utils import vartype\nfrom Orange.widgets.utils.state_summary import format_summary_details\nfrom Orange.widgets.tests.base import WidgetTest\nfrom Orange.widgets.data.owselectcolumns \\\n    import OWSelectAttributes, VariablesListItemModel, \\\n    SelectAttributesDomainContextHandler\nfrom Orange.widgets.data.owrank import OWRank\nfrom Orange.widgets.widget import AttributeList\n\nContinuous = vartype(ContinuousVariable(\"c\"))\nDiscrete = vartype(DiscreteVariable(\"d\"))\n\n\nclass TestSelectAttributesDomainContextHandler(TestCase):\n    def setUp(self):\n        self.domain = Domain(\n            attributes=[ContinuousVariable('c1'),\n                        DiscreteVariable('d1', values='abc'),\n                        DiscreteVariable('d2', values='def')],\n            class_vars=[DiscreteVariable('d3', values='ghi')],\n            metas=[ContinuousVariable('c2'),\n                   DiscreteVariable('d4', values='jkl')]\n        )\n        self.args = (self.domain,\n                     {'c1': Continuous, 'd1': Discrete,\n                      'd2': Discrete, 'd3': Discrete},\n                     {'c2': Continuous, 'd4': Discrete, })\n\n        self.handler = SelectAttributesDomainContextHandler(first_match=False)\n        self.handler.read_defaults = lambda: None\n\n    def test_open_context(self):\n        self.handler.bind(SimpleWidget)\n        context = Mock(\n            attributes=self.args[1], metas=self.args[2], values=dict(\n                domain_role_hints=({('d1', Discrete): ('available', 0),\n                                    ('d2', Discrete): ('meta', 0),\n                                    ('c1', Continuous): ('attribute', 0),\n                                    ('d3', Discrete): ('attribute', 1),\n                                    ('d4', Discrete): ('attribute', 2),\n                                    ('c2', Continuous): ('class', 0)}, -2),\n                with_metas=[('d1', Discrete), ('d2', Discrete)]\n            ))\n        self.handler.global_contexts = \\\n            [Mock(values={}), context, Mock(values={})]\n\n        widget = SimpleWidget()\n        self.handler.initialize(widget)\n        domain = self.args[0]\n        self.handler.open_context(widget, domain)\n        self.assertEqual(widget.domain_role_hints,\n                         {domain['d1']: ('available', 0),\n                          domain['d2']: ('meta', 0),\n                          domain['c1']: ('attribute', 0),\n                          domain['d3']: ('attribute', 1),\n                          domain['d4']: ('attribute', 2),\n                          domain['c2']: ('class', 0)})\n\n    def test_open_context_with_imperfect_match(self):\n        self.handler.bind(SimpleWidget)\n        context1 = Mock(values=dict(\n            domain_role_hints=({('d1', Discrete): ('attribute', 0),\n                                ('m2', Discrete): ('meta', 0)}, -2)\n        ))\n        context = Mock(values=dict(\n            domain_role_hints=({('d1', Discrete): ('available', 0),\n                                ('d2', Discrete): ('meta', 0),\n                                ('c1', Continuous): ('attribute', 0),\n                                ('d6', Discrete): ('attribute', 1),\n                                ('d7', Discrete): ('attribute', 2),\n                                ('c2', Continuous): ('class', 0)}, -2)\n        ))\n        self.handler.global_contexts = \\\n            [Mock(values={}), context1, context, Mock(values={})]\n\n        widget = SimpleWidget()\n        self.handler.initialize(widget)\n        domain = self.args[0]\n        self.handler.open_context(widget, domain)\n\n        self.assertEqual(widget.domain_role_hints,\n                         {domain['d1']: ('available', 0),\n                          domain['d2']: ('meta', 0),\n                          domain['c1']: ('attribute', 0),\n                          domain['c2']: ('class', 0)})\n\n\nclass TestModel(TestCase):\n    def test_drop_mime(self):\n        iris = Table(\"iris\")\n        m = VariablesListItemModel(iris.domain.variables)\n        mime = m.mimeData([m.index(1, 0)])\n        self.assertTrue(mime.hasFormat(VariablesListItemModel.MIME_TYPE))\n        assert m.dropMimeData(mime, Qt.MoveAction, 5, 0, m.index(-1, -1))\n        self.assertIs(m[5], m[1])\n        assert m.dropMimeData(mime, Qt.MoveAction, -1, -1, m.index(-1, -1))\n        self.assertIs(m[6], m[1])\n\n    def test_flags(self):\n        m = VariablesListItemModel([ContinuousVariable(\"X\")])\n        flags = m.flags(m.index(0))\n        self.assertTrue(flags & Qt.ItemIsDragEnabled)\n        self.assertFalse(flags & Qt.ItemIsDropEnabled)\n        # 'invalid' index is drop enabled -> indicates insertion capability\n        flags = m.flags(m.index(-1, -1))\n        self.assertTrue(flags & Qt.ItemIsDropEnabled)\n\n\nclass SimpleWidget:\n    domain_role_hints = ContextSetting({})\n    required = ContextSetting(\"\", required=ContextSetting.REQUIRED)\n\n    def retrieveSpecificSettings(self):\n        pass\n\n    def storeSpecificSettings(self):\n        pass\n\n\nclass TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n",
            "new_file_content": "# pylint: disable=unsubscriptable-object\nimport unittest\nfrom unittest import TestCase\nfrom unittest.mock import Mock\n\nimport numpy as np\nfrom AnyQt.QtCore import QMimeData, QPoint, Qt\nfrom AnyQt.QtGui import QDragEnterEvent\n\nfrom Orange.data import Table, ContinuousVariable, DiscreteVariable, Domain\nfrom Orange.widgets.settings import ContextSetting\nfrom Orange.widgets.utils import vartype\nfrom Orange.widgets.utils.state_summary import format_summary_details\nfrom Orange.widgets.tests.base import WidgetTest\nfrom Orange.widgets.data.owselectcolumns \\\n    import OWSelectAttributes, VariablesListItemModel, \\\n    SelectAttributesDomainContextHandler\nfrom Orange.widgets.data.owrank import OWRank\nfrom Orange.widgets.widget import AttributeList\n\nContinuous = vartype(ContinuousVariable(\"c\"))\nDiscrete = vartype(DiscreteVariable(\"d\"))\n\n\nclass TestSelectAttributesDomainContextHandler(TestCase):\n    def setUp(self):\n        self.domain = Domain(\n            attributes=[ContinuousVariable('c1'),\n                        DiscreteVariable('d1', values='abc'),\n                        DiscreteVariable('d2', values='def')],\n            class_vars=[DiscreteVariable('d3', values='ghi')],\n            metas=[ContinuousVariable('c2'),\n                   DiscreteVariable('d4', values='jkl')]\n        )\n        self.args = (self.domain,\n                     {'c1': Continuous, 'd1': Discrete,\n                      'd2': Discrete, 'd3': Discrete},\n                     {'c2': Continuous, 'd4': Discrete, })\n\n        self.handler = SelectAttributesDomainContextHandler(first_match=False)\n        self.handler.read_defaults = lambda: None\n\n    def test_open_context(self):\n        self.handler.bind(SimpleWidget)\n        context = Mock(\n            attributes=self.args[1], metas=self.args[2], values=dict(\n                domain_role_hints=({('d1', Discrete): ('available', 0),\n                                    ('d2', Discrete): ('meta', 0),\n                                    ('c1', Continuous): ('attribute', 0),\n                                    ('d3', Discrete): ('attribute', 1),\n                                    ('d4', Discrete): ('attribute', 2),\n                                    ('c2', Continuous): ('class', 0)}, -2),\n                with_metas=[('d1', Discrete), ('d2', Discrete)]\n            ))\n        self.handler.global_contexts = \\\n            [Mock(values={}), context, Mock(values={})]\n\n        widget = SimpleWidget()\n        self.handler.initialize(widget)\n        domain = self.args[0]\n        self.handler.open_context(widget, domain)\n        self.assertEqual(widget.domain_role_hints,\n                         {domain['d1']: ('available', 0),\n                          domain['d2']: ('meta', 0),\n                          domain['c1']: ('attribute', 0),\n                          domain['d3']: ('attribute', 1),\n                          domain['d4']: ('attribute', 2),\n                          domain['c2']: ('class', 0)})\n\n    def test_open_context_with_imperfect_match(self):\n        self.handler.bind(SimpleWidget)\n        context1 = Mock(values=dict(\n            domain_role_hints=({('d1', Discrete): ('attribute', 0),\n                                ('m2', Discrete): ('meta', 0)}, -2)\n        ))\n        context = Mock(values=dict(\n            domain_role_hints=({('d1', Discrete): ('available', 0),\n                                ('d2', Discrete): ('meta', 0),\n                                ('c1', Continuous): ('attribute', 0),\n                                ('d6', Discrete): ('attribute', 1),\n                                ('d7', Discrete): ('attribute', 2),\n                                ('c2', Continuous): ('class', 0)}, -2)\n        ))\n        self.handler.global_contexts = \\\n            [Mock(values={}), context1, context, Mock(values={})]\n\n        widget = SimpleWidget()\n        self.handler.initialize(widget)\n        domain = self.args[0]\n        self.handler.open_context(widget, domain)\n\n        self.assertEqual(widget.domain_role_hints,\n                         {domain['d1']: ('available', 0),\n                          domain['d2']: ('meta', 0),\n                          domain['c1']: ('attribute', 0),\n                          domain['c2']: ('class', 0)})\n\n\nclass TestModel(TestCase):\n    def test_drop_mime(self):\n        iris = Table(\"iris\")\n        m = VariablesListItemModel(iris.domain.variables)\n        mime = m.mimeData([m.index(1, 0)])\n        self.assertTrue(mime.hasFormat(VariablesListItemModel.MIME_TYPE))\n        assert m.dropMimeData(mime, Qt.MoveAction, 5, 0, m.index(-1, -1))\n        self.assertIs(m[5], m[1])\n        assert m.dropMimeData(mime, Qt.MoveAction, -1, -1, m.index(-1, -1))\n        self.assertIs(m[6], m[1])\n\n    def test_flags(self):\n        m = VariablesListItemModel([ContinuousVariable(\"X\")])\n        flags = m.flags(m.index(0))\n        self.assertTrue(flags & Qt.ItemIsDragEnabled)\n        self.assertFalse(flags & Qt.ItemIsDropEnabled)\n        # 'invalid' index is drop enabled -> indicates insertion capability\n        flags = m.flags(m.index(-1, -1))\n        self.assertTrue(flags & Qt.ItemIsDropEnabled)\n\n\nclass SimpleWidget:\n    domain_role_hints = ContextSetting({})\n    required = ContextSetting(\"\", required=ContextSetting.REQUIRED)\n\n    def retrieveSpecificSettings(self):\n        pass\n\n    def storeSpecificSettings(self):\n        pass\n\n\nclass TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When ignore_new_features unchecked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertFalse(self.widget.ignore_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When ignore_new_features checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # select ignore_new_features\n        self.widget.controls.ignore_new_features.click()\n        self.assertTrue(self.widget.ignore_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if ignore_new_features checked all new features goes in the\n        # available attributes column\n        self.assertTrue(self.widget.ignore_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n",
            "header": {
                "file": {
                    "path": "Orange/widgets/data/tests/test_owselectcolumns.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "21bb0a9c9",
                "new_commit_hash": "b7f8498ce",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Orange/widgets/data/tests/test_owselectcolumns.py"
            },
            "plus_file": {
                "path": "b/Orange/widgets/data/tests/test_owselectcolumns.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 415,
                            "length": 7
                        },
                        "new_range": {
                            "start": 415,
                            "length": 7
                        },
                        "section": "class TestOWSelectAttributes(WidgetTest):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_select_new_features(self):",
                                "type": "context"
                            },
                            {
                                "content": "        \"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "        When select_new_features checked new attributes must appear in one of",
                                "type": "deleted"
                            },
                            {
                                "content": "        When ignore_new_features unchecked new attributes must appear in one of",
                                "type": "added"
                            },
                            {
                                "content": "        selected columns. Test with fist make context remember attributes of",
                                "type": "context"
                            },
                            {
                                "content": "        reduced domain and then testing with full domain. Features in missing",
                                "type": "context"
                            },
                            {
                                "content": "        in reduced domain must appears as seleceted.",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                            "type": "method",
                            "name": "TestOWSelectAttributes.test_select_new_features",
                            "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 416,
                            "end_lineno": 451,
                            "parent": {
                                "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                                "type": "class",
                                "name": "TestOWSelectAttributes",
                                "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 131,
                                "end_lineno": 495,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                            "type": "class",
                            "name": "TestOWSelectAttributes",
                            "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 131,
                            "end_lineno": 495,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 445,
                            "length": 14
                        },
                        "new_range": {
                            "start": 445,
                            "length": 14
                        },
                        "section": "class TestOWSelectAttributes(WidgetTest):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        # if select_new_features checked all new features goes in the selected",
                                "type": "context"
                            },
                            {
                                "content": "        # features columns - domain equal original",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertTrue(self.widget.select_new_features)",
                                "type": "deleted"
                            },
                            {
                                "content": "        self.assertFalse(self.widget.ignore_new_features)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertTupleEqual(data.domain.metas, output.domain.metas)",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(data.domain.class_var, output.domain.class_var)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_unselect_new_features(self):",
                                "type": "context"
                            },
                            {
                                "content": "        \"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "        When select_new_features not checked new attributes must appear in one",
                                "type": "deleted"
                            },
                            {
                                "content": "        When ignore_new_features checked new attributes must appear in one",
                                "type": "added"
                            },
                            {
                                "content": "        available attributes column. Test with fist make context remember",
                                "type": "context"
                            },
                            {
                                "content": "        attributes of reduced domain and then testing with full domain.",
                                "type": "context"
                            },
                            {
                                "content": "        Features in missing in reduced domain must appears as not seleceted.",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                            "type": "method",
                            "name": "TestOWSelectAttributes.test_unselect_new_features",
                            "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 453,
                            "end_lineno": 495,
                            "parent": {
                                "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                                "type": "class",
                                "name": "TestOWSelectAttributes",
                                "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 131,
                                "end_lineno": 495,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                            "type": "method",
                            "name": "TestOWSelectAttributes.test_select_new_features",
                            "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 416,
                            "end_lineno": 451,
                            "parent": {
                                "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                                "type": "class",
                                "name": "TestOWSelectAttributes",
                                "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 131,
                                "end_lineno": 495,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                            "type": "class",
                            "name": "TestOWSelectAttributes",
                            "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 131,
                            "end_lineno": 495,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 468,
                            "length": 9
                        },
                        "new_range": {
                            "start": 468,
                            "length": 9
                        },
                        "section": "class TestOWSelectAttributes(WidgetTest):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        # make context remember features in reduced domain",
                                "type": "context"
                            },
                            {
                                "content": "        self.send_signal(self.widget.Inputs.data, new_data)",
                                "type": "context"
                            },
                            {
                                "content": "        # unselect select_new_features",
                                "type": "deleted"
                            },
                            {
                                "content": "        self.widget.controls.select_new_features.click()",
                                "type": "deleted"
                            },
                            {
                                "content": "        self.assertFalse(self.widget.select_new_features)",
                                "type": "deleted"
                            },
                            {
                                "content": "        # select ignore_new_features",
                                "type": "added"
                            },
                            {
                                "content": "        self.widget.controls.ignore_new_features.click()",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertTrue(self.widget.ignore_new_features)",
                                "type": "added"
                            },
                            {
                                "content": "        output = self.get_output(self.widget.Outputs.data)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertTupleEqual(",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                            "type": "method",
                            "name": "TestOWSelectAttributes.test_unselect_new_features",
                            "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 453,
                            "end_lineno": 495,
                            "parent": {
                                "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                                "type": "class",
                                "name": "TestOWSelectAttributes",
                                "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 131,
                                "end_lineno": 495,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                            "type": "class",
                            "name": "TestOWSelectAttributes",
                            "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 131,
                            "end_lineno": 495,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 483,
                            "length": 9
                        },
                        "new_range": {
                            "start": 483,
                            "length": 9
                        },
                        "section": "class TestOWSelectAttributes(WidgetTest):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        self.send_signal(self.widget.Inputs.data, data)",
                                "type": "context"
                            },
                            {
                                "content": "        output = self.get_output(self.widget.Outputs.data)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        # if select_new_features not checked all new features goes in the",
                                "type": "deleted"
                            },
                            {
                                "content": "        # if ignore_new_features checked all new features goes in the",
                                "type": "added"
                            },
                            {
                                "content": "        # available attributes column",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertFalse(self.widget.select_new_features)",
                                "type": "deleted"
                            },
                            {
                                "content": "        self.assertTrue(self.widget.ignore_new_features)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertTupleEqual(new_domain.metas, output.domain.metas)",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(new_domain.class_var, output.domain.class_var)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                            "type": "method",
                            "name": "TestOWSelectAttributes.test_unselect_new_features",
                            "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 453,
                            "end_lineno": 495,
                            "parent": {
                                "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                                "type": "class",
                                "name": "TestOWSelectAttributes",
                                "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 131,
                                "end_lineno": 495,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "Orange/widgets/data/tests/test_owselectcolumns.py",
                            "type": "class",
                            "name": "TestOWSelectAttributes",
                            "content": "class TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When select_new_features checked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertTrue(self.widget.select_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When select_new_features not checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # unselect select_new_features\n        self.widget.controls.select_new_features.click()\n        self.assertFalse(self.widget.select_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features not checked all new features goes in the\n        # available attributes column\n        self.assertFalse(self.widget.select_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 131,
                            "end_lineno": 495,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "a4c46c8ccad1f694d1a78f7b929cd861bd179237^",
    "new_commit_hash": "a4c46c8ccad1f694d1a78f7b929cd861bd179237",
    "commit_message": "Select columns: rename Select new features to Ignore new variables by default",
    "commit_date": "2021-02-05T11:20:01+01:00",
    "metadata": {}
}
{
    "repo_name": "orange3",
    "new_commit_hash": "a4c46c8ccad1f694d1a78f7b929cd861bd179237",
    "test_file_codes": [
        "# pylint: disable=unsubscriptable-object\nimport unittest\nfrom unittest import TestCase\nfrom unittest.mock import Mock\n\nimport numpy as np\nfrom AnyQt.QtCore import QMimeData, QPoint, Qt\nfrom AnyQt.QtGui import QDragEnterEvent\n\nfrom Orange.data import Table, ContinuousVariable, DiscreteVariable, Domain\nfrom Orange.widgets.settings import ContextSetting\nfrom Orange.widgets.utils import vartype\nfrom Orange.widgets.utils.state_summary import format_summary_details\nfrom Orange.widgets.tests.base import WidgetTest\nfrom Orange.widgets.data.owselectcolumns \\\n    import OWSelectAttributes, VariablesListItemModel, \\\n    SelectAttributesDomainContextHandler\nfrom Orange.widgets.data.owrank import OWRank\nfrom Orange.widgets.widget import AttributeList\n\nContinuous = vartype(ContinuousVariable(\"c\"))\nDiscrete = vartype(DiscreteVariable(\"d\"))\n\n\nclass TestSelectAttributesDomainContextHandler(TestCase):\n    def setUp(self):\n        self.domain = Domain(\n            attributes=[ContinuousVariable('c1'),\n                        DiscreteVariable('d1', values='abc'),\n                        DiscreteVariable('d2', values='def')],\n            class_vars=[DiscreteVariable('d3', values='ghi')],\n            metas=[ContinuousVariable('c2'),\n                   DiscreteVariable('d4', values='jkl')]\n        )\n        self.args = (self.domain,\n                     {'c1': Continuous, 'd1': Discrete,\n                      'd2': Discrete, 'd3': Discrete},\n                     {'c2': Continuous, 'd4': Discrete, })\n\n        self.handler = SelectAttributesDomainContextHandler(first_match=False)\n        self.handler.read_defaults = lambda: None\n\n    def test_open_context(self):\n        self.handler.bind(SimpleWidget)\n        context = Mock(\n            attributes=self.args[1], metas=self.args[2], values=dict(\n                domain_role_hints=({('d1', Discrete): ('available', 0),\n                                    ('d2', Discrete): ('meta', 0),\n                                    ('c1', Continuous): ('attribute', 0),\n                                    ('d3', Discrete): ('attribute', 1),\n                                    ('d4', Discrete): ('attribute', 2),\n                                    ('c2', Continuous): ('class', 0)}, -2),\n                with_metas=[('d1', Discrete), ('d2', Discrete)]\n            ))\n        self.handler.global_contexts = \\\n            [Mock(values={}), context, Mock(values={})]\n\n        widget = SimpleWidget()\n        self.handler.initialize(widget)\n        domain = self.args[0]\n        self.handler.open_context(widget, domain)\n        self.assertEqual(widget.domain_role_hints,\n                         {domain['d1']: ('available', 0),\n                          domain['d2']: ('meta', 0),\n                          domain['c1']: ('attribute', 0),\n                          domain['d3']: ('attribute', 1),\n                          domain['d4']: ('attribute', 2),\n                          domain['c2']: ('class', 0)})\n\n    def test_open_context_with_imperfect_match(self):\n        self.handler.bind(SimpleWidget)\n        context1 = Mock(values=dict(\n            domain_role_hints=({('d1', Discrete): ('attribute', 0),\n                                ('m2', Discrete): ('meta', 0)}, -2)\n        ))\n        context = Mock(values=dict(\n            domain_role_hints=({('d1', Discrete): ('available', 0),\n                                ('d2', Discrete): ('meta', 0),\n                                ('c1', Continuous): ('attribute', 0),\n                                ('d6', Discrete): ('attribute', 1),\n                                ('d7', Discrete): ('attribute', 2),\n                                ('c2', Continuous): ('class', 0)}, -2)\n        ))\n        self.handler.global_contexts = \\\n            [Mock(values={}), context1, context, Mock(values={})]\n\n        widget = SimpleWidget()\n        self.handler.initialize(widget)\n        domain = self.args[0]\n        self.handler.open_context(widget, domain)\n\n        self.assertEqual(widget.domain_role_hints,\n                         {domain['d1']: ('available', 0),\n                          domain['d2']: ('meta', 0),\n                          domain['c1']: ('attribute', 0),\n                          domain['c2']: ('class', 0)})\n\n\nclass TestModel(TestCase):\n    def test_drop_mime(self):\n        iris = Table(\"iris\")\n        m = VariablesListItemModel(iris.domain.variables)\n        mime = m.mimeData([m.index(1, 0)])\n        self.assertTrue(mime.hasFormat(VariablesListItemModel.MIME_TYPE))\n        assert m.dropMimeData(mime, Qt.MoveAction, 5, 0, m.index(-1, -1))\n        self.assertIs(m[5], m[1])\n        assert m.dropMimeData(mime, Qt.MoveAction, -1, -1, m.index(-1, -1))\n        self.assertIs(m[6], m[1])\n\n    def test_flags(self):\n        m = VariablesListItemModel([ContinuousVariable(\"X\")])\n        flags = m.flags(m.index(0))\n        self.assertTrue(flags & Qt.ItemIsDragEnabled)\n        self.assertFalse(flags & Qt.ItemIsDropEnabled)\n        # 'invalid' index is drop enabled -> indicates insertion capability\n        flags = m.flags(m.index(-1, -1))\n        self.assertTrue(flags & Qt.ItemIsDropEnabled)\n\n\nclass SimpleWidget:\n    domain_role_hints = ContextSetting({})\n    required = ContextSetting(\"\", required=ContextSetting.REQUIRED)\n\n    def retrieveSpecificSettings(self):\n        pass\n\n    def storeSpecificSettings(self):\n        pass\n\n\nclass TestOWSelectAttributes(WidgetTest):\n    def setUp(self):\n        self.widget = self.create_widget(OWSelectAttributes)\n\n    def assertVariableCountsEqual(self, available, used, classattrs, metas=0):\n        self.assertEqual(len(self.widget.available_attrs), available)\n        self.assertEqual(len(self.widget.used_attrs), used)\n        self.assertEqual(len(self.widget.class_attrs), classattrs)\n        self.assertEqual(len(self.widget.meta_attrs), metas)\n\n    def assertControlsEnabled(self, _list, button, box, widget=None):\n        if widget is None:\n            widget = self.widget\n        control = widget.use_features_box\n        self.assertEqual(control.button.isEnabled(), button)\n        self.assertEqual(control.isVisibleTo(widget), box)\n        self.assertEqual(widget.used_attrs_view.isEnabled(), _list)\n        self.assertEqual(widget.up_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.move_attr_button.isEnabled(), _list)\n        self.assertEqual(widget.down_attr_button.isEnabled(), _list)\n        if button:\n            control.button.click()\n            self.assertEqual(control.button.isEnabled(), False)\n\n    def test_multiple_target_variable(self):\n        \"\"\"\n        More than one target variable can be moved to a box for target variables\n        at the same time and moved back as well.\n        GH-2100\n        GH-2086\n        \"\"\"\n        iris = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, iris)\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.move_class_button.click()\n        self.assertVariableCountsEqual(available=0, used=4, classattrs=1)\n\n        self.widget.used_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.used_attrs_view)\n        self.assertVariableCountsEqual(available=4, used=0, classattrs=1)\n\n        self.widget.available_attrs_view.selectAll()\n        self.widget.move_selected(self.widget.class_attrs_view)\n        self.assertVariableCountsEqual(0, 0, 5)\n\n    def test_input_features(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_by_name(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_same_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes))\n\n    def test_input_features_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.attributes[::3])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(10, 6, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             in_features)\n\n    def test_input_features_by_name_sub_domain(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList([DiscreteVariable(attr.name, attr.values)\n                                     for attr in data.domain.attributes[:5]])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(11, 5, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(data.domain.attributes[:5]))\n\n    def test_input_features_diff_domain(self):\n        zoo = Table(\"zoo\")\n        in_features = AttributeList(Table(\"iris\").domain.attributes)\n        self.send_signal(self.widget.Inputs.data, zoo)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 16, 1, 1)\n        self.assertListEqual(self.get_output(self.widget.Outputs.features),\n                             list(zoo.domain.attributes))\n        self.assertTrue(self.widget.Warning.mismatching_domain.is_shown())\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertFalse(self.widget.Warning.mismatching_domain.is_shown())\n\n    def test_input_features_no_data(self):\n        data = Table(\"zoo\")\n        in_features = AttributeList(data.domain.variables + data.domain.metas)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n    def test_input_combinations(self):\n        data = Table(\"iris\")\n        in_features = AttributeList(data.domain.attributes[:2])\n\n        # check initial state\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 4, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 4)\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, True, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove data\n        self.send_signal(self.widget.Inputs.data, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send features\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(0, 0, 0, 0)\n        self.assertIsNone(self.get_output(self.widget.Outputs.features))\n\n        # send data\n        self.send_signal(self.widget.Inputs.data, data)\n        self.assertControlsEnabled(True, False, True)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n        # remove features\n        self.send_signal(self.widget.Inputs.features, None)\n        self.assertControlsEnabled(True, False, False)\n        self.assertVariableCountsEqual(2, 2, 1, 0)\n        self.assertEqual(len(self.get_output(self.widget.Outputs.features)), 2)\n\n    def test_input_features_from_rank(self):\n        data = Table(\"iris\")\n        owrank = self.create_widget(OWRank)\n        self.send_signal(owrank.Inputs.data, data, widget=owrank)\n        rank_features = self.get_output(owrank.Outputs.features, widget=owrank)\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, rank_features)\n        self.assertControlsEnabled(True, True, True)\n        features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(rank_features, features)\n\n    def test_use_features_checked(self):\n        data = Table(\"iris\")\n        attrs = data.domain.attributes\n\n        # prepare stored settings (check \"Use input features\")\n        in_features = AttributeList(attrs[:2])\n        self.send_signal(self.widget.Inputs.data, data)\n        self.send_signal(self.widget.Inputs.features, in_features)\n        self.widget.use_features_box.checkbox.setChecked(True)\n        self.assertControlsEnabled(False, False, True)\n        out_features = self.get_output(self.widget.Outputs.features)\n        self.assertListEqual(out_features, in_features)\n        settings = self.widget.settingsHandler.pack_data(self.widget)\n\n        # \"Use input features\" is checked by default\n        widget = self.create_widget(OWSelectAttributes, settings)\n        in_features = AttributeList(attrs[:3])\n        self.send_signal(widget.Inputs.data, data, widget=widget)\n        self.send_signal(widget.Inputs.features, in_features, widget=widget)\n        self.assertControlsEnabled(False, False, True, widget)\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertListEqual(out_features, in_features)\n\n        # reset \"Features\"\n        widget.reset()\n        out_features = self.get_output(widget.Outputs.features, widget=widget)\n        self.assertFalse(widget.use_features_box.checkbox.isChecked())\n        self.assertListEqual(out_features, AttributeList(attrs))\n        self.assertControlsEnabled(True, True, True, widget)\n\n    def test_used_attrs_supported_types(self):\n        data = Table(\"zoo\")\n        event = self._drag_enter_event(data.domain[:1])\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertTrue(event.isAccepted())\n\n        event = self._drag_enter_event(data.domain.metas)\n        self.widget.used_attrs_view.dragEnterEvent(event)\n        self.assertFalse(event.isAccepted())\n\n    def _drag_enter_event(self, variables):\n        # pylint: disable=attribute-defined-outside-init\n        self.event_data = mime = QMimeData()\n        mime.setProperty(\"_items\", variables)\n        return QDragEnterEvent(QPoint(0, 0), Qt.MoveAction, mime,\n                               Qt.NoButton, Qt.NoModifier)\n\n    def test_move_rows(self):\n        data = Table(\"iris\")[:5]\n        w = self.widget\n        self.send_signal(w.Inputs.data, data)\n        view = w.used_attrs_view\n        model = view.model()\n        selmodel = view.selectionModel()\n        midx = model.index(1, 0)\n        selmodel.select(midx, selmodel.ClearAndSelect)\n\n        w.move_up(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes[:2][::-1] + data.domain.attributes[2:]\n        )\n        w.move_down(view)\n        d1 = self.get_output(w.Outputs.data, w)\n        self.assertEqual(\n            d1.domain.attributes,\n            data.domain.attributes\n        )\n\n    def test_summary(self):\n        \"\"\"Check if status bar is updated when data is received\"\"\"\n        input_sum = self.widget.info.set_input_summary = Mock()\n        output_sum = self.widget.info.set_output_summary = Mock()\n\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n        input_sum.assert_called_with(len(data), format_summary_details(data))\n        output = self.get_output(self.widget.Outputs.data)\n        output_sum.assert_called_with(len(output),\n                                      format_summary_details(output))\n\n        input_sum.reset_mock()\n        output_sum.reset_mock()\n        self.send_signal(self.widget.Inputs.data, None)\n        input_sum.assert_called_once()\n        self.assertEqual(input_sum.call_args[0][0].brief, \"\")\n        output_sum.assert_called_once()\n        self.assertEqual(output_sum.call_args[0][0].brief, \"\")\n\n    def test_domain_new_feature(self):\n        \"\"\" Test scenario when new attribute is added at position 0 \"\"\"\n        data = Table(\"iris\")\n        self.send_signal(self.widget.Inputs.data, data)\n\n        data1 = Table(\n            Domain(\n                (ContinuousVariable(\"a\"),) + data.domain.attributes,\n                data.domain.class_var),\n            np.hstack((np.ones((len(data), 1)), data.X)),\n            data.Y\n        )\n        self.send_signal(self.widget.Inputs.data, data1)\n\n    def test_select_new_features(self):\n        \"\"\"\n        When ignore_new_features unchecked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n        self.assertFalse(self.widget.ignore_new_features)\n        self.assertTupleEqual(data.domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(data.domain.metas, output.domain.metas)\n        self.assertEqual(data.domain.class_var, output.domain.class_var)\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When ignore_new_features checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n\n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n\n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # select ignore_new_features\n        self.widget.controls.ignore_new_features.click()\n        self.assertTrue(self.widget.ignore_new_features)\n        output = self.get_output(self.widget.Outputs.data)\n\n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n\n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n\n        # if ignore_new_features checked all new features goes in the\n        # available attributes column\n        self.assertTrue(self.widget.ignore_new_features)\n        self.assertTupleEqual(new_domain.attributes, output.domain.attributes)\n        self.assertTupleEqual(new_domain.metas, output.domain.metas)\n        self.assertEqual(new_domain.class_var, output.domain.class_var)\n        # test if new attribute was added to unselected attributes\n        self.assertEqual(\n            domain.attributes[-1], list(self.widget.available_attrs)[0]\n        )\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\nCompiling Orange/classification/_tree_scorers.pyx because it changed.\nCompiling Orange/data/_contingency.pyx because it changed.\nCompiling Orange/data/_io.pyx because it changed.\nCompiling Orange/data/_valuecount.pyx because it changed.\nCompiling Orange/data/_variable.pyx because it changed.\nCompiling Orange/distance/_distance.pyx because it changed.\nCompiling Orange/preprocess/_discretize.pyx because it changed.\nCompiling Orange/preprocess/_relieff.pyx because it changed.\nCompiling Orange/projection/_som.pyx because it changed.\n[1/9] Cythonizing Orange/classification/_tree_scorers.pyx\n[2/9] Cythonizing Orange/data/_contingency.pyx\n[3/9] Cythonizing Orange/data/_io.pyx\n[4/9] Cythonizing Orange/data/_valuecount.pyx\n[5/9] Cythonizing Orange/data/_variable.pyx\n[6/9] Cythonizing Orange/distance/_distance.pyx\n[7/9] Cythonizing Orange/preprocess/_discretize.pyx\n[8/9] Cythonizing Orange/preprocess/_relieff.pyx\n[9/9] Cythonizing Orange/projection/_som.pyx\nbuilding 'Orange.classification._tree_scorers' extension\ncreating build\ncreating build/temp.linux-x86_64-3.7\ncreating build/temp.linux-x86_64-3.7/Orange\ncreating build/temp.linux-x86_64-3.7/Orange/classification\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/classification/_tree_scorers.c -o build/temp.linux-x86_64-3.7/Orange/classification/_tree_scorers.o\ncreating build/lib.linux-x86_64-3.7\ncreating build/lib.linux-x86_64-3.7/Orange\ncreating build/lib.linux-x86_64-3.7/Orange/classification\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 build/lib.linux-x86_64-3.7/Orange/classification/_tree_scorers.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._contingency' extension\ncreating build/temp.linux-x86_64-3.7/Orange/data\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/data/_contingency.c -o build/temp.linux-x86_64-3.7/Orange/data/_contingency.o\ncreating build/lib.linux-x86_64-3.7/Orange/data\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 build/lib.linux-x86_64-3.7/Orange/data/_contingency.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._io' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/data/_io.c -o build/temp.linux-x86_64-3.7/Orange/data/_io.o\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 build/lib.linux-x86_64-3.7/Orange/data/_io.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._valuecount' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/data/_valuecount.c -o build/temp.linux-x86_64-3.7/Orange/data/_valuecount.o\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 build/lib.linux-x86_64-3.7/Orange/data/_valuecount.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._variable' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/data/_variable.c -o build/temp.linux-x86_64-3.7/Orange/data/_variable.o\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 build/lib.linux-x86_64-3.7/Orange/data/_variable.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.distance._distance' extension\ncreating build/temp.linux-x86_64-3.7/Orange/distance\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/distance/_distance.c -o build/temp.linux-x86_64-3.7/Orange/distance/_distance.o\ncreating build/lib.linux-x86_64-3.7/Orange/distance\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 build/lib.linux-x86_64-3.7/Orange/distance/_distance.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._discretize' extension\ncreating build/temp.linux-x86_64-3.7/Orange/preprocess\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/preprocess/_discretize.c -o build/temp.linux-x86_64-3.7/Orange/preprocess/_discretize.o\ncreating build/lib.linux-x86_64-3.7/Orange/preprocess\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 build/lib.linux-x86_64-3.7/Orange/preprocess/_discretize.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._relieff' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/preprocess/_relieff.cpp -o build/temp.linux-x86_64-3.7/Orange/preprocess/_relieff.o\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 build/lib.linux-x86_64-3.7/Orange/preprocess/_relieff.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.projection._som' extension\ncreating build/temp.linux-x86_64-3.7/Orange/projection\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/projection/_som.c -o build/temp.linux-x86_64-3.7/Orange/projection/_som.o\ncreating build/lib.linux-x86_64-3.7/Orange/projection\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 build/lib.linux-x86_64-3.7/Orange/projection/_som.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.classification._simple_tree' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/classification/_simple_tree.c -o build/temp.linux-x86_64-3.7/Orange/classification/_simple_tree.o\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 build/lib.linux-x86_64-3.7/Orange/classification/_simple_tree.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.widgets.utils._grid_density' extension\ncreating build/temp.linux-x86_64-3.7/Orange/widgets\ncreating build/temp.linux-x86_64-3.7/Orange/widgets/utils\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/widgets/utils/_grid_density.cpp -o build/temp.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.o\ncreating build/lib.linux-x86_64-3.7/Orange/widgets\ncreating build/lib.linux-x86_64-3.7/Orange/widgets/utils\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 build/lib.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.cpython-37m-x86_64-linux-gnu.so\ncopying build/lib.linux-x86_64-3.7/Orange/classification/_tree_scorers.cpython-37m-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-3.7/Orange/data/_contingency.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_io.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_valuecount.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_variable.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/distance/_distance.cpython-37m-x86_64-linux-gnu.so -> Orange/distance\ncopying build/lib.linux-x86_64-3.7/Orange/preprocess/_discretize.cpython-37m-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-3.7/Orange/preprocess/_relieff.cpython-37m-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-3.7/Orange/projection/_som.cpython-37m-x86_64-linux-gnu.so -> Orange/projection\ncopying build/lib.linux-x86_64-3.7/Orange/classification/_simple_tree.cpython-37m-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.cpython-37m-x86_64-linux-gnu.so -> Orange/widgets/utils\nrunning develop\nrunning egg_info\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'\nadding license file 'LICENSE'\nwriting manifest file 'Orange3.egg-info/SOURCES.txt'\nrunning build_ext\ncopying build/lib.linux-x86_64-3.7/Orange/classification/_tree_scorers.cpython-37m-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-3.7/Orange/data/_contingency.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_io.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_valuecount.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_variable.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/distance/_distance.cpython-37m-x86_64-linux-gnu.so -> Orange/distance\ncopying build/lib.linux-x86_64-3.7/Orange/preprocess/_discretize.cpython-37m-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-3.7/Orange/preprocess/_relieff.cpython-37m-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-3.7/Orange/projection/_som.cpython-37m-x86_64-linux-gnu.so -> Orange/projection\ncopying build/lib.linux-x86_64-3.7/Orange/classification/_simple_tree.cpython-37m-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.cpython-37m-x86_64-linux-gnu.so -> Orange/widgets/utils\nCreating /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/Orange3.egg-link (link to .)\nAdding Orange3 3.28.0.dev0+a4c46c8 to easy-install.pth file\nInstalling orange-canvas script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\n\nInstalled /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237\nProcessing dependencies for Orange3==3.28.0.dev0+a4c46c8\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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for pyqtgraph==0.12.4\nBest match: pyqtgraph 0.12.4\nAdding pyqtgraph 0.12.4 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\nInstalling pip3 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\nInstalling pip3.10 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\nInstalling f2py3 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\nInstalling f2py3.7 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for httpx==0.14.3\nBest match: httpx 0.14.3\nAdding httpx 0.14.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for chardet==3.0.4\nBest match: chardet 3.0.4\nAdding chardet 3.0.4 to easy-install.pth file\nInstalling chardetect script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for PyQtWebEngine==5.15.6\nBest match: PyQtWebEngine 5.15.6\nAdding PyQtWebEngine 5.15.6 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for PyQt5==5.15.10\nBest match: PyQt5 5.15.10\nAdding PyQt5 5.15.10 to easy-install.pth file\nInstalling pylupdate5 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\nInstalling pyrcc5 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\nInstalling pyuic5 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\nInstalling pyftmerge script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\nInstalling pyftsubset script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\nInstalling ttx script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for sniffio==1.3.1\nBest match: sniffio 1.3.1\nAdding sniffio 1.3.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for rfc3986==1.5.0\nBest match: rfc3986 1.5.0\nAdding rfc3986 1.5.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for httpcore==0.10.2\nBest match: httpcore 0.10.2\nAdding httpcore 0.10.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for PyQt5-sip==12.13.0\nBest match: PyQt5-sip 12.13.0\nAdding PyQt5-sip 12.13.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for PyQtWebEngine-Qt5==5.15.16\nBest match: PyQtWebEngine-Qt5 5.15.16\nAdding PyQtWebEngine-Qt5 5.15.16 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for PyQt5-Qt5==5.15.16\nBest match: PyQt5-Qt5 5.15.16\nAdding PyQt5-Qt5 5.15.16 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nSearching for h11==0.9.0\nBest match: h11 0.9.0\nAdding h11 0.9.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages\nFinished processing dependencies for Orange3==3.28.0.dev0+a4c46c8\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 119ms\nPrepared 18 packages in 5ms\nInstalled 18 packages in 101ms\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 53 packages in 349ms\nInstalled 47 packages in 818ms\n + baycomp==1.0.3\n + bottleneck==1.4.0\n + certifi==2024.12.14\n + cffi==1.15.1\n + chardet==3.0.4\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 + h11==0.9.0\n + httpcore==0.10.2\n + httpx==0.14.3\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 + rfc3986==1.5.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 + sniffio==1.3.1\n + threadpoolctl==3.1.0\n + urllib3==2.0.7\n + xlrd==2.0.1\n + xlsxwriter==3.2.0\nResolved 39 packages in 164ms\nInstalled 13 packages in 303ms\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.12.4\n + qasync==0.25.0\n + requests-cache==1.1.1\n + url-normalize==1.4.3\nResolved 2 packages in 3ms\nInstalled 2 packages in 29ms\n + psycopg2==2.9.9\n + pymssql==2.3.2\nResolved 19 packages in 37ms\nInstalled 5 packages in 1.10s\n + catboost==1.2.7\n + graphviz==0.20.1\n + plotly==5.18.0\n + tenacity==8.2.3\n + xgboost==1.6.2\nAudited 2 packages in 46ms\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/classification/_tree_scorers.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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:3413:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 3413 |   __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:4869:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 4869 |   __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:5615:43: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5615 |           for (__pyx_t_19 = 0; __pyx_t_19 < __pyx_t_18; __pyx_t_19+=1) {\n      |                                           ^\nOrange/classification/_tree_scorers.c:5736:39: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5736 |           __pyx_t_20 = ((__pyx_v_left >= __pyx_v_min_leaf) != 0);\n      |                                       ^~\nOrange/classification/_tree_scorers.c:5742:53: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5742 |           __pyx_t_20 = (((__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:7202:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7202 |         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:7857:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7857 |         for (__pyx_t_11 = 0; __pyx_t_11 < __pyx_t_10; __pyx_t_11+=1) {\n      |                                         ^\nOrange/classification/_tree_scorers.c:7917:143: warning: comparison of integer expressions of different signedness: ‘__pyx_t_5numpy_int32_t’ {aka ‘int’} and ‘unsigned int’ [-Wsign-compare]\n 7917 |               __pyx_t_15 = (((*((__pyx_t_5numpy_int32_t *) ( /* dim=0 */ (__pyx_v_indices.data + __pyx_t_14 * __pyx_v_indices.strides[0]) ))) != __pyx_v_i) != 0);\n      |                                                                                                                                               ^~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/data/_contingency.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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:4120:43: warning: ‘__pyx_v_decs’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4120 |           __pyx_v_value = ((__pyx_v_value * __pyx_v_decs) + (__pyx_v_c & 0xf));\n      |                            ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/data/_io.c:4318:24: warning: ‘__pyx_v_value’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4318 |           __pyx_t_10 = PyFloat_FromDouble(__pyx_v_value); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 223, __pyx_L5_error)\n      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:683:40: warning: ‘__pyx_v_attr_index’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n  683 |   #define PyInt_FromLong               PyLong_FromLong\n      |                                        ^~~~~~~~~~~~~~~\nOrange/data/_io.c:1590:7: note: ‘__pyx_v_attr_index’ was declared here\n 1590 |   int __pyx_v_attr_index;\n      |       ^~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:3183:25: warning: ‘__pyx_v_atomp’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3183 |           __pyx_v_atomp = (__pyx_v_atomp + 1);\n      |           ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/data/_valuecount.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/distance/_distance.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/preprocess/_discretize.c:774:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/preprocess/_relieff.cpp:790:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/projection/_som.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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:3863:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3863 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:3862:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3862 |   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:4934:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4934 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:4933:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4933 |   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:4732:223: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4732 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_26, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_27, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_y;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:4307:7: note: ‘__pyx_v_win_y’ was declared here\n 4307 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:4721:223: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4721 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_27, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_26, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_x;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:4306:7: note: ‘__pyx_v_win_x’ was declared here\n 4306 |   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:5682:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 5682 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:5681:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 5681 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_1get_winners’:\nOrange/projection/_som.c:3184:223: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3184 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_22, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_23, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_y;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:2887:7: note: ‘__pyx_v_win_y’ was declared here\n 2887 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:3173:223: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3173 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_23, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_22, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_x;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:2886:7: note: ‘__pyx_v_win_x’ was declared here\n 2886 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_3update’:\nOrange/projection/_som.c:3357:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3357 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\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      |         ^~~~~~~~~~~~\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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_a4c46c8ccad1f694d1a78f7b929cd861bd179237/.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,\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'\n",
    "new_commit_res_code": 1,
    "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_a4c46c8ccad1f694d1a78f7b929cd861bd179237\ncollected 27 items\n\nr2e_tests/test_1.py sss...............F........                          [100%]\n\n=================================== FAILURES ===================================\n___________________ TestOWSelectAttributes.test_minimum_size ___________________\n\nself = <r2e_tests.test_1.TestOWSelectAttributes testMethod=test_minimum_size>\n\n    def test_minimum_size(self):\n        widget = getattr(self, \"widget\", None)\n        if widget is None:\n            self.skipTest(\"minimum size not tested as .widget was not set\")\n>       self.check_minimum_size(widget)\n\n.venv/lib/python3.7/site-packages/orangewidget/tests/base.py:242: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n.venv/lib/python3.7/site-packages/orangewidget/tests/base.py:615: in check_minimum_size\n    self.assertLess(min_size.width(), 800)\nE   AssertionError: 804 not less than 800\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestSelectAttributesDomainContextHandler::test_open_context\nPASSED r2e_tests/test_1.py::TestSelectAttributesDomainContextHandler::test_open_context_with_imperfect_match\nPASSED r2e_tests/test_1.py::TestModel::test_drop_mime\nPASSED r2e_tests/test_1.py::TestModel::test_flags\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_domain_new_feature\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_image_export\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_combinations\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_by_name\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_by_name_sub_domain\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_diff_domain\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_from_rank\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_no_data\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_same_domain\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_sub_domain\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_move_rows\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_msg_base_class\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_multiple_target_variable\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_select_new_features\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_summary\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_unselect_new_features\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_use_features_checked\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_used_attrs_supported_types\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::TestOWSelectAttributes::test_minimum_size - Asser...\n=================== 1 failed, 23 passed, 3 skipped in 5.61s ====================\nWidgets left: 0    Max widgets: 1999 \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_a4c46c8ccad1f694d1a78f7b929cd861bd179237\ncollected 27 items\n\nr2e_tests/test_1.py sss...............F...F.F..                          [100%]\n\n=================================== FAILURES ===================================\n___________________ TestOWSelectAttributes.test_minimum_size ___________________\n\nself = <r2e_tests.test_1.TestOWSelectAttributes testMethod=test_minimum_size>\n\n    def test_minimum_size(self):\n        widget = getattr(self, \"widget\", None)\n        if widget is None:\n            self.skipTest(\"minimum size not tested as .widget was not set\")\n>       self.check_minimum_size(widget)\n\n.venv/lib/python3.7/site-packages/orangewidget/tests/base.py:242: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n.venv/lib/python3.7/site-packages/orangewidget/tests/base.py:615: in check_minimum_size\n    self.assertLess(min_size.width(), 800)\nE   AssertionError: 804 not less than 800\n_______________ TestOWSelectAttributes.test_select_new_features ________________\n\nself = <r2e_tests.test_1.TestOWSelectAttributes testMethod=test_select_new_features>\n\n    def test_select_new_features(self):\n        \"\"\"\n        When ignore_new_features unchecked new attributes must appear in one of\n        selected columns. Test with fist make context remember attributes of\n        reduced domain and then testing with full domain. Features in missing\n        in reduced domain must appears as seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n    \n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n    \n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        output = self.get_output(self.widget.Outputs.data)\n    \n        self.assertTupleEqual(\n            new_data.domain.attributes, output.domain.attributes\n        )\n        self.assertTupleEqual(new_data.domain.metas, output.domain.metas)\n        self.assertEqual(new_data.domain.class_var, output.domain.class_var)\n    \n        # send full domain\n        self.send_signal(self.widget.Inputs.data, data)\n        output = self.get_output(self.widget.Outputs.data)\n    \n        # if select_new_features checked all new features goes in the selected\n        # features columns - domain equal original\n>       self.assertFalse(self.widget.ignore_new_features)\nE       AttributeError: 'OWSelectAttributes' object has no attribute 'ignore_new_features'\n\nr2e_tests/test_1.py:448: AttributeError\n______________ TestOWSelectAttributes.test_unselect_new_features _______________\n\nself = <orangewidget.gui.ControlGetter object at 0x7adf4abbe8d0>\nname = 'ignore_new_features'\n\n    def __getattr__(self, name):\n        widget = self.widget\n        callfronts = widget.controlled_attributes.get(name, None)\n        if callfronts is None:\n            # This must be an OWComponent\n            try:\n>               return getattr(widget, name).controls\nE               AttributeError: 'OWSelectAttributes' object has no attribute 'ignore_new_features'\n\n.venv/lib/python3.7/site-packages/orangewidget/gui.py:3165: AttributeError\n\nDuring handling of the above exception, another exception occurred:\n\nself = <r2e_tests.test_1.TestOWSelectAttributes testMethod=test_unselect_new_features>\n\n    def test_unselect_new_features(self):\n        \"\"\"\n        When ignore_new_features checked new attributes must appear in one\n        available attributes column. Test with fist make context remember\n        attributes of reduced domain and then testing with full domain.\n        Features in missing in reduced domain must appears as not seleceted.\n        \"\"\"\n        data = Table(\"iris\")\n        domain = data.domain\n    \n        # data with one feature missing\n        new_domain = Domain(\n            domain.attributes[:-1], domain.class_var, domain.metas\n        )\n        new_data = Table.from_table(new_domain, data)\n    \n        # make context remember features in reduced domain\n        self.send_signal(self.widget.Inputs.data, new_data)\n        # select ignore_new_features\n>       self.widget.controls.ignore_new_features.click()\n\nr2e_tests/test_1.py:472: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <orangewidget.gui.ControlGetter object at 0x7adf4abbe8d0>\nname = 'ignore_new_features'\n\n    def __getattr__(self, name):\n        widget = self.widget\n        callfronts = widget.controlled_attributes.get(name, None)\n        if callfronts is None:\n            # This must be an OWComponent\n            try:\n                return getattr(widget, name).controls\n            except AttributeError:\n                raise AttributeError(\n                    \"'{}' is not an attribute related to a gui element or \"\n>                   \"component\".format(name))\nE               AttributeError: 'ignore_new_features' is not an attribute related to a gui element or component\n\n.venv/lib/python3.7/site-packages/orangewidget/gui.py:3169: AttributeError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestSelectAttributesDomainContextHandler::test_open_context\nPASSED r2e_tests/test_1.py::TestSelectAttributesDomainContextHandler::test_open_context_with_imperfect_match\nPASSED r2e_tests/test_1.py::TestModel::test_drop_mime\nPASSED r2e_tests/test_1.py::TestModel::test_flags\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_domain_new_feature\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_image_export\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_combinations\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_by_name\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_by_name_sub_domain\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_diff_domain\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_from_rank\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_no_data\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_same_domain\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_input_features_sub_domain\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_move_rows\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_msg_base_class\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_multiple_target_variable\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_summary\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_use_features_checked\nPASSED r2e_tests/test_1.py::TestOWSelectAttributes::test_used_attrs_supported_types\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::TestOWSelectAttributes::test_minimum_size - Asser...\nFAILED r2e_tests/test_1.py::TestOWSelectAttributes::test_select_new_features\nFAILED r2e_tests/test_1.py::TestOWSelectAttributes::test_unselect_new_features\n=================== 3 failed, 21 passed, 3 skipped in 3.31s ====================\nWidgets left: 0    Max widgets: 1999 \n\n",
    "old_commit_res_stderr": ""
}
Orange/widgets/data/owselectcolumns.py Orange/widgets/data/tests/test_owselectcolumns.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Tests Fail with AttributeError After Renaming `select_new_features` to `ignore_new_features`

**Description:**
After renaming the `select_new_features` setting to `ignore_new_features` in the `OWSelectAttributes` widget, related tests are failing due to missing attributes.

**Example Buggy Code:**
```python
def test_select_new_features(self):
    data = Table('iris')
    domain = data.domain
    new_domain = Domain(domain.attributes[:-1], domain.class_var, domain.metas)
    new_data = Table.from_table(new_domain, data)
    self.send_signal(self.widget.Inputs.data, new_data)
    output = self.get_output(self.widget.Outputs.data)
    self.send_signal(self.widget.Inputs.data, data)
    output = self.get_output(self.widget.Outputs.data)
    self.assertFalse(self.widget.ignore_new_features)  # Raises AttributeError

def test_unselect_new_features(self):
    data = Table('iris')
    domain = data.domain
    new_domain = Domain(domain.attributes[:-1], domain.class_var, domain.metas)
    new_data = Table.from_table(new_domain, data)
    self.send_signal(self.widget.Inputs.data, new_data)
    self.widget.controls.ignore_new_features.click()  # Raises AttributeError
```

**Expected Behavior:**
The `OWSelectAttributes` widget should have an attribute named `ignore_new_features` after the rename. Tests interacting with this attribute should execute without errors, correctly reflecting the widget's state based on the new setting.

**Actual Behavior:**
Running the tests results in an `AttributeError` because the `OWSelectAttributes` object does not have an attribute named `ignore_new_features`. This prevents the tests from properly verifying the widget's functionality related to ignoring new features.

**Error Messages:**
- In `test_select_new_features`:
  ```
  AttributeError: 'OWSelectAttributes' object has no attribute 'ignore_new_features'
  ```
- In `test_unselect_new_features`:
  ```
  AttributeError: 'ignore_new_features' is not an attribute related to a gui element or component
  ```
[/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/owselectcolumns.py
from functools import partial
from typing import Optional, Dict, Tuple

from AnyQt.QtWidgets import QWidget, QGridLayout
from AnyQt.QtWidgets import QListView
from AnyQt.QtCore import (
    Qt, QTimer, QSortFilterProxyModel, QItemSelection, QItemSelectionModel,
    QMimeData, QAbstractItemModel
)

from Orange.data import Domain, Variable
from Orange.widgets import gui, widget
from Orange.widgets.settings import (
    ContextSetting, Setting, DomainContextHandler
)
from Orange.widgets.utils import vartype
from Orange.widgets.utils.listfilter import (
    VariablesListItemView, slices, variables_filter
)
from Orange.widgets.utils.widgetpreview import WidgetPreview
from Orange.widgets.utils.state_summary import format_summary_details
from Orange.widgets.widget import Input, Output, AttributeList, Msg
from Orange.data.table import Table
from Orange.widgets.utils.itemmodels import VariableListModel
import Orange


def source_model(view):
    """ Return the source model for the Qt Item View if it uses
    the QSortFilterProxyModel.
    """
    if isinstance(view.model(), QSortFilterProxyModel):
        return view.model().sourceModel()
    else:
        return view.model()


def source_indexes(indexes, view):
    """ Map model indexes through a views QSortFilterProxyModel
    """
    model = view.model()
    if isinstance(model, QSortFilterProxyModel):
        return list(map(model.mapToSource, indexes))
    else:
        return indexes


class VariablesListItemModel(VariableListModel):
    """
    An Variable list item model specialized for Drag and Drop.
    """
    MIME_TYPE = "application/x-Orange-VariableListModelData"

    def flags(self, index):
        flags = super().flags(index)
        if index.isValid():
            flags |= Qt.ItemIsDragEnabled
        else:
            flags |= Qt.ItemIsDropEnabled
        return flags

    @staticmethod
    def supportedDropActions():
        return Qt.MoveAction  # pragma: no cover

    @staticmethod
    def supportedDragActions():
        return Qt.MoveAction  # pragma: no cover

    def mimeTypes(self):
        return [self.MIME_TYPE]

    def mimeData(self, indexlist):
        """
        Reimplemented.

        For efficiency reasons only the variable instances are set on the
        mime data (under `'_items'` property)
        """
        items = [self[index.row()] for index in indexlist]
        mime = QMimeData()
        # the encoded 'data' is empty, variables are passed by properties
        mime.setData(self.MIME_TYPE, b'')
        mime.setProperty("_items", items)
        return mime

    def dropMimeData(self, mime, action, row, column, parent):
        """
        Reimplemented.
        """
        if action == Qt.IgnoreAction:
            return True  # pragma: no cover
        if not mime.hasFormat(self.MIME_TYPE):
            return False  # pragma: no cover
        variables = mime.property("_items")
        if variables is None:
            return False  # pragma: no cover
        if row < 0:
            row = self.rowCount()

        self[row:row] = variables
        return True


class SelectAttributesDomainContextHandler(DomainContextHandler):
    def encode_setting(self, context, setting, value):
        if setting.name == 'domain_role_hints':
            value = {(var.name, vartype(var)): role_i
                     for var, role_i in value.items()}
        return super().encode_setting(context, setting, value)

    def decode_setting(self, setting, value, domain=None, *_args):
        decoded = super().decode_setting(setting, value, domain)
        if setting.name == 'domain_role_hints':
            decoded = {domain[name]: role_i
                       for (name, _), role_i in decoded.items()}
        return decoded

    def match(self, context, domain, attrs, metas):
        if context.attributes == attrs and context.metas == metas:
            return self.PERFECT_MATCH

        if not "domain_role_hints" in context.values:
            return self.NO_MATCH

        all_vars = attrs.copy()
        all_vars.update(metas)
        value = context.values["domain_role_hints"][0]
        assigned = [desc for desc, (role, _) in value.items()
                    if role != "available"]
        if not assigned:
            return self.NO_MATCH
        return sum(all_vars.get(attr) == vtype for attr, vtype in assigned) \
               / len(assigned)

    def filter_value(self, setting, data, domain, attrs, metas):
        if setting.name != "domain_role_hints":
            return super().filter_value(setting, data, domain, attrs, metas)

        all_vars = attrs.copy()
        all_vars.update(metas)
        value = data["domain_role_hints"][0].items()
        data["domain_role_hints"] = {desc: role_i
                                     for desc, role_i in value
                                     if all_vars.get(desc[0]) == desc[1]}


class OWSelectAttributes(widget.OWWidget):
    # pylint: disable=too-many-instance-attributes
    name = "Select Columns"
    description = "Select columns from the data table and assign them to " \
                  "data features, classes or meta variables."
    icon = "icons/SelectColumns.svg"
    priority = 100
    keywords = ["filter", "attributes", "target", "variable"]

    class Inputs:
        data = Input("Data", Table, default=True)
        features = Input("Features", AttributeList)

    class Outputs:
        data = Output("Data", Table)
        features = Output("Features", AttributeList, dynamic=False)

    want_main_area = False
    want_control_area = True

    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)
    domain_role_hints = ContextSetting({})
    use_input_features = Setting(False)
    select_new_features = Setting(True)
    auto_commit = Setting(True)

    class Warning(widget.OWWidget.Warning):
        mismatching_domain = Msg("Features and data domain do not match")

    def __init__(self):
        super().__init__()
        self.data = None
        self.features = None

        # Schedule interface updates (enabled buttons) using a coalescing
        # single shot timer (complex interactions on selection and filtering
        # updates in the 'available_attrs_view')
        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)
        self.__interface_update_timer.timeout.connect(
            self.__update_interface_state)
        # The last view that has the selection for move operation's source
        self.__last_active_view = None  # type: Optional[QListView]

        def update_on_change(view):
            # Schedule interface state update on selection change in `view`
            self.__last_active_view = view
            self.__interface_update_timer.start()

        self.controlArea = QWidget(self.controlArea)
        self.layout().addWidget(self.controlArea)
        layout = QGridLayout()
        self.controlArea.setLayout(layout)
        layout.setContentsMargins(4, 4, 4, 4)
        box = gui.vBox(self.controlArea, "Available Variables",
                       addToLayout=False)

        self.available_attrs = VariablesListItemModel()
        filter_edit, self.available_attrs_view = variables_filter(
            parent=self, model=self.available_attrs)
        box.layout().addWidget(filter_edit)

        def dropcompleted(action):
            if action == Qt.MoveAction:
                self.commit()

        self.available_attrs_view.selectionModel().selectionChanged.connect(
            partial(update_on_change, self.available_attrs_view))
        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)

        box.layout().addWidget(self.available_attrs_view)
        layout.addWidget(box, 0, 0, 3, 1)

        box = gui.vBox(self.controlArea, "Features", addToLayout=False)
        self.used_attrs = VariablesListItemModel()
        filter_edit, self.used_attrs_view = variables_filter(
            parent=self, model=self.used_attrs,
            accepted_type=(Orange.data.DiscreteVariable,
                           Orange.data.ContinuousVariable))
        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)
        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)
        self.used_attrs_view.selectionModel().selectionChanged.connect(
            partial(update_on_change, self.used_attrs_view))
        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)
        self.use_features_box = gui.auto_commit(
            self.controlArea, self, "use_input_features",
            "Use input features", "Always use input features",
            box=False, commit=self.__use_features_clicked,
            callback=self.__use_features_changed, addToLayout=False
        )
        self.enable_use_features_box()
        box.layout().addWidget(self.use_features_box)
        box.layout().addWidget(filter_edit)
        box.layout().addWidget(self.used_attrs_view)
        layout.addWidget(box, 0, 2, 1, 1)

        box = gui.vBox(self.controlArea, "Target Variable", addToLayout=False)
        self.class_attrs = VariablesListItemModel()
        self.class_attrs_view = VariablesListItemView(
            acceptedType=(Orange.data.DiscreteVariable,
                          Orange.data.ContinuousVariable))
        self.class_attrs_view.setModel(self.class_attrs)
        self.class_attrs_view.selectionModel().selectionChanged.connect(
            partial(update_on_change, self.class_attrs_view))
        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)
        self.class_attrs_view.setMaximumHeight(72)
        box.layout().addWidget(self.class_attrs_view)
        layout.addWidget(box, 1, 2, 1, 1)

        box = gui.vBox(self.controlArea, "Meta Attributes", addToLayout=False)
        self.meta_attrs = VariablesListItemModel()
        self.meta_attrs_view = VariablesListItemView(
            acceptedType=Orange.data.Variable)
        self.meta_attrs_view.setModel(self.meta_attrs)
        self.meta_attrs_view.selectionModel().selectionChanged.connect(
            partial(update_on_change, self.meta_attrs_view))
        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)
        box.layout().addWidget(self.meta_attrs_view)
        layout.addWidget(box, 2, 2, 1, 1)

        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)
        layout.addWidget(bbox, 0, 1, 1, 1)

        self.up_attr_button = gui.button(bbox, self, "Up",
                                         callback=partial(self.move_up, self.used_attrs_view))
        self.move_attr_button = gui.button(bbox, self, ">",
                                           callback=partial(self.move_selected,
                                                            self.used_attrs_view)
                                          )
        self.down_attr_button = gui.button(bbox, self, "Down",
                                           callback=partial(self.move_down, self.used_attrs_view))

        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)
        layout.addWidget(bbox, 1, 1, 1, 1)

        self.up_class_button = gui.button(bbox, self, "Up",
                                          callback=partial(self.move_up, self.class_attrs_view))
        self.move_class_button = gui.button(bbox, self, ">",
                                            callback=partial(self.move_selected,
                                                             self.class_attrs_view)
                                           )
        self.down_class_button = gui.button(bbox, self, "Down",
                                            callback=partial(self.move_down, self.class_attrs_view))

        bbox = gui.vBox(self.controlArea, addToLayout=False)
        layout.addWidget(bbox, 2, 1, 1, 1)
        self.up_meta_button = gui.button(bbox, self, "Up",
                                         callback=partial(self.move_up, self.meta_attrs_view))
        self.move_meta_button = gui.button(bbox, self, ">",
                                           callback=partial(self.move_selected,
                                                            self.meta_attrs_view)
                                          )
        self.down_meta_button = gui.button(bbox, self, "Down",
                                           callback=partial(self.move_down, self.meta_attrs_view))

        bbox = gui.vBox(self.controlArea, "Additional settings", addToLayout=False)
        gui.checkBox(
            bbox, self, "select_new_features", "Automatically select additional/new features"
        )
        layout.addWidget(bbox, 3, 0, 1, 3)

        autobox = gui.auto_send(None, self, "auto_commit")
        layout.addWidget(autobox, 4, 0, 1, 3)
        reset = gui.button(None, self, "Reset", callback=self.reset, width=120)
        autobox.layout().insertWidget(0, reset)
        autobox.layout().insertStretch(1, 20)

        layout.setRowStretch(0, 4)
        layout.setRowStretch(1, 0)
        layout.setRowStretch(2, 2)
        layout.setHorizontalSpacing(0)
        self.controlArea.setLayout(layout)

        self.output_data = None
        self.original_completer_items = []

        self.info.set_input_summary(self.info.NoInput)
        self.info.set_output_summary(self.info.NoOutput)

        self.resize(600, 600)

    @property
    def features_from_data_attributes(self):
        if self.data is None or self.features is None:
            return []
        domain = self.data.domain
        return [domain[feature.name] for feature in self.features
                if feature.name in domain and domain[feature.name]
                in domain.attributes]

    def can_use_features(self):
        return bool(self.features_from_data_attributes) and \
               self.features_from_data_attributes != self.used_attrs[:]

    def __use_features_changed(self):  # Use input features check box
        # Needs a check since callback is invoked before object is created
        if not hasattr(self, "use_features_box"):
            return
        self.enable_used_attrs(not self.use_input_features)
        if self.use_input_features and self.can_use_features():
            self.use_features()
        if not self.use_input_features:
            self.enable_use_features_box()

    def __use_features_clicked(self):  # Use input features button
        self.use_features()

    def __used_attrs_changed(self):
        self.enable_use_features_box()

    @Inputs.data
    def set_data(self, data=None):
        self.update_domain_role_hints()
        self.closeContext()
        self.domain_role_hints = {}

        self.data = data
        if data is None:
            self.used_attrs[:] = []
            self.class_attrs[:] = []
            self.meta_attrs[:] = []
            self.available_attrs[:] = []
            self.info.set_input_summary(self.info.NoInput)
            return

        self.openContext(data)
        all_vars = data.domain.variables + data.domain.metas

        def attrs_for_role(role):
            selected_attrs = [
                attr for attr in all_vars if domain_hints[attr][0] == role
            ]
            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])

        domain_hints = self.restore_hints(data.domain)
        self.used_attrs[:] = attrs_for_role("attribute")
        self.class_attrs[:] = attrs_for_role("class")
        self.meta_attrs[:] = attrs_for_role("meta")
        self.available_attrs[:] = attrs_for_role("available")
        self.info.set_input_summary(len(data), format_summary_details(data))

    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:
        """
        Define hints for selected/unselected features.
        Rules:
        - if context available, restore new features based on checked/unchecked
          select_new_features, context hint should be took into account
        - in no context, restore features based on the domain (as selected)

        Parameters
        ----------
        domain
            Data domain

        Returns
        -------
        Dictionary with hints about order and model in which each feature
        should appear
        """
        domain_hints = {}
        if self.select_new_features or len(self.domain_role_hints) == 0:
            # select_new_features selected or no context - restore based on domain
            domain_hints.update(
                self._hints_from_seq("attribute", domain.attributes)
            )
            domain_hints.update(self._hints_from_seq("meta", domain.metas))
            domain_hints.update(
                self._hints_from_seq("class", domain.class_vars)
            )
        else:
            # if context restored and select_new_features unselected - restore
            # new features as available
            d = domain.attributes + domain.metas + domain.class_vars
            domain_hints.update(self._hints_from_seq("available", d))

        domain_hints.update(self.domain_role_hints)
        return domain_hints

    def update_domain_role_hints(self):
        """ Update the domain hints to be stored in the widgets settings.
        """
        hints = {}
        hints.update(self._hints_from_seq("available", self.available_attrs))
        hints.update(self._hints_from_seq("attribute", self.used_attrs))
        hints.update(self._hints_from_seq("class", self.class_attrs))
        hints.update(self._hints_from_seq("meta", self.meta_attrs))
        self.domain_role_hints = hints

    @staticmethod
    def _hints_from_seq(role, model):
        return [(attr, (role, i)) for i, attr in enumerate(model)]

    @Inputs.features
    def set_features(self, features):
        self.features = features

    def handleNewSignals(self):
        self.check_data()
        self.enable_used_attrs()
        self.enable_use_features_box()
        if self.use_input_features and self.features_from_data_attributes:
            self.enable_used_attrs(False)
            self.use_features()
        self.unconditional_commit()

    def check_data(self):
        self.Warning.mismatching_domain.clear()
        if self.data is not None and self.features is not None and \
                not self.features_from_data_attributes:
            self.Warning.mismatching_domain()

    def enable_used_attrs(self, enable=True):
        self.up_attr_button.setEnabled(enable)
        self.move_attr_button.setEnabled(enable)
        self.down_attr_button.setEnabled(enable)
        self.used_attrs_view.setEnabled(enable)
        self.used_attrs_view.repaint()

    def enable_use_features_box(self):
        self.use_features_box.button.setEnabled(self.can_use_features())
        enable_checkbox = bool(self.features_from_data_attributes)
        self.use_features_box.setHidden(not enable_checkbox)
        self.use_features_box.repaint()

    def use_features(self):
        attributes = self.features_from_data_attributes
        available, used = self.available_attrs[:], self.used_attrs[:]
        self.available_attrs[:] = [attr for attr in used + available
                                   if attr not in attributes]
        self.used_attrs[:] = attributes
        self.commit()

    @staticmethod
    def selected_rows(view):
        """ Return the selected rows in the view.
        """
        rows = view.selectionModel().selectedRows()
        model = view.model()
        if isinstance(model, QSortFilterProxyModel):
            rows = [model.mapToSource(r) for r in rows]
        return [r.row() for r in rows]

    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):
        rows = [idx.row() for idx in view.selectionModel().selectedRows()]
        model = view.model()  # type: QAbstractItemModel
        rowcount = model.rowCount()
        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]

        def itemData(index):
            return {role: model.data(index, role) for role in roles}

        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):
            d1 = itemData(model.index(row, 0))
            d2 = itemData(model.index(newrow, 0))
            model.setItemData(model.index(row, 0), d2)
            model.setItemData(model.index(newrow, 0), d1)

        selection = QItemSelection()
        for nrow in newrows:
            index = model.index(nrow, 0)
            selection.select(index, index)
        view.selectionModel().select(
            selection, QItemSelectionModel.ClearAndSelect)

        self.commit()

    def move_up(self, view: QListView):
        self.move_rows(view, -1)

    def move_down(self, view: QListView):
        self.move_rows(view, 1)

    def move_selected(self, view):
        if self.selected_rows(view):
            self.move_selected_from_to(view, self.available_attrs_view)
        elif self.selected_rows(self.available_attrs_view):
            self.move_selected_from_to(self.available_attrs_view, view)

    def move_selected_from_to(self, src, dst):
        self.move_from_to(src, dst, self.selected_rows(src))

    def move_from_to(self, src, dst, rows):
        src_model = source_model(src)
        attrs = [src_model[r] for r in rows]

        for s1, s2 in reversed(list(slices(rows))):
            del src_model[s1:s2]

        dst_model = source_model(dst)

        dst_model.extend(attrs)

        self.commit()

    def __update_interface_state(self):
        last_view = self.__last_active_view
        if last_view is not None:
            self.update_interface_state(last_view)

    def update_interface_state(self, focus=None):
        for view in [self.available_attrs_view, self.used_attrs_view,
                     self.class_attrs_view, self.meta_attrs_view]:
            if view is not focus and not view.hasFocus() \
                    and view.selectionModel().hasSelection():
                view.selectionModel().clear()

        def selected_vars(view):
            model = source_model(view)
            return [model[i] for i in self.selected_rows(view)]

        available_selected = selected_vars(self.available_attrs_view)
        attrs_selected = selected_vars(self.used_attrs_view)
        class_selected = selected_vars(self.class_attrs_view)
        meta_selected = selected_vars(self.meta_attrs_view)

        available_types = set(map(type, available_selected))
        all_primitive = all(var.is_primitive()
                            for var in available_types)

        move_attr_enabled = \
            ((available_selected and all_primitive) or attrs_selected) and \
            self.used_attrs_view.isEnabled()

        self.move_attr_button.setEnabled(bool(move_attr_enabled))
        if move_attr_enabled:
            self.move_attr_button.setText(">" if available_selected else "<")

        move_class_enabled = bool(all_primitive and available_selected) or class_selected

        self.move_class_button.setEnabled(bool(move_class_enabled))
        if move_class_enabled:
            self.move_class_button.setText(">" if available_selected else "<")
        move_meta_enabled = available_selected or meta_selected

        self.move_meta_button.setEnabled(bool(move_meta_enabled))
        if move_meta_enabled:
            self.move_meta_button.setText(">" if available_selected else "<")

        self.__last_active_view = None
        self.__interface_update_timer.stop()

    def commit(self):
        self.update_domain_role_hints()
        if self.data is not None:
            attributes = list(self.used_attrs)
            class_var = list(self.class_attrs)
            metas = list(self.meta_attrs)

            domain = Orange.data.Domain(attributes, class_var, metas)
            newdata = self.data.transform(domain)
            self.output_data = newdata
            self.Outputs.data.send(newdata)
            self.Outputs.features.send(AttributeList(attributes))
            self.info.set_output_summary(len(newdata),
                                         format_summary_details(newdata))
        else:
            self.output_data = None
            self.Outputs.data.send(None)
            self.Outputs.features.send(None)
            self.info.set_output_summary(self.info.NoOutput)

    def reset(self):
        self.enable_used_attrs()
        self.use_features_box.checkbox.setChecked(False)
        if self.data is not None:
            self.available_attrs[:] = []
            self.used_attrs[:] = self.data.domain.attributes
            self.class_attrs[:] = self.data.domain.class_vars
            self.meta_attrs[:] = self.data.domain.metas
            self.update_domain_role_hints()
            self.commit()

    def send_report(self):
        if not self.data or not self.output_data:
            return
        in_domain, out_domain = self.data.domain, self.output_data.domain
        self.report_domain("Input data", self.data.domain)
        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (
                out_domain.attributes, out_domain.class_vars, out_domain.metas):
            self.report_paragraph("Output data", "No changes.")
        else:
            self.report_domain("Output data", self.output_data.domain)
            diff = list(set(in_domain.variables + in_domain.metas) -
                        set(out_domain.variables + out_domain.metas))
            if diff:
                text = "%i (%s)" % (len(diff), ", ".join(x.name for x in diff))
                self.report_items((("Removed", text),))


if __name__ == "__main__":  # pragma: no cover
    brown = Orange.data.Table("brown-selected")
    feats = AttributeList(brown.domain.attributes[:2])
    WidgetPreview(OWSelectAttributes).run(set_data=brown, set_features=feats)

```
--- 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:** Tests Fail with AttributeError After Renaming `select_new_features` to `ignore_new_features`

**Description:**
After renaming the `select_new_features` setting to `ignore_new_features` in the `OWSelectAttributes` widget, related tests are failing due to missing attributes.

**Example Buggy Code:**
```python
def test_select_new_features(self):
    data = Table('iris')
    domain = data.domain
    new_domain = Domain(domain.attributes[:-1], domain.class_var, domain.metas)
    new_data = Table.from_table(new_domain, data)
    self.send_signal(self.widget.Inputs.data, new_data)
    output = self.get_output(self.widget.Outputs.data)
    self.send_signal(self.widget.Inputs.data, data)
    output = self.get_output(self.widget.Outputs.data)
    self.assertFalse(self.widget.ignore_new_features)  # Raises AttributeError

def test_unselect_new_features(self):
    data = Table('iris')
    domain = data.domain
    new_domain = Domain(domain.attributes[:-1], domain.class_var, domain.metas)
    new_data = Table.from_table(new_domain, data)
    self.send_signal(self.widget.Inputs.data, new_data)
    self.widget.controls.ignore_new_features.click()  # Raises AttributeError
```

**Expected Behavior:**
The `OWSelectAttributes` widget should have an attribute named `ignore_new_features` after the rename. Tests interacting with this attribute should execute without errors, correctly reflecting the widget's state based on the new setting.

**Actual Behavior:**
Running the tests results in an `AttributeError` because the `OWSelectAttributes` object does not have an attribute named `ignore_new_features`. This prevents the tests from properly verifying the widget's functionality related to ignoring new features.

**Error Messages:**
- In `test_select_new_features`:
  ```
  AttributeError: 'OWSelectAttributes' object has no attribute 'ignore_new_features'
  ```
- In `test_unselect_new_features`:
  ```
  AttributeError: 'ignore_new_features' is not an attribute related to a gui element or component
  ```
[/ISSUE]
{
    "TestSelectAttributesDomainContextHandler.test_open_context": "PASSED",
    "TestSelectAttributesDomainContextHandler.test_open_context_with_imperfect_match": "PASSED",
    "TestModel.test_drop_mime": "PASSED",
    "TestModel.test_flags": "PASSED",
    "TestOWSelectAttributes.test_domain_new_feature": "PASSED",
    "TestOWSelectAttributes.test_image_export": "PASSED",
    "TestOWSelectAttributes.test_input_combinations": "PASSED",
    "TestOWSelectAttributes.test_input_features": "PASSED",
    "TestOWSelectAttributes.test_input_features_by_name": "PASSED",
    "TestOWSelectAttributes.test_input_features_by_name_sub_domain": "PASSED",
    "TestOWSelectAttributes.test_input_features_diff_domain": "PASSED",
    "TestOWSelectAttributes.test_input_features_from_rank": "PASSED",
    "TestOWSelectAttributes.test_input_features_no_data": "PASSED",
    "TestOWSelectAttributes.test_input_features_same_domain": "PASSED",
    "TestOWSelectAttributes.test_input_features_sub_domain": "PASSED",
    "TestOWSelectAttributes.test_move_rows": "PASSED",
    "TestOWSelectAttributes.test_msg_base_class": "PASSED",
    "TestOWSelectAttributes.test_multiple_target_variable": "PASSED",
    "TestOWSelectAttributes.test_select_new_features": "PASSED",
    "TestOWSelectAttributes.test_summary": "PASSED",
    "TestOWSelectAttributes.test_unselect_new_features": "PASSED",
    "TestOWSelectAttributes.test_use_features_checked": "PASSED",
    "TestOWSelectAttributes.test_used_attrs_supported_types": "PASSED",
    "TestOWSelectAttributes.test_minimum_size": "FAILED"
}
diff --git a/Orange/widgets/data/owselectcolumns.py b/Orange/widgets/data/owselectcolumns.py
index af11f3668..3a385ba69 100644
--- a/Orange/widgets/data/owselectcolumns.py
+++ b/Orange/widgets/data/owselectcolumns.py
@@ -168,7 +168,7 @@ class OWSelectAttributes(widget.OWWidget):
     settingsHandler = SelectAttributesDomainContextHandler(first_match=False)
     domain_role_hints = ContextSetting({})
     use_input_features = Setting(False)
-    select_new_features = Setting(True)
+    ignore_new_features = Setting(False)
     auto_commit = Setting(True)
 
     class Warning(widget.OWWidget.Warning):
@@ -301,7 +301,7 @@ class OWSelectAttributes(widget.OWWidget):
 
         bbox = gui.vBox(self.controlArea, "Additional settings", addToLayout=False)
         gui.checkBox(
-            bbox, self, "select_new_features", "Automatically select additional/new features"
+            bbox, self, "ignore_new_features", "Ignore new variables by default"
         )
         layout.addWidget(bbox, 3, 0, 1, 3)
 
@@ -390,7 +390,7 @@ class OWSelectAttributes(widget.OWWidget):
         Define hints for selected/unselected features.
         Rules:
         - if context available, restore new features based on checked/unchecked
-          select_new_features, context hint should be took into account
+          ignore_new_features, context hint should be took into account
         - in no context, restore features based on the domain (as selected)
 
         Parameters
@@ -404,7 +404,7 @@ class OWSelectAttributes(widget.OWWidget):
         should appear
         """
         domain_hints = {}
-        if self.select_new_features or len(self.domain_role_hints) == 0:
+        if not self.ignore_new_features or len(self.domain_role_hints) == 0:
             # select_new_features selected or no context - restore based on domain
             domain_hints.update(
                 self._hints_from_seq("attribute", domain.attributes)
@@ -414,7 +414,7 @@ class OWSelectAttributes(widget.OWWidget):
                 self._hints_from_seq("class", domain.class_vars)
             )
         else:
-            # if context restored and select_new_features unselected - restore
+            # if context restored and ignore_new_features selected - restore
             # new features as available
             d = domain.attributes + domain.metas + domain.class_vars
             domain_hints.update(self._hints_from_seq("available", d))

{"Orange/widgets/data/owselectcolumns.py": "from functools import partial\nfrom typing import Optional, Dict, Tuple\n\nfrom AnyQt.QtWidgets import QWidget, QGridLayout\nfrom AnyQt.QtWidgets import QListView\nfrom AnyQt.QtCore import (\n    Qt, QTimer, QSortFilterProxyModel, QItemSelection, QItemSelectionModel,\n    QMimeData, QAbstractItemModel\n)\n\nfrom Orange.data import Domain, Variable\nfrom Orange.widgets import gui, widget\nfrom Orange.widgets.settings import (\n    ContextSetting, Setting, DomainContextHandler\n)\nfrom Orange.widgets.utils import vartype\nfrom Orange.widgets.utils.listfilter import (\n    VariablesListItemView, slices, variables_filter\n)\nfrom Orange.widgets.utils.widgetpreview import WidgetPreview\nfrom Orange.widgets.utils.state_summary import format_summary_details\nfrom Orange.widgets.widget import Input, Output, AttributeList, Msg\nfrom Orange.data.table import Table\nfrom Orange.widgets.utils.itemmodels import VariableListModel\nimport Orange\n\n\ndef source_model(view):\n    \"\"\" Return the source model for the Qt Item View if it uses\n    the QSortFilterProxyModel.\n    \"\"\"\n    if isinstance(view.model(), QSortFilterProxyModel):\n        return view.model().sourceModel()\n    else:\n        return view.model()\n\n\ndef source_indexes(indexes, view):\n    \"\"\" Map model indexes through a views QSortFilterProxyModel\n    \"\"\"\n    model = view.model()\n    if isinstance(model, QSortFilterProxyModel):\n        return list(map(model.mapToSource, indexes))\n    else:\n        return indexes\n\n\nclass VariablesListItemModel(VariableListModel):\n    \"\"\"\n    An Variable list item model specialized for Drag and Drop.\n    \"\"\"\n    MIME_TYPE = \"application/x-Orange-VariableListModelData\"\n\n    def flags(self, index):\n        flags = super().flags(index)\n        if index.isValid():\n            flags |= Qt.ItemIsDragEnabled\n        else:\n            flags |= Qt.ItemIsDropEnabled\n        return flags\n\n    @staticmethod\n    def supportedDropActions():\n        return Qt.MoveAction  # pragma: no cover\n\n    @staticmethod\n    def supportedDragActions():\n        return Qt.MoveAction  # pragma: no cover\n\n    def mimeTypes(self):\n        return [self.MIME_TYPE]\n\n    def mimeData(self, indexlist):\n        \"\"\"\n        Reimplemented.\n\n        For efficiency reasons only the variable instances are set on the\n        mime data (under `'_items'` property)\n        \"\"\"\n        items = [self[index.row()] for index in indexlist]\n        mime = QMimeData()\n        # the encoded 'data' is empty, variables are passed by properties\n        mime.setData(self.MIME_TYPE, b'')\n        mime.setProperty(\"_items\", items)\n        return mime\n\n    def dropMimeData(self, mime, action, row, column, parent):\n        \"\"\"\n        Reimplemented.\n        \"\"\"\n        if action == Qt.IgnoreAction:\n            return True  # pragma: no cover\n        if not mime.hasFormat(self.MIME_TYPE):\n            return False  # pragma: no cover\n        variables = mime.property(\"_items\")\n        if variables is None:\n            return False  # pragma: no cover\n        if row < 0:\n            row = self.rowCount()\n\n        self[row:row] = variables\n        return True\n\n\nclass SelectAttributesDomainContextHandler(DomainContextHandler):\n    def encode_setting(self, context, setting, value):\n        if setting.name == 'domain_role_hints':\n            value = {(var.name, vartype(var)): role_i\n                     for var, role_i in value.items()}\n        return super().encode_setting(context, setting, value)\n\n    def decode_setting(self, setting, value, domain=None, *_args):\n        decoded = super().decode_setting(setting, value, domain)\n        if setting.name == 'domain_role_hints':\n            decoded = {domain[name]: role_i\n                       for (name, _), role_i in decoded.items()}\n        return decoded\n\n    def match(self, context, domain, attrs, metas):\n        if context.attributes == attrs and context.metas == metas:\n            return self.PERFECT_MATCH\n\n        if not \"domain_role_hints\" in context.values:\n            return self.NO_MATCH\n\n        all_vars = attrs.copy()\n        all_vars.update(metas)\n        value = context.values[\"domain_role_hints\"][0]\n        assigned = [desc for desc, (role, _) in value.items()\n                    if role != \"available\"]\n        if not assigned:\n            return self.NO_MATCH\n        return sum(all_vars.get(attr) == vtype for attr, vtype in assigned) \\\n               / len(assigned)\n\n    def filter_value(self, setting, data, domain, attrs, metas):\n        if setting.name != \"domain_role_hints\":\n            return super().filter_value(setting, data, domain, attrs, metas)\n\n        all_vars = attrs.copy()\n        all_vars.update(metas)\n        value = data[\"domain_role_hints\"][0].items()\n        data[\"domain_role_hints\"] = {desc: role_i\n                                     for desc, role_i in value\n                                     if all_vars.get(desc[0]) == desc[1]}\n\n\nclass OWSelectAttributes(widget.OWWidget):\n    # pylint: disable=too-many-instance-attributes\n    name = \"Select Columns\"\n    description = \"Select columns from the data table and assign them to \" \\\n                  \"data features, classes or meta variables.\"\n    icon = \"icons/SelectColumns.svg\"\n    priority = 100\n    keywords = [\"filter\", \"attributes\", \"target\", \"variable\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table, default=True)\n        features = Input(\"Features\", AttributeList)\n\n    class Outputs:\n        data = Output(\"Data\", Table)\n        features = Output(\"Features\", AttributeList, dynamic=False)\n\n    want_main_area = False\n    want_control_area = True\n\n    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)\n    domain_role_hints = ContextSetting({})\n    use_input_features = Setting(False)\n    select_new_features = Setting(True)\n    auto_commit = Setting(True)\n\n    class Warning(widget.OWWidget.Warning):\n        mismatching_domain = Msg(\"Features and data domain do not match\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n        self.features = None\n\n        # Schedule interface updates (enabled buttons) using a coalescing\n        # single shot timer (complex interactions on selection and filtering\n        # updates in the 'available_attrs_view')\n        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)\n        self.__interface_update_timer.timeout.connect(\n            self.__update_interface_state)\n        # The last view that has the selection for move operation's source\n        self.__last_active_view = None  # type: Optional[QListView]\n\n        def update_on_change(view):\n            # Schedule interface state update on selection change in `view`\n            self.__last_active_view = view\n            self.__interface_update_timer.start()\n\n        self.controlArea = QWidget(self.controlArea)\n        self.layout().addWidget(self.controlArea)\n        layout = QGridLayout()\n        self.controlArea.setLayout(layout)\n        layout.setContentsMargins(4, 4, 4, 4)\n        box = gui.vBox(self.controlArea, \"Available Variables\",\n                       addToLayout=False)\n\n        self.available_attrs = VariablesListItemModel()\n        filter_edit, self.available_attrs_view = variables_filter(\n            parent=self, model=self.available_attrs)\n        box.layout().addWidget(filter_edit)\n\n        def dropcompleted(action):\n            if action == Qt.MoveAction:\n                self.commit()\n\n        self.available_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.available_attrs_view))\n        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n\n        box.layout().addWidget(self.available_attrs_view)\n        layout.addWidget(box, 0, 0, 3, 1)\n\n        box = gui.vBox(self.controlArea, \"Features\", addToLayout=False)\n        self.used_attrs = VariablesListItemModel()\n        filter_edit, self.used_attrs_view = variables_filter(\n            parent=self, model=self.used_attrs,\n            accepted_type=(Orange.data.DiscreteVariable,\n                           Orange.data.ContinuousVariable))\n        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)\n        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)\n        self.used_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.used_attrs_view))\n        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.use_features_box = gui.auto_commit(\n            self.controlArea, self, \"use_input_features\",\n            \"Use input features\", \"Always use input features\",\n            box=False, commit=self.__use_features_clicked,\n            callback=self.__use_features_changed, addToLayout=False\n        )\n        self.enable_use_features_box()\n        box.layout().addWidget(self.use_features_box)\n        box.layout().addWidget(filter_edit)\n        box.layout().addWidget(self.used_attrs_view)\n        layout.addWidget(box, 0, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Target Variable\", addToLayout=False)\n        self.class_attrs = VariablesListItemModel()\n        self.class_attrs_view = VariablesListItemView(\n            acceptedType=(Orange.data.DiscreteVariable,\n                          Orange.data.ContinuousVariable))\n        self.class_attrs_view.setModel(self.class_attrs)\n        self.class_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.class_attrs_view))\n        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        self.class_attrs_view.setMaximumHeight(72)\n        box.layout().addWidget(self.class_attrs_view)\n        layout.addWidget(box, 1, 2, 1, 1)\n\n        box = gui.vBox(self.controlArea, \"Meta Attributes\", addToLayout=False)\n        self.meta_attrs = VariablesListItemModel()\n        self.meta_attrs_view = VariablesListItemView(\n            acceptedType=Orange.data.Variable)\n        self.meta_attrs_view.setModel(self.meta_attrs)\n        self.meta_attrs_view.selectionModel().selectionChanged.connect(\n            partial(update_on_change, self.meta_attrs_view))\n        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)\n        box.layout().addWidget(self.meta_attrs_view)\n        layout.addWidget(box, 2, 2, 1, 1)\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 0, 1, 1, 1)\n\n        self.up_attr_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.used_attrs_view))\n        self.move_attr_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.used_attrs_view)\n                                          )\n        self.down_attr_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.used_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)\n        layout.addWidget(bbox, 1, 1, 1, 1)\n\n        self.up_class_button = gui.button(bbox, self, \"Up\",\n                                          callback=partial(self.move_up, self.class_attrs_view))\n        self.move_class_button = gui.button(bbox, self, \">\",\n                                            callback=partial(self.move_selected,\n                                                             self.class_attrs_view)\n                                           )\n        self.down_class_button = gui.button(bbox, self, \"Down\",\n                                            callback=partial(self.move_down, self.class_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, addToLayout=False)\n        layout.addWidget(bbox, 2, 1, 1, 1)\n        self.up_meta_button = gui.button(bbox, self, \"Up\",\n                                         callback=partial(self.move_up, self.meta_attrs_view))\n        self.move_meta_button = gui.button(bbox, self, \">\",\n                                           callback=partial(self.move_selected,\n                                                            self.meta_attrs_view)\n                                          )\n        self.down_meta_button = gui.button(bbox, self, \"Down\",\n                                           callback=partial(self.move_down, self.meta_attrs_view))\n\n        bbox = gui.vBox(self.controlArea, \"Additional settings\", addToLayout=False)\n        gui.checkBox(\n            bbox, self, \"select_new_features\", \"Automatically select additional/new features\"\n        )\n        layout.addWidget(bbox, 3, 0, 1, 3)\n\n        autobox = gui.auto_send(None, self, \"auto_commit\")\n        layout.addWidget(autobox, 4, 0, 1, 3)\n        reset = gui.button(None, self, \"Reset\", callback=self.reset, width=120)\n        autobox.layout().insertWidget(0, reset)\n        autobox.layout().insertStretch(1, 20)\n\n        layout.setRowStretch(0, 4)\n        layout.setRowStretch(1, 0)\n        layout.setRowStretch(2, 2)\n        layout.setHorizontalSpacing(0)\n        self.controlArea.setLayout(layout)\n\n        self.output_data = None\n        self.original_completer_items = []\n\n        self.info.set_input_summary(self.info.NoInput)\n        self.info.set_output_summary(self.info.NoOutput)\n\n        self.resize(600, 600)\n\n    @property\n    def features_from_data_attributes(self):\n        if self.data is None or self.features is None:\n            return []\n        domain = self.data.domain\n        return [domain[feature.name] for feature in self.features\n                if feature.name in domain and domain[feature.name]\n                in domain.attributes]\n\n    def can_use_features(self):\n        return bool(self.features_from_data_attributes) and \\\n               self.features_from_data_attributes != self.used_attrs[:]\n\n    def __use_features_changed(self):  # Use input features check box\n        # Needs a check since callback is invoked before object is created\n        if not hasattr(self, \"use_features_box\"):\n            return\n        self.enable_used_attrs(not self.use_input_features)\n        if self.use_input_features and self.can_use_features():\n            self.use_features()\n        if not self.use_input_features:\n            self.enable_use_features_box()\n\n    def __use_features_clicked(self):  # Use input features button\n        self.use_features()\n\n    def __used_attrs_changed(self):\n        self.enable_use_features_box()\n\n    @Inputs.data\n    def set_data(self, data=None):\n        self.update_domain_role_hints()\n        self.closeContext()\n        self.domain_role_hints = {}\n\n        self.data = data\n        if data is None:\n            self.used_attrs[:] = []\n            self.class_attrs[:] = []\n            self.meta_attrs[:] = []\n            self.available_attrs[:] = []\n            self.info.set_input_summary(self.info.NoInput)\n            return\n\n        self.openContext(data)\n        all_vars = data.domain.variables + data.domain.metas\n\n        def attrs_for_role(role):\n            selected_attrs = [\n                attr for attr in all_vars if domain_hints[attr][0] == role\n            ]\n            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])\n\n        domain_hints = self.restore_hints(data.domain)\n        self.used_attrs[:] = attrs_for_role(\"attribute\")\n        self.class_attrs[:] = attrs_for_role(\"class\")\n        self.meta_attrs[:] = attrs_for_role(\"meta\")\n        self.available_attrs[:] = attrs_for_role(\"available\")\n        self.info.set_input_summary(len(data), format_summary_details(data))\n\n    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:\n        \"\"\"\n        Define hints for selected/unselected features.\n        Rules:\n        - if context available, restore new features based on checked/unchecked\n          select_new_features, context hint should be took into account\n        - in no context, restore features based on the domain (as selected)\n\n        Parameters\n        ----------\n        domain\n            Data domain\n\n        Returns\n        -------\n        Dictionary with hints about order and model in which each feature\n        should appear\n        \"\"\"\n        domain_hints = {}\n        if self.select_new_features or len(self.domain_role_hints) == 0:\n            # select_new_features selected or no context - restore based on domain\n            domain_hints.update(\n                self._hints_from_seq(\"attribute\", domain.attributes)\n            )\n            domain_hints.update(self._hints_from_seq(\"meta\", domain.metas))\n            domain_hints.update(\n                self._hints_from_seq(\"class\", domain.class_vars)\n            )\n        else:\n            # if context restored and select_new_features unselected - restore\n            # new features as available\n            d = domain.attributes + domain.metas + domain.class_vars\n            domain_hints.update(self._hints_from_seq(\"available\", d))\n\n        domain_hints.update(self.domain_role_hints)\n        return domain_hints\n\n    def update_domain_role_hints(self):\n        \"\"\" Update the domain hints to be stored in the widgets settings.\n        \"\"\"\n        hints = {}\n        hints.update(self._hints_from_seq(\"available\", self.available_attrs))\n        hints.update(self._hints_from_seq(\"attribute\", self.used_attrs))\n        hints.update(self._hints_from_seq(\"class\", self.class_attrs))\n        hints.update(self._hints_from_seq(\"meta\", self.meta_attrs))\n        self.domain_role_hints = hints\n\n    @staticmethod\n    def _hints_from_seq(role, model):\n        return [(attr, (role, i)) for i, attr in enumerate(model)]\n\n    @Inputs.features\n    def set_features(self, features):\n        self.features = features\n\n    def handleNewSignals(self):\n        self.check_data()\n        self.enable_used_attrs()\n        self.enable_use_features_box()\n        if self.use_input_features and self.features_from_data_attributes:\n            self.enable_used_attrs(False)\n            self.use_features()\n        self.unconditional_commit()\n\n    def check_data(self):\n        self.Warning.mismatching_domain.clear()\n        if self.data is not None and self.features is not None and \\\n                not self.features_from_data_attributes:\n            self.Warning.mismatching_domain()\n\n    def enable_used_attrs(self, enable=True):\n        self.up_attr_button.setEnabled(enable)\n        self.move_attr_button.setEnabled(enable)\n        self.down_attr_button.setEnabled(enable)\n        self.used_attrs_view.setEnabled(enable)\n        self.used_attrs_view.repaint()\n\n    def enable_use_features_box(self):\n        self.use_features_box.button.setEnabled(self.can_use_features())\n        enable_checkbox = bool(self.features_from_data_attributes)\n        self.use_features_box.setHidden(not enable_checkbox)\n        self.use_features_box.repaint()\n\n    def use_features(self):\n        attributes = self.features_from_data_attributes\n        available, used = self.available_attrs[:], self.used_attrs[:]\n        self.available_attrs[:] = [attr for attr in used + available\n                                   if attr not in attributes]\n        self.used_attrs[:] = attributes\n        self.commit()\n\n    @staticmethod\n    def selected_rows(view):\n        \"\"\" Return the selected rows in the view.\n        \"\"\"\n        rows = view.selectionModel().selectedRows()\n        model = view.model()\n        if isinstance(model, QSortFilterProxyModel):\n            rows = [model.mapToSource(r) for r in rows]\n        return [r.row() for r in rows]\n\n    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):\n        rows = [idx.row() for idx in view.selectionModel().selectedRows()]\n        model = view.model()  # type: QAbstractItemModel\n        rowcount = model.rowCount()\n        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]\n\n        def itemData(index):\n            return {role: model.data(index, role) for role in roles}\n\n        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):\n            d1 = itemData(model.index(row, 0))\n            d2 = itemData(model.index(newrow, 0))\n            model.setItemData(model.index(row, 0), d2)\n            model.setItemData(model.index(newrow, 0), d1)\n\n        selection = QItemSelection()\n        for nrow in newrows:\n            index = model.index(nrow, 0)\n            selection.select(index, index)\n        view.selectionModel().select(\n            selection, QItemSelectionModel.ClearAndSelect)\n\n        self.commit()\n\n    def move_up(self, view: QListView):\n        self.move_rows(view, -1)\n\n    def move_down(self, view: QListView):\n        self.move_rows(view, 1)\n\n    def move_selected(self, view):\n        if self.selected_rows(view):\n            self.move_selected_from_to(view, self.available_attrs_view)\n        elif self.selected_rows(self.available_attrs_view):\n            self.move_selected_from_to(self.available_attrs_view, view)\n\n    def move_selected_from_to(self, src, dst):\n        self.move_from_to(src, dst, self.selected_rows(src))\n\n    def move_from_to(self, src, dst, rows):\n        src_model = source_model(src)\n        attrs = [src_model[r] for r in rows]\n\n        for s1, s2 in reversed(list(slices(rows))):\n            del src_model[s1:s2]\n\n        dst_model = source_model(dst)\n\n        dst_model.extend(attrs)\n\n        self.commit()\n\n    def __update_interface_state(self):\n        last_view = self.__last_active_view\n        if last_view is not None:\n            self.update_interface_state(last_view)\n\n    def update_interface_state(self, focus=None):\n        for view in [self.available_attrs_view, self.used_attrs_view,\n                     self.class_attrs_view, self.meta_attrs_view]:\n            if view is not focus and not view.hasFocus() \\\n                    and view.selectionModel().hasSelection():\n                view.selectionModel().clear()\n\n        def selected_vars(view):\n            model = source_model(view)\n            return [model[i] for i in self.selected_rows(view)]\n\n        available_selected = selected_vars(self.available_attrs_view)\n        attrs_selected = selected_vars(self.used_attrs_view)\n        class_selected = selected_vars(self.class_attrs_view)\n        meta_selected = selected_vars(self.meta_attrs_view)\n\n        available_types = set(map(type, available_selected))\n        all_primitive = all(var.is_primitive()\n                            for var in available_types)\n\n        move_attr_enabled = \\\n            ((available_selected and all_primitive) or attrs_selected) and \\\n            self.used_attrs_view.isEnabled()\n\n        self.move_attr_button.setEnabled(bool(move_attr_enabled))\n        if move_attr_enabled:\n            self.move_attr_button.setText(\">\" if available_selected else \"<\")\n\n        move_class_enabled = bool(all_primitive and available_selected) or class_selected\n\n        self.move_class_button.setEnabled(bool(move_class_enabled))\n        if move_class_enabled:\n            self.move_class_button.setText(\">\" if available_selected else \"<\")\n        move_meta_enabled = available_selected or meta_selected\n\n        self.move_meta_button.setEnabled(bool(move_meta_enabled))\n        if move_meta_enabled:\n            self.move_meta_button.setText(\">\" if available_selected else \"<\")\n\n        self.__last_active_view = None\n        self.__interface_update_timer.stop()\n\n    def commit(self):\n        self.update_domain_role_hints()\n        if self.data is not None:\n            attributes = list(self.used_attrs)\n            class_var = list(self.class_attrs)\n            metas = list(self.meta_attrs)\n\n            domain = Orange.data.Domain(attributes, class_var, metas)\n            newdata = self.data.transform(domain)\n            self.output_data = newdata\n            self.Outputs.data.send(newdata)\n            self.Outputs.features.send(AttributeList(attributes))\n            self.info.set_output_summary(len(newdata),\n                                         format_summary_details(newdata))\n        else:\n            self.output_data = None\n            self.Outputs.data.send(None)\n            self.Outputs.features.send(None)\n            self.info.set_output_summary(self.info.NoOutput)\n\n    def reset(self):\n        self.enable_used_attrs()\n        self.use_features_box.checkbox.setChecked(False)\n        if self.data is not None:\n            self.available_attrs[:] = []\n            self.used_attrs[:] = self.data.domain.attributes\n            self.class_attrs[:] = self.data.domain.class_vars\n            self.meta_attrs[:] = self.data.domain.metas\n            self.update_domain_role_hints()\n            self.commit()\n\n    def send_report(self):\n        if not self.data or not self.output_data:\n            return\n        in_domain, out_domain = self.data.domain, self.output_data.domain\n        self.report_domain(\"Input data\", self.data.domain)\n        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (\n                out_domain.attributes, out_domain.class_vars, out_domain.metas):\n            self.report_paragraph(\"Output data\", \"No changes.\")\n        else:\n            self.report_domain(\"Output data\", self.output_data.domain)\n            diff = list(set(in_domain.variables + in_domain.metas) -\n                        set(out_domain.variables + out_domain.metas))\n            if diff:\n                text = \"%i (%s)\" % (len(diff), \", \".join(x.name for x in diff))\n                self.report_items(((\"Removed\", text),))\n\n\nif __name__ == \"__main__\":  # pragma: no cover\n    brown = Orange.data.Table(\"brown-selected\")\n    feats = AttributeList(brown.domain.attributes[:2])\n    WidgetPreview(OWSelectAttributes).run(set_data=brown, set_features=feats)\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:** Tests Fail with AttributeError After Renaming `select_new_features` to `ignore_new_features`

**Description:**
After renaming the `select_new_features` setting to `ignore_new_features` in the `OWSelectAttributes` widget, related tests are failing due to missing attributes.

**Example Buggy Code:**
```python
def test_select_new_features(self):
    data = Table('iris')
    domain = data.domain
    new_domain = Domain(domain.attributes[:-1], domain.class_var, domain.metas)
    new_data = Table.from_table(new_domain, data)
    self.send_signal(self.widget.Inputs.data, new_data)
    output = self.get_output(self.widget.Outputs.data)
    self.send_signal(self.widget.Inputs.data, data)
    output = self.get_output(self.widget.Outputs.data)
    self.assertFalse(self.widget.ignore_new_features)  # Raises AttributeError

def test_unselect_new_features(self):
    data = Table('iris')
    domain = data.domain
    new_domain = Domain(domain.attributes[:-1], domain.class_var, domain.metas)
    new_data = Table.from_table(new_domain, data)
    self.send_signal(self.widget.Inputs.data, new_data)
    self.widget.controls.ignore_new_features.click()  # Raises AttributeError
```

**Expected Behavior:**
The `OWSelectAttributes` widget should have an attribute named `ignore_new_features` after the rename. Tests interacting with this attribute should execute without errors, correctly reflecting the widget's state based on the new setting.

**Actual Behavior:**
Running the tests results in an `AttributeError` because the `OWSelectAttributes` object does not have an attribute named `ignore_new_features`. This prevents the tests from properly verifying the widget's functionality related to ignoring new features.

**Error Messages:**
- In `test_select_new_features`:
  ```
  AttributeError: 'OWSelectAttributes' object has no attribute 'ignore_new_features'
  ```
- In `test_unselect_new_features`:
  ```
  AttributeError: 'ignore_new_features' is not an attribute related to a gui element or component
  ```
[/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/owselectcolumns.py
from functools import partial
from typing import Optional, Dict, Tuple

from AnyQt.QtWidgets import QWidget, QGridLayout
from AnyQt.QtWidgets import QListView
from AnyQt.QtCore import (
    Qt, QTimer, QSortFilterProxyModel, QItemSelection, QItemSelectionModel,
    QMimeData, QAbstractItemModel
)

from Orange.data import Domain, Variable
from Orange.widgets import gui, widget
from Orange.widgets.settings import (
    ContextSetting, Setting, DomainContextHandler
)
from Orange.widgets.utils import vartype
from Orange.widgets.utils.listfilter import (
    VariablesListItemView, slices, variables_filter
)
from Orange.widgets.utils.widgetpreview import WidgetPreview
from Orange.widgets.utils.state_summary import format_summary_details
from Orange.widgets.widget import Input, Output, AttributeList, Msg
from Orange.data.table import Table
from Orange.widgets.utils.itemmodels import VariableListModel
import Orange


def source_model(view):
    """ Return the source model for the Qt Item View if it uses
    the QSortFilterProxyModel.
    """
    if isinstance(view.model(), QSortFilterProxyModel):
        return view.model().sourceModel()
    else:
        return view.model()


def source_indexes(indexes, view):
    """ Map model indexes through a views QSortFilterProxyModel
    """
    model = view.model()
    if isinstance(model, QSortFilterProxyModel):
        return list(map(model.mapToSource, indexes))
    else:
        return indexes


class VariablesListItemModel(VariableListModel):
    """
    An Variable list item model specialized for Drag and Drop.
    """
    MIME_TYPE = "application/x-Orange-VariableListModelData"

    def flags(self, index):
        flags = super().flags(index)
        if index.isValid():
            flags |= Qt.ItemIsDragEnabled
        else:
            flags |= Qt.ItemIsDropEnabled
        return flags

    @staticmethod
    def supportedDropActions():
        return Qt.MoveAction  # pragma: no cover

    @staticmethod
    def supportedDragActions():
        return Qt.MoveAction  # pragma: no cover

    def mimeTypes(self):
        return [self.MIME_TYPE]

    def mimeData(self, indexlist):
        """
        Reimplemented.

        For efficiency reasons only the variable instances are set on the
        mime data (under `'_items'` property)
        """
        items = [self[index.row()] for index in indexlist]
        mime = QMimeData()
        # the encoded 'data' is empty, variables are passed by properties
        mime.setData(self.MIME_TYPE, b'')
        mime.setProperty("_items", items)
        return mime

    def dropMimeData(self, mime, action, row, column, parent):
        """
        Reimplemented.
        """
        if action == Qt.IgnoreAction:
            return True  # pragma: no cover
        if not mime.hasFormat(self.MIME_TYPE):
            return False  # pragma: no cover
        variables = mime.property("_items")
        if variables is None:
            return False  # pragma: no cover
        if row < 0:
            row = self.rowCount()

        self[row:row] = variables
        return True


class SelectAttributesDomainContextHandler(DomainContextHandler):
    def encode_setting(self, context, setting, value):
        if setting.name == 'domain_role_hints':
            value = {(var.name, vartype(var)): role_i
                     for var, role_i in value.items()}
        return super().encode_setting(context, setting, value)

    def decode_setting(self, setting, value, domain=None, *_args):
        decoded = super().decode_setting(setting, value, domain)
        if setting.name == 'domain_role_hints':
            decoded = {domain[name]: role_i
                       for (name, _), role_i in decoded.items()}
        return decoded

    def match(self, context, domain, attrs, metas):
        if context.attributes == attrs and context.metas == metas:
            return self.PERFECT_MATCH

        if not "domain_role_hints" in context.values:
            return self.NO_MATCH

        all_vars = attrs.copy()
        all_vars.update(metas)
        value = context.values["domain_role_hints"][0]
        assigned = [desc for desc, (role, _) in value.items()
                    if role != "available"]
        if not assigned:
            return self.NO_MATCH
        return sum(all_vars.get(attr) == vtype for attr, vtype in assigned) \
               / len(assigned)

    def filter_value(self, setting, data, domain, attrs, metas):
        if setting.name != "domain_role_hints":
            return super().filter_value(setting, data, domain, attrs, metas)

        all_vars = attrs.copy()
        all_vars.update(metas)
        value = data["domain_role_hints"][0].items()
        data["domain_role_hints"] = {desc: role_i
                                     for desc, role_i in value
                                     if all_vars.get(desc[0]) == desc[1]}


class OWSelectAttributes(widget.OWWidget):
    # pylint: disable=too-many-instance-attributes
    name = "Select Columns"
    description = "Select columns from the data table and assign them to " \
                  "data features, classes or meta variables."
    icon = "icons/SelectColumns.svg"
    priority = 100
    keywords = ["filter", "attributes", "target", "variable"]

    class Inputs:
        data = Input("Data", Table, default=True)
        features = Input("Features", AttributeList)

    class Outputs:
        data = Output("Data", Table)
        features = Output("Features", AttributeList, dynamic=False)

    want_main_area = False
    want_control_area = True

    settingsHandler = SelectAttributesDomainContextHandler(first_match=False)
    domain_role_hints = ContextSetting({})
    use_input_features = Setting(False)
    select_new_features = Setting(True)
    auto_commit = Setting(True)

    class Warning(widget.OWWidget.Warning):
        mismatching_domain = Msg("Features and data domain do not match")

    def __init__(self):
        super().__init__()
        self.data = None
        self.features = None

        # Schedule interface updates (enabled buttons) using a coalescing
        # single shot timer (complex interactions on selection and filtering
        # updates in the 'available_attrs_view')
        self.__interface_update_timer = QTimer(self, interval=0, singleShot=True)
        self.__interface_update_timer.timeout.connect(
            self.__update_interface_state)
        # The last view that has the selection for move operation's source
        self.__last_active_view = None  # type: Optional[QListView]

        def update_on_change(view):
            # Schedule interface state update on selection change in `view`
            self.__last_active_view = view
            self.__interface_update_timer.start()

        self.controlArea = QWidget(self.controlArea)
        self.layout().addWidget(self.controlArea)
        layout = QGridLayout()
        self.controlArea.setLayout(layout)
        layout.setContentsMargins(4, 4, 4, 4)
        box = gui.vBox(self.controlArea, "Available Variables",
                       addToLayout=False)

        self.available_attrs = VariablesListItemModel()
        filter_edit, self.available_attrs_view = variables_filter(
            parent=self, model=self.available_attrs)
        box.layout().addWidget(filter_edit)

        def dropcompleted(action):
            if action == Qt.MoveAction:
                self.commit()

        self.available_attrs_view.selectionModel().selectionChanged.connect(
            partial(update_on_change, self.available_attrs_view))
        self.available_attrs_view.dragDropActionDidComplete.connect(dropcompleted)

        box.layout().addWidget(self.available_attrs_view)
        layout.addWidget(box, 0, 0, 3, 1)

        box = gui.vBox(self.controlArea, "Features", addToLayout=False)
        self.used_attrs = VariablesListItemModel()
        filter_edit, self.used_attrs_view = variables_filter(
            parent=self, model=self.used_attrs,
            accepted_type=(Orange.data.DiscreteVariable,
                           Orange.data.ContinuousVariable))
        self.used_attrs.rowsInserted.connect(self.__used_attrs_changed)
        self.used_attrs.rowsRemoved.connect(self.__used_attrs_changed)
        self.used_attrs_view.selectionModel().selectionChanged.connect(
            partial(update_on_change, self.used_attrs_view))
        self.used_attrs_view.dragDropActionDidComplete.connect(dropcompleted)
        self.use_features_box = gui.auto_commit(
            self.controlArea, self, "use_input_features",
            "Use input features", "Always use input features",
            box=False, commit=self.__use_features_clicked,
            callback=self.__use_features_changed, addToLayout=False
        )
        self.enable_use_features_box()
        box.layout().addWidget(self.use_features_box)
        box.layout().addWidget(filter_edit)
        box.layout().addWidget(self.used_attrs_view)
        layout.addWidget(box, 0, 2, 1, 1)

        box = gui.vBox(self.controlArea, "Target Variable", addToLayout=False)
        self.class_attrs = VariablesListItemModel()
        self.class_attrs_view = VariablesListItemView(
            acceptedType=(Orange.data.DiscreteVariable,
                          Orange.data.ContinuousVariable))
        self.class_attrs_view.setModel(self.class_attrs)
        self.class_attrs_view.selectionModel().selectionChanged.connect(
            partial(update_on_change, self.class_attrs_view))
        self.class_attrs_view.dragDropActionDidComplete.connect(dropcompleted)
        self.class_attrs_view.setMaximumHeight(72)
        box.layout().addWidget(self.class_attrs_view)
        layout.addWidget(box, 1, 2, 1, 1)

        box = gui.vBox(self.controlArea, "Meta Attributes", addToLayout=False)
        self.meta_attrs = VariablesListItemModel()
        self.meta_attrs_view = VariablesListItemView(
            acceptedType=Orange.data.Variable)
        self.meta_attrs_view.setModel(self.meta_attrs)
        self.meta_attrs_view.selectionModel().selectionChanged.connect(
            partial(update_on_change, self.meta_attrs_view))
        self.meta_attrs_view.dragDropActionDidComplete.connect(dropcompleted)
        box.layout().addWidget(self.meta_attrs_view)
        layout.addWidget(box, 2, 2, 1, 1)

        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)
        layout.addWidget(bbox, 0, 1, 1, 1)

        self.up_attr_button = gui.button(bbox, self, "Up",
                                         callback=partial(self.move_up, self.used_attrs_view))
        self.move_attr_button = gui.button(bbox, self, ">",
                                           callback=partial(self.move_selected,
                                                            self.used_attrs_view)
                                          )
        self.down_attr_button = gui.button(bbox, self, "Down",
                                           callback=partial(self.move_down, self.used_attrs_view))

        bbox = gui.vBox(self.controlArea, addToLayout=False, margin=0)
        layout.addWidget(bbox, 1, 1, 1, 1)

        self.up_class_button = gui.button(bbox, self, "Up",
                                          callback=partial(self.move_up, self.class_attrs_view))
        self.move_class_button = gui.button(bbox, self, ">",
                                            callback=partial(self.move_selected,
                                                             self.class_attrs_view)
                                           )
        self.down_class_button = gui.button(bbox, self, "Down",
                                            callback=partial(self.move_down, self.class_attrs_view))

        bbox = gui.vBox(self.controlArea, addToLayout=False)
        layout.addWidget(bbox, 2, 1, 1, 1)
        self.up_meta_button = gui.button(bbox, self, "Up",
                                         callback=partial(self.move_up, self.meta_attrs_view))
        self.move_meta_button = gui.button(bbox, self, ">",
                                           callback=partial(self.move_selected,
                                                            self.meta_attrs_view)
                                          )
        self.down_meta_button = gui.button(bbox, self, "Down",
                                           callback=partial(self.move_down, self.meta_attrs_view))

        bbox = gui.vBox(self.controlArea, "Additional settings", addToLayout=False)
        gui.checkBox(
            bbox, self, "select_new_features", "Automatically select additional/new features"
        )
        layout.addWidget(bbox, 3, 0, 1, 3)

        autobox = gui.auto_send(None, self, "auto_commit")
        layout.addWidget(autobox, 4, 0, 1, 3)
        reset = gui.button(None, self, "Reset", callback=self.reset, width=120)
        autobox.layout().insertWidget(0, reset)
        autobox.layout().insertStretch(1, 20)

        layout.setRowStretch(0, 4)
        layout.setRowStretch(1, 0)
        layout.setRowStretch(2, 2)
        layout.setHorizontalSpacing(0)
        self.controlArea.setLayout(layout)

        self.output_data = None
        self.original_completer_items = []

        self.info.set_input_summary(self.info.NoInput)
        self.info.set_output_summary(self.info.NoOutput)

        self.resize(600, 600)

    @property
    def features_from_data_attributes(self):
        if self.data is None or self.features is None:
            return []
        domain = self.data.domain
        return [domain[feature.name] for feature in self.features
                if feature.name in domain and domain[feature.name]
                in domain.attributes]

    def can_use_features(self):
        return bool(self.features_from_data_attributes) and \
               self.features_from_data_attributes != self.used_attrs[:]

    def __use_features_changed(self):  # Use input features check box
        # Needs a check since callback is invoked before object is created
        if not hasattr(self, "use_features_box"):
            return
        self.enable_used_attrs(not self.use_input_features)
        if self.use_input_features and self.can_use_features():
            self.use_features()
        if not self.use_input_features:
            self.enable_use_features_box()

    def __use_features_clicked(self):  # Use input features button
        self.use_features()

    def __used_attrs_changed(self):
        self.enable_use_features_box()

    @Inputs.data
    def set_data(self, data=None):
        self.update_domain_role_hints()
        self.closeContext()
        self.domain_role_hints = {}

        self.data = data
        if data is None:
            self.used_attrs[:] = []
            self.class_attrs[:] = []
            self.meta_attrs[:] = []
            self.available_attrs[:] = []
            self.info.set_input_summary(self.info.NoInput)
            return

        self.openContext(data)
        all_vars = data.domain.variables + data.domain.metas

        def attrs_for_role(role):
            selected_attrs = [
                attr for attr in all_vars if domain_hints[attr][0] == role
            ]
            return sorted(selected_attrs, key=lambda attr: domain_hints[attr][1])

        domain_hints = self.restore_hints(data.domain)
        self.used_attrs[:] = attrs_for_role("attribute")
        self.class_attrs[:] = attrs_for_role("class")
        self.meta_attrs[:] = attrs_for_role("meta")
        self.available_attrs[:] = attrs_for_role("available")
        self.info.set_input_summary(len(data), format_summary_details(data))

    def restore_hints(self, domain: Domain) -> Dict[Variable, Tuple[str, int]]:
        """
        Define hints for selected/unselected features.
        Rules:
        - if context available, restore new features based on checked/unchecked
          select_new_features, context hint should be took into account
        - in no context, restore features based on the domain (as selected)

        Parameters
        ----------
        domain
            Data domain

        Returns
        -------
        Dictionary with hints about order and model in which each feature
        should appear
        """
        domain_hints = {}
        if self.select_new_features or len(self.domain_role_hints) == 0:
            # select_new_features selected or no context - restore based on domain
            domain_hints.update(
                self._hints_from_seq("attribute", domain.attributes)
            )
            domain_hints.update(self._hints_from_seq("meta", domain.metas))
            domain_hints.update(
                self._hints_from_seq("class", domain.class_vars)
            )
        else:
            # if context restored and select_new_features unselected - restore
            # new features as available
            d = domain.attributes + domain.metas + domain.class_vars
            domain_hints.update(self._hints_from_seq("available", d))

        domain_hints.update(self.domain_role_hints)
        return domain_hints

    def update_domain_role_hints(self):
        """ Update the domain hints to be stored in the widgets settings.
        """
        hints = {}
        hints.update(self._hints_from_seq("available", self.available_attrs))
        hints.update(self._hints_from_seq("attribute", self.used_attrs))
        hints.update(self._hints_from_seq("class", self.class_attrs))
        hints.update(self._hints_from_seq("meta", self.meta_attrs))
        self.domain_role_hints = hints

    @staticmethod
    def _hints_from_seq(role, model):
        return [(attr, (role, i)) for i, attr in enumerate(model)]

    @Inputs.features
    def set_features(self, features):
        self.features = features

    def handleNewSignals(self):
        self.check_data()
        self.enable_used_attrs()
        self.enable_use_features_box()
        if self.use_input_features and self.features_from_data_attributes:
            self.enable_used_attrs(False)
            self.use_features()
        self.unconditional_commit()

    def check_data(self):
        self.Warning.mismatching_domain.clear()
        if self.data is not None and self.features is not None and \
                not self.features_from_data_attributes:
            self.Warning.mismatching_domain()

    def enable_used_attrs(self, enable=True):
        self.up_attr_button.setEnabled(enable)
        self.move_attr_button.setEnabled(enable)
        self.down_attr_button.setEnabled(enable)
        self.used_attrs_view.setEnabled(enable)
        self.used_attrs_view.repaint()

    def enable_use_features_box(self):
        self.use_features_box.button.setEnabled(self.can_use_features())
        enable_checkbox = bool(self.features_from_data_attributes)
        self.use_features_box.setHidden(not enable_checkbox)
        self.use_features_box.repaint()

    def use_features(self):
        attributes = self.features_from_data_attributes
        available, used = self.available_attrs[:], self.used_attrs[:]
        self.available_attrs[:] = [attr for attr in used + available
                                   if attr not in attributes]
        self.used_attrs[:] = attributes
        self.commit()

    @staticmethod
    def selected_rows(view):
        """ Return the selected rows in the view.
        """
        rows = view.selectionModel().selectedRows()
        model = view.model()
        if isinstance(model, QSortFilterProxyModel):
            rows = [model.mapToSource(r) for r in rows]
        return [r.row() for r in rows]

    def move_rows(self, view: QListView, offset: int, roles=(Qt.EditRole,)):
        rows = [idx.row() for idx in view.selectionModel().selectedRows()]
        model = view.model()  # type: QAbstractItemModel
        rowcount = model.rowCount()
        newrows = [min(max(0, row + offset), rowcount - 1) for row in rows]

        def itemData(index):
            return {role: model.data(index, role) for role in roles}

        for row, newrow in sorted(zip(rows, newrows), reverse=offset > 0):
            d1 = itemData(model.index(row, 0))
            d2 = itemData(model.index(newrow, 0))
            model.setItemData(model.index(row, 0), d2)
            model.setItemData(model.index(newrow, 0), d1)

        selection = QItemSelection()
        for nrow in newrows:
            index = model.index(nrow, 0)
            selection.select(index, index)
        view.selectionModel().select(
            selection, QItemSelectionModel.ClearAndSelect)

        self.commit()

    def move_up(self, view: QListView):
        self.move_rows(view, -1)

    def move_down(self, view: QListView):
        self.move_rows(view, 1)

    def move_selected(self, view):
        if self.selected_rows(view):
            self.move_selected_from_to(view, self.available_attrs_view)
        elif self.selected_rows(self.available_attrs_view):
            self.move_selected_from_to(self.available_attrs_view, view)

    def move_selected_from_to(self, src, dst):
        self.move_from_to(src, dst, self.selected_rows(src))

    def move_from_to(self, src, dst, rows):
        src_model = source_model(src)
        attrs = [src_model[r] for r in rows]

        for s1, s2 in reversed(list(slices(rows))):
            del src_model[s1:s2]

        dst_model = source_model(dst)

        dst_model.extend(attrs)

        self.commit()

    def __update_interface_state(self):
        last_view = self.__last_active_view
        if last_view is not None:
            self.update_interface_state(last_view)

    def update_interface_state(self, focus=None):
        for view in [self.available_attrs_view, self.used_attrs_view,
                     self.class_attrs_view, self.meta_attrs_view]:
            if view is not focus and not view.hasFocus() \
                    and view.selectionModel().hasSelection():
                view.selectionModel().clear()

        def selected_vars(view):
            model = source_model(view)
            return [model[i] for i in self.selected_rows(view)]

        available_selected = selected_vars(self.available_attrs_view)
        attrs_selected = selected_vars(self.used_attrs_view)
        class_selected = selected_vars(self.class_attrs_view)
        meta_selected = selected_vars(self.meta_attrs_view)

        available_types = set(map(type, available_selected))
        all_primitive = all(var.is_primitive()
                            for var in available_types)

        move_attr_enabled = \
            ((available_selected and all_primitive) or attrs_selected) and \
            self.used_attrs_view.isEnabled()

        self.move_attr_button.setEnabled(bool(move_attr_enabled))
        if move_attr_enabled:
            self.move_attr_button.setText(">" if available_selected else "<")

        move_class_enabled = bool(all_primitive and available_selected) or class_selected

        self.move_class_button.setEnabled(bool(move_class_enabled))
        if move_class_enabled:
            self.move_class_button.setText(">" if available_selected else "<")
        move_meta_enabled = available_selected or meta_selected

        self.move_meta_button.setEnabled(bool(move_meta_enabled))
        if move_meta_enabled:
            self.move_meta_button.setText(">" if available_selected else "<")

        self.__last_active_view = None
        self.__interface_update_timer.stop()

    def commit(self):
        self.update_domain_role_hints()
        if self.data is not None:
            attributes = list(self.used_attrs)
            class_var = list(self.class_attrs)
            metas = list(self.meta_attrs)

            domain = Orange.data.Domain(attributes, class_var, metas)
            newdata = self.data.transform(domain)
            self.output_data = newdata
            self.Outputs.data.send(newdata)
            self.Outputs.features.send(AttributeList(attributes))
            self.info.set_output_summary(len(newdata),
                                         format_summary_details(newdata))
        else:
            self.output_data = None
            self.Outputs.data.send(None)
            self.Outputs.features.send(None)
            self.info.set_output_summary(self.info.NoOutput)

    def reset(self):
        self.enable_used_attrs()
        self.use_features_box.checkbox.setChecked(False)
        if self.data is not None:
            self.available_attrs[:] = []
            self.used_attrs[:] = self.data.domain.attributes
            self.class_attrs[:] = self.data.domain.class_vars
            self.meta_attrs[:] = self.data.domain.metas
            self.update_domain_role_hints()
            self.commit()

    def send_report(self):
        if not self.data or not self.output_data:
            return
        in_domain, out_domain = self.data.domain, self.output_data.domain
        self.report_domain("Input data", self.data.domain)
        if (in_domain.attributes, in_domain.class_vars, in_domain.metas) == (
                out_domain.attributes, out_domain.class_vars, out_domain.metas):
            self.report_paragraph("Output data", "No changes.")
        else:
            self.report_domain("Output data", self.output_data.domain)
            diff = list(set(in_domain.variables + in_domain.metas) -
                        set(out_domain.variables + out_domain.metas))
            if diff:
                text = "%i (%s)" % (len(diff), ", ".join(x.name for x in diff))
                self.report_items((("Removed", text),))


if __name__ == "__main__":  # pragma: no cover
    brown = Orange.data.Table("brown-selected")
    feats = AttributeList(brown.domain.attributes[:2])
    WidgetPreview(OWSelectAttributes).run(set_data=brown, set_features=feats)

```
--- 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