def test_extend(self): model = PyListModel([]) model.extend([1, 2, 3, 4]) self.assertSequenceEqual(model, [1, 2, 3, 4]) model.extend([5, 6]) self.assertSequenceEqual(model, [1, 2, 3, 4, 5, 6]) self.assertEqual(len(model), len(model._other_data))
def test_clear(self): model = PyListModel([1, 2, 3, 2, 4]) model.clear() self.assertSequenceEqual(model, []) self.assertEqual(len(model), len(model._other_data)) model.clear() self.assertSequenceEqual(model, []) self.assertEqual(len(model), len(model._other_data))
def test_append(self): model = PyListModel([]) model.append(1) self.assertSequenceEqual(model, [1]) model.append(2) self.assertSequenceEqual(model, [1, 2]) self.assertEqual(len(model), len(model._other_data))
def test_insert_delete_rows(self): model = PyListModel([1, 2, 3, 4]) success = model.insertRows(0, 3) self.assertIs(success, True) self.assertSequenceEqual(model, [None, None, None, 1, 2, 3, 4]) success = model.removeRows(3, 4) self.assertIs(success, True) self.assertSequenceEqual(model, [None, None, None])
def test_wrap(self): model = PyListModel() s = [1, 2] model.wrap(s) self.assertSequenceEqual(model, [1, 2]) model.append(3) self.assertEqual(s, [1, 2, 3]) self.assertEqual(len(model._other_data), 3) s.append(5) self.assertRaises(RuntimeError, model._is_index_valid, 0)
def test_dropMimeData(self): model = PyListModel([1, 2]) model.setData(model.index(0), "a", Qt.UserRole) mime = model.mimeData([model.index(0)]) self.assertTrue( model.dropMimeData(mime, Qt.CopyAction, 2, -1, model.index(-1, -1)) ) self.assertEqual(len(model), 3) self.assertEqual( model.itemData(model.index(2)), {Qt.DisplayRole: 1, Qt.EditRole: 1, Qt.UserRole: "a"} )
def test_itemData(self): model = PyListModel([1, 2, 3, 4]) mi = model.index(2) model.setItemData(mi, {Qt.ToolTipRole: "foo"}) self.assertEqual(model.itemData(mi)[Qt.ToolTipRole], "foo") self.assertEqual(model.itemData(model.index(5)), {})
def __init__(self, parent, model_list, **kwargs): super().__init__(parent, **kwargs) self.setValidator(self.Validator()) self.setModel(PyListModel(iterable=model_list, flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable, parent=self)) self.view().setItemDelegate(self.TitleShowingPopupDelegate(self))
def test_construct_variables_discrete(self): data = Table("iris") name = "Discrete Variable" expression = ("iris_one if iris == 'Iris-setosa' else iris_two " "if iris == 'Iris-versicolor' else iris_three") values = ("iris one", "iris two", "iris three") desc = PyListModel([ DiscreteDescriptor( name=name, expression=expression, values=values, base_value=-1, ordered=False, ) ]) data = Table( Domain( list(data.domain.attributes) + construct_variables(desc, data.domain.variables), data.domain.class_vars, data.domain.metas, ), data, ) self.assertTrue(isinstance(data.domain[name], DiscreteVariable)) self.assertEqual(data.domain[name].values, list(values)) for i in range(3): self.assertEqual(data[i * 50, name], values[i])
def __init__(self): OWWidget.__init__(self) ConcurrentWidgetMixin.__init__(self) self.__onto_handler = OntologyHandler() flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable self.__model = PyListModel([], self, flags=flags) self.__input_model = QStandardItemModel() self.__library_view: QListView = None self.__input_view: ListViewSearch = None self.__ontology_view: EditableTreeView = None self.ontology_info = "" self._setup_gui() self._restore_state() self.settingsAboutToBePacked.connect(self._save_state)
def test_delitem(self): model = PyListModel([1, 2, 3, 4]) del model[1] self.assertSequenceEqual(model, [1, 3, 4]) model = PyListModel([1, 2, 3, 4]) del model[1:3] self.assertSequenceEqual(model, [1, 4]) model = PyListModel([1, 2, 3, 4]) del model[:] self.assertSequenceEqual(model, []) model = PyListModel([1, 2, 3, 4]) with self.assertRaises(IndexError): # non unit strides currently not supported del model[0:-1:2]
def test_delitem(self): model = PyListModel([1, 2, 3, 4]) model._other_data = list("abcd") del model[1] self.assertSequenceEqual(model, [1, 3, 4]) self.assertSequenceEqual(model._other_data, "acd") model = PyListModel([1, 2, 3, 4]) model._other_data = list("abcd") del model[1:3] self.assertSequenceEqual(model, [1, 4]) self.assertSequenceEqual(model._other_data, "ad") model = PyListModel([1, 2, 3, 4]) model._other_data = list("abcd") del model[:] self.assertSequenceEqual(model, []) self.assertEqual(len(model._other_data), 0) model = PyListModel([1, 2, 3, 4]) with self.assertRaises(IndexError): # non unit strides currently not supported del model[0:-1:2] self.assertEqual(len(model), len(model._other_data))
def update(model: PyListModel, lib_words: List, in_words: List, rule: int): if rule == UpdateRules.INTERSECT: intersect = set(lib_words) & set(in_words) model.wrap(list({k: None for k in lib_words if k in intersect})) elif rule == UpdateRules.UNION: model.wrap(list({k: None for k in lib_words + in_words})) elif rule == UpdateRules.INPUT: model.wrap(list(in_words)) elif rule == UpdateRules.LIBRARY: model.wrap(list(lib_words)) else: raise NotImplementedError
def test_setitem(self): model = PyListModel([1, 2, 3, 4]) model[1] = 42 self.assertSequenceEqual(model, [1, 42, 3, 4]) model[-1] = 42 self.assertSequenceEqual(model, [1, 42, 3, 42]) with self.assertRaises(IndexError): model[4] with self.assertRaises(IndexError): model[-5] model = PyListModel([1, 2, 3, 4]) model[0:0] = [-1, 0] self.assertSequenceEqual(model, [-1, 0, 1, 2, 3, 4]) model = PyListModel([1, 2, 3, 4]) model[len(model):len(model)] = [5, 6] self.assertSequenceEqual(model, [1, 2, 3, 4, 5, 6]) model = PyListModel([1, 2, 3, 4]) model[0:2] = [-1, -2] self.assertSequenceEqual(model, [-1, -2, 3, 4]) model = PyListModel([1, 2, 3, 4]) model[-2:] = [-3, -4] self.assertSequenceEqual(model, [1, 2, -3, -4]) model = PyListModel([1, 2, 3, 4]) with self.assertRaises(IndexError): # non unit strides currently not supported model[0:-1:2] = [3, 3]
def test_construct_variables_string(self): data = Table("iris") name = 'String Variable' expression = "str(iris) + '_name'" desc = PyListModel( [StringDescriptor(name=name, expression=expression)]) data = data.transform( Domain(data.domain.attributes, data.domain.class_vars, list(data.domain.metas) + construct_variables(desc, data))) self.assertTrue(isinstance(data.domain[name], StringVariable)) for i in range(3): self.assertEqual(data[i * 50, name], str(data[i * 50, "iris"]) + "_name")
def test_construct_numeric_names(self): data = Table("iris") data.domain.attributes[0].name = "0.1" data.domain.attributes[1].name = "1" desc = PyListModel([ ContinuousDescriptor(name="S", expression="_0_1 + _1", number_of_decimals=3) ]) nv = construct_variables(desc, data.domain) ndata = Table(Domain(nv, None), data) np.testing.assert_array_equal(ndata.X[:, 0], data.X[:, :2].sum(axis=1)) ContinuousVariable._clear_all_caches()
def test_unicode_normalization(): micro = "\u00b5" domain = Domain([ContinuousVariable(micro)]) name = 'Micro Variable' expression = micro desc = PyListModel( [ContinuousDescriptor(name=name, expression=expression, number_of_decimals=2)] ) data = Table.from_numpy(domain, np.arange(5).reshape(5, 1)) data = data.transform(Domain(data.domain.attributes, [], construct_variables(desc, data))) np.testing.assert_equal(data.X, data.metas)
def __init__(self): super().__init__(self) flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable self.library_model = PyListModel([], self, flags=flags) self.words_model = PyListModel([], self, flags=flags, enable_dnd=True) self.library_view: QListView = None self.words_view: ListView = None self.__input_words_model = DomainModel(valid_types=(StringVariable, )) self.__input_words: Optional[Table] = None self.__library_box: QGroupBox = gui.vBox(None, "Library") self.__input_box: QGroupBox = gui.vBox(None, "Input") self.__words_box: QGroupBox = gui.vBox(None, box=True) self.__update_rule_rb: QRadioButton = None self.__add_word_action: QAction = None self.__remove_word_action: QAction = None self._setup_gui() self._restore_state() self.settingsAboutToBePacked.connect(self._save_state)
def test_construct_numeric_names(): data = Table("iris") newdomain = Domain( (ContinuousVariable("0.1"), ContinuousVariable("1")) + data.domain.attributes[2:], data.domain.class_var) data = Table.from_numpy(newdomain, data.X, data.Y) desc = PyListModel([ ContinuousDescriptor(name="S", expression="_0_1 + _1", number_of_decimals=3) ]) nv = construct_variables(desc, data) ndata = Table(Domain(nv, None), data) np.testing.assert_array_equal(ndata.X[:, 0], data.X[:, :2].sum(axis=1))
def test_list_specials(self): # Essentially tested in other tests, but let's do it explicitly, too # __len__ self.assertEqual(len(self.model), 4) # __contains__ self.assertTrue(2 in self.model) self.assertFalse(5 in self.model) # __iter__ self.assertSequenceEqual(self.model, [1, 2, 3, 4]) # __bool__ self.assertTrue(bool(self.model)) self.assertFalse(bool(PyListModel()))
def test_construct_variables_datetime(self): data = Table("housing") name = 'Date' expression = '"2019-07-{:02}".format(int(MEDV/3))' featuremodel = PyListModel( [DateTimeDescriptor(name=name, expression=expression)]) data = Table( Domain( list(data.domain.attributes) + construct_variables(featuremodel, data), data.domain.class_vars, data.domain.metas), data) self.assertTrue(isinstance(data.domain[name], TimeVariable)) for row in data: self.assertEqual("2019-07-{:02}".format(int(row["MEDV"] / 3)), str(row["Date"])[:10])
def test_construct_variables_continuous(self): data = Table("iris") name = 'Continuous Variable' expression = "pow(sepal_length + sepal_width, 2)" featuremodel = PyListModel( [ContinuousDescriptor(name=name, expression=expression, number_of_decimals=2)] ) data = Table(Domain(list(data.domain.attributes) + construct_variables(featuremodel, data.domain), data.domain.class_vars, data.domain.metas), data) self.assertTrue(isinstance(data.domain[name], ContinuousVariable)) for i in range(3): self.assertEqual(data[i * 50, name], pow(data[i * 50, 0] + data[i * 50, 1], 2))
def test_construct_variables_discrete(self): data = Table("iris") name = 'Discrete Variable' expression = "iris_one if iris == 'Iris-setosa' else iris_two " \ "if iris == 'Iris-versicolor' else iris_three" values = ('iris one', 'iris two', 'iris three') desc = PyListModel( [DiscreteDescriptor(name=name, expression=expression, values=values, ordered=False)] ) data = data.transform(Domain(list(data.domain.attributes) + construct_variables(desc, data), data.domain.class_vars, data.domain.metas)) self.assertTrue(isinstance(data.domain[name], DiscreteVariable)) self.assertEqual(data.domain[name].values, values) for i in range(3): self.assertEqual(data[i * 50, name], values[i])
def setup_visible_image_controls(self): self.visbox = gui.widgetBox(self.controlArea, True) gui.checkBox(self.visbox, self, 'show_visible_image', label='Show visible image', callback=lambda: (self.update_visible_image_interface(), self.update_visible_image())) self.visible_image_model = VisibleImageListModel() gui.comboBox(self.visbox, self, 'visible_image', model=self.visible_image_model, callback=self.update_visible_image) self.visual_image_composition_modes = OrderedDict([ ('Normal', QPainter.CompositionMode_Source), ('Overlay', QPainter.CompositionMode_Overlay), ('Multiply', QPainter.CompositionMode_Multiply), ('Difference', QPainter.CompositionMode_Difference) ]) gui.comboBox(self.visbox, self, 'visible_image_composition', label='Composition mode:', model=PyListModel( self.visual_image_composition_modes.keys()), callback=self.update_visible_image_composition_mode) gui.hSlider(self.visbox, self, 'visible_image_opacity', label='Opacity:', minValue=0, maxValue=255, step=10, createLabel=False, callback=self.update_visible_image_opacity) self.update_visible_image_interface() self.update_visible_image_composition_mode() self.update_visible_image_opacity()
def test_construct_variables_discrete_no_values(self): data = Table("iris") name = 'Discrete Variable' expression = "str(iris)[-1]" # last letter - a or r values = () desc = PyListModel( [DiscreteDescriptor(name=name, expression=expression, values=values, ordered=False)] ) data = data.transform(Domain(list(data.domain.attributes) + construct_variables(desc, data), data.domain.class_vars, data.domain.metas)) newvar = data.domain[name] self.assertTrue(isinstance(newvar, DiscreteVariable)) self.assertEqual(set(data.domain[name].values), set("ar")) for i in range(3): inst = data[i * 50] self.assertEqual(str(inst[name]), str(inst["iris"])[-1])
def test_token_list_completer(self): from Orange.widgets.utils.itemmodels import PyListModel completer = TokenListCompleter() completer.setTokenList(["foo", "bar", "baz"]) completer.setCompletionPrefix("foo b") def completions(completer): current = completer.currentRow() items = [] for i in range(completer.completionCount()): completer.setCurrentRow(i) items.append(completer.currentCompletion()) completer.setCurrentRow(current) return items self.assertSequenceEqual(completions(completer), ["foo bar", "foo baz"]) completer.setModel(None) self.assertSequenceEqual(completer.tokenList(), []) self.assertSequenceEqual(completions(completer), []) completer.setModel(QStringListModel(["a", "ab", "b"])) self.assertSequenceEqual(completer.tokenList(), ["a", "ab", "b"]) completer.setCompletionPrefix("a a") self.assertSequenceEqual(completions(completer), ["a a", "a ab"]) completer.setModel(PyListModel(["a", "aa", "ab", "ad"])) self.assertSequenceEqual(completer.tokenList(), ["a", "aa", "ab", "ad"]) completer.model()[-1] = "z" self.assertSequenceEqual(completer.tokenList(), ["a", "aa", "ab", "z"]) completer.model()[-2:] = ["ax", "az"] self.assertSequenceEqual(completer.tokenList(), ["a", "aa", "ax", "az"]) completer.setSeparator(",") completer.setCompletionPrefix("a, a") self.assertSequenceEqual(completions(completer), ["a, a", "a, aa", "a, ax", "a, az"])
def __init__(self, *args, **kwargs): self.__pp_data: Optional[Table] = None self.__param_widget: ParametersWidget = None self.__expression_edit: QLineEdit = None self.__feature_combo: ComboBoxSearch = None self.__parameter_combo: ComboBoxSearch = None self.__function_combo: ComboBoxSearch = None self.__feature_model = DomainModel( order=DomainModel.ATTRIBUTES, placeholder=self.FEATURE_PLACEHOLDER, separators=False, valid_types=ContinuousVariable) self.__param_model = PyListModel([self.PARAM_PLACEHOLDER]) self.__pending_parameters = self.parameters self.__pending_expression = self.expression super().__init__(*args, **kwargs) self.Warning.data_missing()
def test_set_data(self): model = PyListModel([1, 2, 3, 4]) model.setData(model.index(0), None, Qt.EditRole) self.assertIs(model.data(model.index(0), Qt.EditRole), None) model.setData(model.index(1), "This is two", Qt.ToolTipRole) self.assertEqual(model.data(model.index(1), Qt.ToolTipRole), "This is two",) self.assertFalse(model.setData(model.index(5), "foo"))
def __init__(self): super().__init__() self.domain = None self.data = None self.loaded_file = "" self._relocate_recent_files() vbox = gui.radioButtons( self.controlArea, self, "source", box=True, addSpace=True, callback=self.load_data) box = gui.widgetBox(vbox, orientation="horizontal") gui.appendRadioButton(vbox, "File", insertInto=box) self.file_combo = QtGui.QComboBox( box, sizeAdjustPolicy=QtGui.QComboBox.AdjustToContents) self.file_combo.setMinimumWidth(250) box.layout().addWidget(self.file_combo) self.file_combo.activated[int].connect(self.select_file) button = gui.button( box, self, '...', callback=self.browse_file, autoDefault=False) button.setIcon(self.style().standardIcon(QtGui.QStyle.SP_DirOpenIcon)) button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) button = gui.button( box, self, "Reload", callback=self.reload, autoDefault=False) button.setIcon( self.style().standardIcon(QtGui.QStyle.SP_BrowserReload)) button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) box = gui.widgetBox(vbox, orientation="horizontal") gui.appendRadioButton(vbox, "URL", insertInto=box) self.le_url = le_url = QtGui.QLineEdit(self.url) l, t, r, b = le_url.getTextMargins() le_url.setTextMargins(l + 5, t, r, b) le_url.editingFinished.connect(self._url_set) box.layout().addWidget(le_url) self.completer_model = PyListModel() self.completer_model.wrap(self.recent_urls) completer = QtGui.QCompleter() completer.setModel(self.completer_model) completer.setCompletionMode(completer.PopupCompletion) completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive) le_url.setCompleter(completer) box = gui.widgetBox(self.controlArea, "Info") self.info = gui.widgetLabel(box, 'No data loaded.') self.warnings = gui.widgetLabel(box, '') box = gui.widgetBox(self.controlArea, orientation="horizontal") gui.button(box, self, "Browse documentation data sets", callback=lambda: self.browse_file(True), autoDefault=False) gui.rubber(box) box.layout().addWidget(self.report_button) self.report_button.setFixedWidth(170) # Set word wrap, so long warnings won't expand the widget self.warnings.setWordWrap(True) self.warnings.setSizePolicy( QSizePolicy.Ignored, QSizePolicy.MinimumExpanding) self.set_file_list() # Must not call open_file from within __init__. open_file # explicitly re-enters the event loop (by a progress bar) QtCore.QTimer.singleShot(0, self.load_data)
def test_moveRows(self): model = PyListModel([1, 2, 3, 4]) for i in range(model.rowCount()): model.setData(model.index(i), str(i + 1), Qt.UserRole) def modeldata(role): return [model.index(i).data(role) for i in range(model.rowCount())] def userdata(): return modeldata(Qt.UserRole) def editdata(): return modeldata(Qt.EditRole) r = model.moveRows(QModelIndex(), 1, 1, QModelIndex(), 0) self.assertIs(r, True) self.assertSequenceEqual(editdata(), [2, 1, 3, 4]) self.assertSequenceEqual(userdata(), ["2", "1", "3", "4"]) r = model.moveRows(QModelIndex(), 1, 2, QModelIndex(), 4) self.assertIs(r, True) self.assertSequenceEqual(editdata(), [2, 4, 1, 3]) self.assertSequenceEqual(userdata(), ["2", "4", "1", "3"]) r = model.moveRows(QModelIndex(), 3, 1, QModelIndex(), 0) self.assertIs(r, True) self.assertSequenceEqual(editdata(), [3, 2, 4, 1]) self.assertSequenceEqual(userdata(), ["3", "2", "4", "1"]) r = model.moveRows(QModelIndex(), 2, 1, QModelIndex(), 2) self.assertIs(r, False) model = PyListModel([]) r = model.moveRows(QModelIndex(), 0, 0, QModelIndex(), 0) self.assertIs(r, False)
def test_set_data(self): model = PyListModel([1, 2, 3, 4]) model.setData(model.index(0), None, Qt.EditRole) self.assertIs(model.data(model.index(0), Qt.EditRole), None) model.setData(model.index(1), "This is two", Qt.ToolTipRole) self.assertEqual( model.data(model.index(1), Qt.ToolTipRole), "This is two", )
def setUpClass(cls): cls.model = PyListModel([1, 2, 3, 4])
def test_sort(self): model = PyListModel([3, 1, 4, 2]) model._other_data = list("abcd") model.sort() self.assertSequenceEqual(model, [1, 2, 3, 4]) self.assertSequenceEqual(model._other_data, "bdac")
def test_mimeData(self): model = PyListModel([1, 2]) model._other_data[:] = [{Qt.UserRole: "a"}, {}] mime = model.mimeData([model.index(0), model.index(1)]) self.assertTrue(mime.hasFormat(PyListModel.MIME_TYPE))
class OWFile(widget.OWWidget): name = "File" id = "orange.widgets.data.file" description = "Read a data from an input file or network" \ "and send the data table to the output." icon = "icons/File.svg" priority = 10 category = "Data" keywords = ["data", "file", "load", "read"] outputs = [widget.OutputSignal( "Data", Table, doc="Attribute-valued data set read from the input file.")] want_main_area = False resizing_enabled = False LOCAL_FILE, URL = range(2) #: List[RecentPath] recent_paths = Setting([]) recent_urls = Setting([]) source = Setting(LOCAL_FILE) url = Setting("") dlg_formats = ( "All readable files ({});;".format( '*' + ' *'.join(FileFormat.readers.keys())) + ";;".join("{} (*{})".format(f.DESCRIPTION, ' *'.join(f.EXTENSIONS)) for f in sorted(set(FileFormat.readers.values()), key=list(FileFormat.readers.values()).index))) def __init__(self): super().__init__() self.domain = None self.data = None self.loaded_file = "" self._relocate_recent_files() vbox = gui.radioButtons( self.controlArea, self, "source", box=True, addSpace=True, callback=self.load_data) box = gui.widgetBox(vbox, orientation="horizontal") gui.appendRadioButton(vbox, "File", insertInto=box) self.file_combo = QtGui.QComboBox( box, sizeAdjustPolicy=QtGui.QComboBox.AdjustToContents) self.file_combo.setMinimumWidth(250) box.layout().addWidget(self.file_combo) self.file_combo.activated[int].connect(self.select_file) button = gui.button( box, self, '...', callback=self.browse_file, autoDefault=False) button.setIcon(self.style().standardIcon(QtGui.QStyle.SP_DirOpenIcon)) button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) button = gui.button( box, self, "Reload", callback=self.reload, autoDefault=False) button.setIcon( self.style().standardIcon(QtGui.QStyle.SP_BrowserReload)) button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) box = gui.widgetBox(vbox, orientation="horizontal") gui.appendRadioButton(vbox, "URL", insertInto=box) self.le_url = le_url = QtGui.QLineEdit(self.url) l, t, r, b = le_url.getTextMargins() le_url.setTextMargins(l + 5, t, r, b) le_url.editingFinished.connect(self._url_set) box.layout().addWidget(le_url) self.completer_model = PyListModel() self.completer_model.wrap(self.recent_urls) completer = QtGui.QCompleter() completer.setModel(self.completer_model) completer.setCompletionMode(completer.PopupCompletion) completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive) le_url.setCompleter(completer) box = gui.widgetBox(self.controlArea, "Info") self.info = gui.widgetLabel(box, 'No data loaded.') self.warnings = gui.widgetLabel(box, '') box = gui.widgetBox(self.controlArea, orientation="horizontal") gui.button(box, self, "Browse documentation data sets", callback=lambda: self.browse_file(True), autoDefault=False) gui.rubber(box) box.layout().addWidget(self.report_button) self.report_button.setFixedWidth(170) # Set word wrap, so long warnings won't expand the widget self.warnings.setWordWrap(True) self.warnings.setSizePolicy( QSizePolicy.Ignored, QSizePolicy.MinimumExpanding) self.set_file_list() # Must not call open_file from within __init__. open_file # explicitly re-enters the event loop (by a progress bar) QtCore.QTimer.singleShot(0, self.load_data) def _relocate_recent_files(self): paths = [("sample-datasets", get_sample_datasets_dir())] basedir = self.workflowEnv().get("basedir", None) if basedir is not None: paths.append(("basedir", basedir)) rec = [] for recent in self.recent_paths: resolved = recent.resolve(paths) if resolved is not None: rec.append(RecentPath.create(resolved.abspath, paths)) elif recent.search(paths) is not None: rec.append(RecentPath.create(recent.search(paths), paths)) self.recent_paths = rec def set_file_list(self): self.file_combo.clear() if not self.recent_paths: self.file_combo.addItem("(none)") self.file_combo.model().item(0).setEnabled(False) else: for i, recent in enumerate(self.recent_paths): self.file_combo.addItem(recent.value) self.file_combo.model().item(i).setToolTip(recent.abspath) def reload(self): if self.recent_paths: basename = self.file_combo.currentText() path = self.recent_paths[0] if basename in [path.relpath, path.value]: self.source = self.LOCAL_FILE return self.load_data() self.select_file(len(self.recent_paths) + 1) def select_file(self, n): if n < len(self.recent_paths): recent = self.recent_paths[n] del self.recent_paths[n] self.recent_paths.insert(0, recent) elif n: path = self.file_combo.currentText() if os.path.exists(path): self._add_path(path) else: self.info.setText('Data was not loaded:') self.warnings.setText("File {} does not exist".format(path)) self.file_combo.removeItem(n) self.file_combo.lineEdit().setText(path) return if len(self.recent_paths) > 0: self.source = self.LOCAL_FILE self.load_data() self.set_file_list() def _url_set(self): self.source = self.URL self.load_data() def browse_file(self, in_demos=False): if in_demos: try: start_file = get_sample_datasets_dir() except AttributeError: start_file = "" if not start_file or not os.path.exists(start_file): widgets_dir = os.path.dirname(gui.__file__) orange_dir = os.path.dirname(widgets_dir) start_file = os.path.join(orange_dir, "doc", "datasets") if not start_file or not os.path.exists(start_file): d = os.getcwd() if os.path.basename(d) == "canvas": d = os.path.dirname(d) start_file = os.path.join(os.path.dirname(d), "doc", "datasets") if not os.path.exists(start_file): QtGui.QMessageBox.information( None, "File", "Cannot find the directory with example data sets") return else: if self.recent_paths: start_file = self.recent_paths[0].abspath else: start_file = os.path.expanduser("~/") filename = QtGui.QFileDialog.getOpenFileName( self, 'Open Orange Data File', start_file, self.dlg_formats) if not filename: return self._add_path(filename) self.set_file_list() self.source = self.LOCAL_FILE self.load_data() def _add_path(self, filename): searchpaths = [("sample-datasets", get_sample_datasets_dir())] basedir = self.workflowEnv().get("basedir", None) if basedir is not None: searchpaths.append(("basedir", basedir)) recent = RecentPath.create(filename, searchpaths) if recent in self.recent_paths: self.recent_paths.remove(recent) self.recent_paths.insert(0, recent) # Open a file, create data from it and send it over the data channel def load_data(self): def load(method, fn): with catch_warnings(record=True) as warnings: data = method(fn) self.warning( 33, warnings[-1].message.args[0] if warnings else '') return data, fn def load_from_file(): fn = fn_original = self.recent_paths[0].abspath if fn == "(none)": return None, "" if not os.path.exists(fn): dir_name, basename = os.path.split(fn) if os.path.exists(os.path.join(".", basename)): fn = os.path.join(".", basename) self.information("Loading '{}' from the current directory." .format(basename)) try: return load(Table.from_file, fn) except Exception as exc: self.warnings.setText(str(exc)) ind = self.file_combo.currentIndex() self.file_combo.removeItem(ind) if ind < len(self.recent_paths) and \ self.recent_paths[ind].abspath == fn_original: del self.recent_paths[ind] raise def load_from_network(): def update_model(): try: self.completer_model.remove(url or self.url) except ValueError: pass self.completer_model.insert(0, url) self.url = url = self.le_url.text() if url: QtCore.QTimer.singleShot(0, update_model) if not url: return None, "" elif "://" not in url: url = "http://" + url try: return load(Table.from_url, url) except: self.warnings.setText( "URL '{}' does not contain valid data".format(url)) # Don't remove from recent_urls: # resource may reappear, or the user mistyped it # and would like to retrieve it from history and fix it. raise self.warning() self.information() try: self.data, self.loaded_file = \ [load_from_file, load_from_network][self.source]() except: self.info.setText("Data was not loaded:") self.data = None self.loaded_file = "" return else: self.warnings.setText("") data = self.data if data is None: self.send("Data", None) self.info.setText("No data loaded") return domain = data.domain text = "{} instance(s), {} feature(s), {} meta attribute(s)".format( len(data), len(domain.attributes), len(domain.metas)) if domain.has_continuous_class: text += "\nRegression; numerical class." elif domain.has_discrete_class: text += "\nClassification; discrete class with {} values.".format( len(domain.class_var.values)) elif data.domain.class_vars: text += "\nMulti-target; {} target variables.".format( len(data.domain.class_vars)) else: text += "\nData has no target variable." if 'Timestamp' in data.domain: # Google Forms uses this header to timestamp responses text += '\n\nFirst entry: {}\nLast entry: {}'.format( data[0, 'Timestamp'], data[-1, 'Timestamp']) self.info.setText(text) add_origin(data, self.loaded_file) self.send("Data", data) def get_widget_name_extension(self): _, name = os.path.split(self.loaded_file) return os.path.splitext(name)[0] def send_report(self): def get_ext_name(filename): try: return FileFormat.names[os.path.splitext(filename)[1]] except KeyError: return "unknown" if self.data is None: self.report_paragraph("File", "No file.") return if self.source == self.LOCAL_FILE: home = os.path.expanduser("~") if self.loaded_file.startswith(home): # os.path.join does not like ~ name = "~/" + \ self.loaded_file[len(home):].lstrip("/").lstrip("\\") else: name = self.loaded_file self.report_items("File", [("File name", name), ("Format", get_ext_name(name))]) else: self.report_items("Data", [("URL", self.url), ("Format", get_ext_name(self.url))]) self.report_data("Data", self.data) def workflowEnvChanged(self, key, value, oldvalue): if key == "basedir": self._relocate_recent_files() self.set_file_list()
def test_insert(self): model = PyListModel() model.insert(0, 1) self.assertSequenceEqual(model, [1]) self.assertEqual(len(model._other_data), 1) model._other_data = ["a"] model.insert(0, 2) self.assertSequenceEqual(model, [2, 1]) self.assertEqual(model._other_data[1], "a") self.assertNotEqual(model._other_data[0], "a") model._other_data[0] = "b" model.insert(1, 3) self.assertSequenceEqual(model, [2, 3, 1]) self.assertEqual(model._other_data[0], "b") self.assertEqual(model._other_data[2], "a") self.assertNotEqual(model._other_data[1], "b") self.assertNotEqual(model._other_data[1], "a") model._other_data[1] = "c" model.insert(3, 4) self.assertSequenceEqual(model, [2, 3, 1, 4]) self.assertSequenceEqual(model._other_data[:3], ["b", "c", "a"]) model._other_data[3] = "d" model.insert(-1, 5) self.assertSequenceEqual(model, [2, 3, 1, 5, 4]) self.assertSequenceEqual(model._other_data[:3], ["b", "c", "a"]) self.assertEqual(model._other_data[4], "d") self.assertEqual(len(model), len(model._other_data))
def test_pop(self): model = PyListModel([1, 2, 3, 2, 4]) model._other_data = list("abcde") model.pop(1) self.assertSequenceEqual(model, [1, 3, 2, 4]) self.assertSequenceEqual(model._other_data, "acde")
class OWWordList(OWWidget): name = "Word List" description = "Create a list of words." icon = "icons/WordList.svg" priority = 1000 class Inputs: words = Input("Words", Table) class Outputs: selected_words = Output("Selected Words", Table) words = Output("Words", Table) class Warning(OWWidget.Warning): no_string_vars = Msg("Input needs at least one Text variable.") NONE, CACHED, LIBRARY = range(3) # library list modification types want_main_area = False resizing_enabled = True settingsHandler = DomainContextHandler() word_list_library: List[Dict] = Setting([ { "name": WordList.generate_word_list_name([]), "words": [] }, ]) word_list_index: int = Setting(0) words_var: Optional[StringVariable] = ContextSetting(None) update_rule_index: int = Setting(UpdateRules.INTERSECT) words: List[str] = Setting(None, schema_only=True) selected_words: Set[str] = Setting(set(), schema_only=True) def __init__(self): super().__init__(self) flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable self.library_model = PyListModel([], self, flags=flags) self.words_model = PyListModel([], self, flags=flags, enable_dnd=True) self.library_view: QListView = None self.words_view: ListView = None self.__input_words_model = DomainModel(valid_types=(StringVariable, )) self.__input_words: Optional[Table] = None self.__library_box: QGroupBox = gui.vBox(None, "Library") self.__input_box: QGroupBox = gui.vBox(None, "Input") self.__words_box: QGroupBox = gui.vBox(None, box=True) self.__update_rule_rb: QRadioButton = None self.__add_word_action: QAction = None self.__remove_word_action: QAction = None self._setup_gui() self._restore_state() self.settingsAboutToBePacked.connect(self._save_state) def _setup_gui(self): layout = QGridLayout() gui.widgetBox(self.controlArea, orientation=layout) self._setup_library_box() self._setup_input_box() self._setup_words_box() layout.addWidget(self.__library_box, 0, 0) layout.addWidget(self.__input_box, 1, 0) layout.addWidget(self.__words_box, 0, 1, 0, 1) def _setup_library_box(self): self.library_view = QListView( editTriggers=QListView.DoubleClicked | QListView.EditKeyPressed, minimumWidth=200, sizePolicy=QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Expanding), ) self.library_view.setItemDelegate(WordListItemDelegate(self)) self.library_view.setModel(self.library_model) self.library_view.selectionModel().selectionChanged.connect( self.__on_library_selection_changed) self.__library_box.layout().setSpacing(1) self.__library_box.layout().addWidget(self.library_view) actions_widget = ModelActionsWidget() actions_widget.layout().setSpacing(1) action = QAction("+", self) action.setToolTip("Add a new word list to the library") action.triggered.connect(self.__on_add_word_list) actions_widget.addAction(action) action = QAction("\N{MINUS SIGN}", self) action.setToolTip("Remove word list from library") action.triggered.connect(self.__on_remove_word_list) actions_widget.addAction(action) action = QAction("Update", self) action.setToolTip("Save changes in the editor to library") action.setShortcut(QKeySequence(QKeySequence.Save)) action.triggered.connect(self.__on_update_word_list) actions_widget.addAction(action) gui.rubber(actions_widget.layout()) action = QAction("More", self, toolTip="More actions") new_from_file = QAction("Import Words from File", self) new_from_file.triggered.connect(self.__on_import_word_list) save_to_file = QAction("Save Words to File", self) save_to_file.setShortcut(QKeySequence(QKeySequence.SaveAs)) save_to_file.triggered.connect(self.__on_save_word_list) menu = QMenu(actions_widget) menu.addAction(new_from_file) menu.addAction(save_to_file) action.setMenu(menu) button = actions_widget.addAction(action) button.setPopupMode(QToolButton.InstantPopup) self.__library_box.layout().addWidget(actions_widget) def __on_library_selection_changed(self, selected: QItemSelection, *_): index = [i.row() for i in selected.indexes()] if index: current = index[0] word_list: WordList = self.library_model[current] self.word_list_index = current self.selected_words = set() self.words_model.wrap(list(word_list.cached_words)) self._apply_update_rule() def __on_add_word_list(self): taken = [l.name for l in self.library_model] name = WordList.generate_word_list_name(taken) word_list = WordList(name, self.words_model[:]) self.library_model.append(word_list) self._set_selected_word_list(len(self.library_model) - 1) def __on_remove_word_list(self): index = self._get_selected_word_list_index() if index is not None: del self.library_model[index] self._set_selected_word_list(max(index - 1, 0)) self._apply_update_rule() def __on_update_word_list(self): self._set_word_list_modified(mod_type=self.LIBRARY) def __on_import_word_list(self): filename, _ = QFileDialog.getOpenFileName( self, "Open Word List", os.path.expanduser("~/"), "Text files (*.txt)\nAll files(*.*)") if filename: name = os.path.basename(filename) with open(filename, encoding="utf-8") as f: words = [line.strip() for line in f.readlines()] self.library_model.append(WordList(name, words, filename=filename)) self._set_selected_word_list(len(self.library_model) - 1) self._apply_update_rule() def __on_save_word_list(self): index = self._get_selected_word_list_index() if index is not None: word_list = self.library_model[index] filename = word_list.filename else: filename = os.path.expanduser("~/") filename, _ = QFileDialog.getSaveFileName( self, "Save Word List", filename, "Text files (*.txt)\nAll files(*.*)") if filename: head, tail = os.path.splitext(filename) if not tail: filename = head + ".txt" with open(filename, "w", encoding="utf-8") as f: for word in self.words_model: f.write(f"{word}\n") def _setup_input_box(self): gui.comboBox(self.__input_box, self, "words_var", label="Word variable:", orientation=Qt.Vertical, model=self.__input_words_model, callback=self._apply_update_rule) gui.radioButtons(self.__input_box, self, "update_rule_index", UpdateRules.ITEMS, label="Update: ", orientation=Qt.Vertical, callback=self.__on_update_rule_changed) self.__input_box.setEnabled(False) def __on_update_rule_changed(self): self._enable_words_actions() self._apply_update_rule() def _setup_words_box(self): self.words_view = ListView() self.words_view.drop_finished.connect(self.__on_words_data_changed) self.words_view.setModel(self.words_model) self.words_view.selectionModel().selectionChanged.connect( self.__on_words_selection_changed) self.words_model.dataChanged.connect(self.__on_words_data_changed) self.__words_box.layout().setSpacing(1) self.__words_box.layout().addWidget(self.words_view) actions_widget = ModelActionsWidget() actions_widget.layout().setSpacing(1) action = QAction("+", self.words_view, toolTip="Add a new word") action.triggered.connect(self.__on_add_word) actions_widget.addAction(action) self.__add_word_action = action action = QAction("\N{MINUS SIGN}", self, toolTip="Remove word") action.triggered.connect(self.__on_remove_word) actions_widget.addAction(action) self.__remove_word_action = action gui.rubber(actions_widget) action = QAction("Sort", self) action.setToolTip("Sort words alphabetically") action.triggered.connect(self.__on_apply_sorting) actions_widget.addAction(action) self.__words_box.layout().addWidget(actions_widget) def __on_words_data_changed(self): self._set_word_list_modified(mod_type=self.CACHED) self.commit() def __on_words_selection_changed(self): self.commit() def __on_add_word(self): row = self.words_model.rowCount() if not self.words_model.insertRow(self.words_model.rowCount()): return with disconnected(self.words_view.selectionModel().selectionChanged, self.__on_words_selection_changed): self._set_selected_words([0]) index = self.words_model.index(row, 0) self.words_view.setCurrentIndex(index) self.words_model.setItemData(index, {Qt.EditRole: ""}) self.words_view.edit(index) def __on_remove_word(self): rows = self.words_view.selectionModel().selectedRows(0) if not rows: return indices = sorted([row.row() for row in rows], reverse=True) with disconnected(self.words_view.selectionModel().selectionChanged, self.__on_words_selection_changed): for index in indices: self.words_model.removeRow(index) if self.words_model: self._set_selected_words([max(0, indices[-1] - 1)]) self.__on_words_data_changed() def __on_apply_sorting(self): if not self.words_model: return words = self.words_model[:] mask = np.zeros(len(words), dtype=bool) selection = self._get_selected_words_indices() if selection: mask[selection] = True indices = np.argsort(words) self.words_model.wrap([words[i] for i in indices]) self._set_word_list_modified(mod_type=self.CACHED) if selection: self._set_selected_words(list(np.flatnonzero(mask[indices]))) else: self.commit() @Inputs.words def set_words(self, words: Optional[Table]): self.closeContext() self.__input_words = words self._check_input_words() self._init_controls() self.openContext(self.__input_words) self._apply_update_rule() def _check_input_words(self): self.Warning.no_string_vars.clear() if self.__input_words: metas = self.__input_words.domain.metas if not any(isinstance(m, StringVariable) for m in metas): self.Warning.no_string_vars() self.__input_words = None def _init_controls(self): words = self.__input_words domain = words.domain if words is not None else None self.__input_words_model.set_domain(domain) if len(self.__input_words_model) > 0: self.words_var = self.__input_words_model[0] self.__input_box.setEnabled(bool(self.__input_words_model)) self._enable_words_actions() def _enable_words_actions(self): if bool(self.__input_words_model) \ and self.update_rule_index != UpdateRules.LIBRARY: self.words_view.setEditTriggers(QListView.NoEditTriggers) self.__add_word_action.setEnabled(False) self.__remove_word_action.setEnabled(False) else: self.words_view.setEditTriggers(QListView.DoubleClicked | QListView.EditKeyPressed) self.__add_word_action.setEnabled(True) self.__remove_word_action.setEnabled(True) def _apply_update_rule(self): lib_index = self._get_selected_word_list_index() lib_words, in_words, update_rule = [], [], UpdateRules.LIBRARY if lib_index is not None: lib_words = self.library_model[lib_index].cached_words else: lib_words = self.words_model[:] if self.__input_words is not None: in_words = self.__input_words.get_column_view(self.words_var)[0] in_words = list(in_words) update_rule = self.update_rule_index UpdateRules.update(self.words_model, lib_words, in_words, update_rule) if lib_index is not None: cached = self.library_model[lib_index].cached_words modified = WordList.NotModified if cached == self.words_model[:] \ else WordList.Modified self.library_model[lib_index].update_rule_flag = modified self._set_word_list_modified(mod_type=self.NONE) self.library_view.repaint() # Apply selection. selection_changed invokes commit(). # If there is no selection, call commit explicitly. if any(w in self.selected_words for w in self.words_model): self.set_selected_words() self.words_view.repaint() else: self.commit() def commit(self): selection = self._get_selected_words_indices() self.selected_words = set(np.array(self.words_model)[selection]) words, selected_words = None, None if self.words_model: words_var = StringVariable("Words") words_var.attributes = {"type": "words"} domain = Domain([], metas=[words_var]) _words = Table.from_list(domain, [[w] for w in self.words_model]) _words.name = "Words" if selection: selected_words = _words[selection] words = create_annotated_table(_words, selection) self.Outputs.words.send(words) self.Outputs.selected_words.send(selected_words) def _set_word_list_modified(self, mod_type): index = self._get_selected_word_list_index() if index is not None: if mod_type == self.LIBRARY: self.library_model[index].words = self.words_model[:] self.library_model[index].cached_words = self.words_model[:] self.library_model[index].update_rule_flag \ = WordList.NotModified elif mod_type == self.CACHED: self.library_model[index].cached_words = self.words_model[:] elif mod_type == self.NONE: pass else: raise NotImplementedError self.library_model.emitDataChanged(index) self.library_view.repaint() def _set_selected_word_list(self, index: int): sel_model: QItemSelectionModel = self.library_view.selectionModel() sel_model.select(self.library_model.index(index, 0), QItemSelectionModel.ClearAndSelect) def _get_selected_word_list_index(self) -> Optional[int]: rows = self.library_view.selectionModel().selectedRows() return rows[0].row() if rows else None def _set_selected_words(self, indices: List[int]): selection = QItemSelection() sel_model: QItemSelectionModel = self.words_view.selectionModel() for i in indices: selection.append(QItemSelectionRange(self.words_model.index(i, 0))) sel_model.select(selection, QItemSelectionModel.ClearAndSelect) def _get_selected_words_indices(self) -> List[int]: rows = self.words_view.selectionModel().selectedRows() return [row.row() for row in rows] def set_selected_words(self): if self.selected_words: indices = [ i for i, w in enumerate(self.words_model) if w in self.selected_words ] self._set_selected_words(indices) def _restore_state(self): source = [WordList.from_dict(s) for s in self.word_list_library] self.library_model.wrap(source) # __on_library_selection_changed() (invoked by _set_selected_word_list) # clears self.selected_words selected_words = self.selected_words self._set_selected_word_list(self.word_list_index) if self.words is not None: self.words_model.wrap(list(self.words)) self._set_word_list_modified(mod_type=self.CACHED) if selected_words: self.selected_words = selected_words self.set_selected_words() elif len(self.word_list_library) > self.word_list_index and \ self.word_list_library[self.word_list_index] != self.words: self.commit() def _save_state(self): self.word_list_library = [s.as_dict() for s in self.library_model] self.words = self.words_model[:] def send_report(self): library = self.library_model[self.word_list_index].name \ if self.library_model else "/" settings = [("Library", library)] if self.__input_words: self.report_data("Input Words", self.__input_words) settings.append(("Word variable", self.words_var)) rule = UpdateRules.ITEMS[self.update_rule_index] settings.append(("Update", rule)) self.report_items("Settings", settings) self.report_paragraph("Words", ", ".join(self.words_model[:]))
def test_reverse(self): model = PyListModel([1, 2, 3, 4]) model._other_data = list("abcd") model.reverse() self.assertSequenceEqual(model, [4, 3, 2, 1]) self.assertSequenceEqual(model._other_data, "dcba")
def data(self, index, role=Qt.DisplayRole): if self._is_index_valid(index): img = self[index.row()] if role == Qt.DisplayRole: return img["name"] return PyListModel.data(self, index, role)