def test_create_dataframeeditor_with_correct_format(qtbot, monkeypatch): MockDataFrameEditor = Mock() mockDataFrameEditor_instance = MockDataFrameEditor() monkeypatch.setattr('spyder.widgets.variableexplorer.collectionseditor.DataFrameEditor', MockDataFrameEditor) df = pandas.DataFrame(['foo', 'bar']) editor = CollectionsEditorTableView(None, {'df': df}) qtbot.addWidget(editor) editor.set_dataframe_format('%10d') editor.delegate.createEditor(None, None, editor.model.createIndex(0, 3)) mockDataFrameEditor_instance.dataModel.set_format.assert_called_once_with('%10d')
def test_accept_sig_option_changed_from_dataframeeditor(qtbot, monkeypatch): df = pandas.DataFrame(['foo', 'bar']) editor = CollectionsEditorTableView(None, {'df': df}) qtbot.addWidget(editor) editor.set_dataframe_format('%10d') assert editor.model.dataframe_format == '%10d' editor.delegate.createEditor(None, None, editor.model.createIndex(0, 3)) dataframe_editor = next(iter(editor.delegate._editors.values()))['editor'] qtbot.addWidget(dataframe_editor) dataframe_editor.sig_option_changed.emit('dataframe_format', '%5f') assert editor.model.dataframe_format == '%5f'
def test_editor_parent_set(monkeypatch): """ Test that editors have their parent set so they close with Spyder. Regression test for issue #5696 . """ # Mocking and setup test_parent = QWidget() MockCollectionsEditor = Mock() attr_to_patch_coledit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.CollectionsEditor') monkeypatch.setattr(attr_to_patch_coledit, MockCollectionsEditor) MockArrayEditor = Mock() attr_to_patch_arredit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.ArrayEditor') monkeypatch.setattr(attr_to_patch_arredit, MockArrayEditor) MockDataFrameEditor = Mock() attr_to_patch_dfedit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.DataFrameEditor') monkeypatch.setattr(attr_to_patch_dfedit, MockDataFrameEditor) MockTextEditor = Mock() attr_to_patch_textedit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.TextEditor') monkeypatch.setattr(attr_to_patch_textedit, MockTextEditor) editor_data = [[0, 1, 2, 3, 4], numpy.array([1.0, 42.0, 1337.0]), pandas.DataFrame([[1, 2, 3], [20, 30, 40]]), "012345678901234567890123456789012345678901234567890123456", os] col_editor = CollectionsEditorTableView(test_parent, editor_data) assert col_editor.parent() is test_parent for idx, mock_class in enumerate([MockCollectionsEditor, MockArrayEditor, MockDataFrameEditor, MockTextEditor, MockCollectionsEditor]): col_editor.delegate.createEditor(col_editor.parent(), None, col_editor.model.createIndex(idx, 3)) assert mock_class.call_count == 1 + (idx // 3) assert mock_class.call_args[1]["parent"] is test_parent
def test_shows_dataframeeditor_when_editing_datetimeindex(qtbot, monkeypatch): MockDataFrameEditor = Mock() mockDataFrameEditor_instance = MockDataFrameEditor() monkeypatch.setattr('spyder.widgets.variableexplorer.collectionseditor.DataFrameEditor', MockDataFrameEditor) rng = pandas.date_range('10/1/2016', periods=25, freq='bq') coll = {'rng': rng} editor = CollectionsEditorTableView(None, coll) editor.delegate.createEditor(None, None, editor.model.createIndex(0, 3)) mockDataFrameEditor_instance.show.assert_called_once_with()
def test_shows_dataframeeditor_when_editing_index(qtbot, monkeypatch): for rng_name, rng in generate_pandas_indexes().items(): MockDataFrameEditor = Mock() mockDataFrameEditor_instance = MockDataFrameEditor() monkeypatch.setattr('spyder.widgets.variableexplorer.collectionseditor.DataFrameEditor', MockDataFrameEditor) coll = {'rng': rng} editor = CollectionsEditorTableView(None, coll) editor.delegate.createEditor(None, None, editor.model.createIndex(0, 3)) mockDataFrameEditor_instance.show.assert_called_once_with()
def test_rename_and_duplicate_item_in_collection_editor(): collections = {'list': ([1, 2, 3], False, True), 'tuple': ((1, 2, 3), False, False), 'dict': ({'a': 1, 'b': 2}, True, True)} for coll, rename_enabled, duplicate_enabled in collections.values(): coll_copy = copy.copy(coll) editor = CollectionsEditorTableView(None, coll) assert editor.rename_action.isEnabled() assert editor.duplicate_action.isEnabled() editor.setCurrentIndex(editor.model.createIndex(0, 0)) editor.refresh_menu() assert editor.rename_action.isEnabled() == rename_enabled assert editor.duplicate_action.isEnabled() == duplicate_enabled if isinstance(coll, list): editor.duplicate_item() assert editor.model.get_data() == coll_copy + [coll_copy[0]]
def test_edit_mutable_and_immutable_types(monkeypatch): """ Test that mutable objs/vals are editable in VarExp; immutable ones aren't. Regression test for issue #5991 . """ MockQLineEdit = Mock() attr_to_patch_qlineedit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.QLineEdit') monkeypatch.setattr(attr_to_patch_qlineedit, MockQLineEdit) MockTextEditor = Mock() attr_to_patch_textedit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.TextEditor') monkeypatch.setattr(attr_to_patch_textedit, MockTextEditor) MockQDateTimeEdit = Mock() attr_to_patch_qdatetimeedit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.QDateTimeEdit') monkeypatch.setattr(attr_to_patch_qdatetimeedit, MockQDateTimeEdit) MockCollectionsEditor = Mock() mockCollectionsEditor_instance = MockCollectionsEditor() attr_to_patch_coledit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.CollectionsEditor') monkeypatch.setattr(attr_to_patch_coledit, MockCollectionsEditor) list_test = [ 1, "012345678901234567901234567890123456789012", datetime.datetime(2017, 12, 24, 7, 9), [1, 2, 3], (2, "eggs") ] tup_test = tuple(list_test) # Tests for mutable type (list) # editor_list = CollectionsEditorTableView(None, list_test) # Directly editable values inside list editor_list_value = editor_list.delegate.createEditor( None, None, editor_list.model.createIndex(0, 3)) assert editor_list_value is not None assert MockQLineEdit.call_count == 1 # Text Editor for long text inside list editor_list.delegate.createEditor(None, None, editor_list.model.createIndex(1, 3)) assert MockTextEditor.call_count == 2 assert not MockTextEditor.call_args[1]["readonly"] # Datetime inside list editor_list_datetime = editor_list.delegate.createEditor( None, None, editor_list.model.createIndex(2, 3)) assert editor_list_datetime is not None assert MockQDateTimeEdit.call_count == 1 # List inside list editor_list.delegate.createEditor(None, None, editor_list.model.createIndex(3, 3)) assert mockCollectionsEditor_instance.show.call_count == 1 assert not mockCollectionsEditor_instance.setup.call_args[1]["readonly"] # Tuple inside list editor_list.delegate.createEditor(None, None, editor_list.model.createIndex(4, 3)) assert mockCollectionsEditor_instance.show.call_count == 2 assert mockCollectionsEditor_instance.setup.call_args[1]["readonly"] # Tests for immutable type (tuple) # editor_tup = CollectionsEditorTableView(None, tup_test) # Directly editable values inside tuple editor_tup_value = editor_tup.delegate.createEditor( None, None, editor_tup.model.createIndex(0, 3)) assert editor_tup_value is None assert MockQLineEdit.call_count == 1 # Text Editor for long text inside tuple editor_tup.delegate.createEditor(None, None, editor_tup.model.createIndex(1, 3)) assert MockTextEditor.call_count == 4 assert MockTextEditor.call_args[1]["readonly"] # Datetime inside tuple editor_tup_datetime = editor_tup.delegate.createEditor( None, None, editor_tup.model.createIndex(2, 3)) assert editor_tup_datetime is None assert MockQDateTimeEdit.call_count == 1 # List inside tuple editor_tup.delegate.createEditor(None, None, editor_tup.model.createIndex(3, 3)) assert mockCollectionsEditor_instance.show.call_count == 3 assert mockCollectionsEditor_instance.setup.call_args[1]["readonly"] # Tuple inside tuple editor_tup.delegate.createEditor(None, None, editor_tup.model.createIndex(4, 3)) assert mockCollectionsEditor_instance.show.call_count == 4 assert mockCollectionsEditor_instance.setup.call_args[1]["readonly"]
def test_edit_mutable_and_immutable_types(monkeypatch): """Check to ensure mutable types (lists, dicts) and individual values are editable, but not immutable ones (tuples) or anything inside of them, per #5991""" MockQLineEdit = Mock() attr_to_patch_qlineedit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.QLineEdit') monkeypatch.setattr(attr_to_patch_qlineedit, MockQLineEdit) MockTextEditor = Mock() attr_to_patch_textedit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.TextEditor') monkeypatch.setattr(attr_to_patch_textedit, MockTextEditor) MockQDateTimeEdit = Mock() attr_to_patch_qdatetimeedit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.QDateTimeEdit') monkeypatch.setattr(attr_to_patch_qdatetimeedit, MockQDateTimeEdit) MockCollectionsEditor = Mock() mockCollectionsEditor_instance = MockCollectionsEditor() attr_to_patch_coledit = ('spyder.widgets.variableexplorer.' + 'collectionseditor.CollectionsEditor') monkeypatch.setattr(attr_to_patch_coledit, MockCollectionsEditor) list_test = [ 1, "012345678901234567901234567890123456789012", datetime.datetime(2017, 12, 24, 7, 9), [1, 2, 3], (2, "eggs") ] tup_test = tuple(list_test) # Tests for mutable type (list) # editor_list = CollectionsEditorTableView(None, list_test) # Directly editable values inside list editor_list_value = editor_list.delegate.createEditor( None, None, editor_list.model.createIndex(0, 3)) assert editor_list_value is not None assert MockQLineEdit.call_count == 1 # Text Editor for long text inside list editor_list.delegate.createEditor(None, None, editor_list.model.createIndex(1, 3)) assert MockTextEditor.call_count == 2 MockTextEditor.assert_called_with(ANY, ANY, readonly=False) # Datetime inside list editor_list_datetime = editor_list.delegate.createEditor( None, None, editor_list.model.createIndex(2, 3)) assert editor_list_datetime is not None assert MockQDateTimeEdit.call_count == 1 # List inside list editor_list.delegate.createEditor(None, None, editor_list.model.createIndex(3, 3)) assert mockCollectionsEditor_instance.show.call_count == 1 mockCollectionsEditor_instance.setup.assert_called_with(ANY, ANY, icon=ANY, readonly=False) # Tuple inside list editor_list.delegate.createEditor(None, None, editor_list.model.createIndex(4, 3)) assert mockCollectionsEditor_instance.show.call_count == 2 mockCollectionsEditor_instance.setup.assert_called_with(ANY, ANY, icon=ANY, readonly=True) # Tests for immutable type (tuple) # editor_tup = CollectionsEditorTableView(None, tup_test) # Directly editable values inside tuple editor_tup_value = editor_tup.delegate.createEditor( None, None, editor_tup.model.createIndex(0, 3)) assert editor_tup_value is None assert MockQLineEdit.call_count == 1 # Text Editor for long text inside tuple editor_tup.delegate.createEditor(None, None, editor_tup.model.createIndex(1, 3)) assert MockTextEditor.call_count == 4 MockTextEditor.assert_called_with(ANY, ANY, readonly=True) # Datetime inside tuple editor_tup_datetime = editor_tup.delegate.createEditor( None, None, editor_tup.model.createIndex(2, 3)) assert editor_tup_datetime is None assert MockQDateTimeEdit.call_count == 1 # List inside tuple editor_tup.delegate.createEditor(None, None, editor_tup.model.createIndex(3, 3)) assert mockCollectionsEditor_instance.show.call_count == 3 mockCollectionsEditor_instance.setup.assert_called_with(ANY, ANY, icon=ANY, readonly=True) # Tuple inside tuple editor_tup.delegate.createEditor(None, None, editor_tup.model.createIndex(4, 3)) assert mockCollectionsEditor_instance.show.call_count == 4 mockCollectionsEditor_instance.setup.assert_called_with(ANY, ANY, icon=ANY, readonly=True)
def setup(self, check_all=None, exclude_private=None, exclude_uppercase=None, exclude_capitalized=None, exclude_unsupported=None, excluded_names=None, truncate=None, minmax=None, remote_editing=None, autorefresh=None): """Setup the namespace browser""" assert self.shellwidget is not None self.check_all = check_all self.exclude_private = exclude_private self.exclude_uppercase = exclude_uppercase self.exclude_capitalized = exclude_capitalized self.exclude_unsupported = exclude_unsupported self.excluded_names = excluded_names self.truncate = truncate self.minmax = minmax self.remote_editing = remote_editing self.autorefresh = autorefresh if self.editor is not None: self.editor.setup_menu(truncate, minmax) self.exclude_private_action.setChecked(exclude_private) self.exclude_uppercase_action.setChecked(exclude_uppercase) self.exclude_capitalized_action.setChecked(exclude_capitalized) self.exclude_unsupported_action.setChecked(exclude_unsupported) # Don't turn autorefresh on for IPython kernels # See Issue 1450 if not self.is_ipykernel: self.auto_refresh_button.setChecked(autorefresh) self.refresh_table() return # Dict editor: if self.is_internal_shell: self.editor = CollectionsEditorTableView(self, None, truncate=truncate, minmax=minmax) else: self.editor = RemoteCollectionsEditorTableView( self, None, truncate=truncate, minmax=minmax, remote_editing=remote_editing, get_value_func=self.get_value, set_value_func=self.set_value, new_value_func=self.set_value, remove_values_func=self.remove_values, copy_value_func=self.copy_value, is_list_func=self.is_list, get_len_func=self.get_len, is_array_func=self.is_array, is_image_func=self.is_image, is_dict_func=self.is_dict, is_data_frame_func=self.is_data_frame, is_series_func=self.is_series, get_array_shape_func=self.get_array_shape, get_array_ndim_func=self.get_array_ndim, oedit_func=self.oedit, plot_func=self.plot, imshow_func=self.imshow, show_image_func=self.show_image) self.editor.sig_option_changed.connect(self.sig_option_changed.emit) self.editor.sig_files_dropped.connect(self.import_data) # Setup layout layout = QVBoxLayout() blayout = QHBoxLayout() toolbar = self.setup_toolbar(exclude_private, exclude_uppercase, exclude_capitalized, exclude_unsupported, autorefresh) for widget in toolbar: blayout.addWidget(widget) # Options menu options_button = create_toolbutton(self, text=_('Options'), icon=ima.icon('tooloptions')) options_button.setPopupMode(QToolButton.InstantPopup) menu = QMenu(self) editor = self.editor actions = [ self.exclude_private_action, self.exclude_uppercase_action, self.exclude_capitalized_action, self.exclude_unsupported_action, None, editor.truncate_action ] if is_module_installed('numpy'): actions.append(editor.minmax_action) add_actions(menu, actions) options_button.setMenu(menu) blayout.addStretch() blayout.addWidget(options_button) layout.addLayout(blayout) layout.addWidget(self.editor) self.setLayout(layout) layout.setContentsMargins(0, 0, 0, 0) self.sig_option_changed.connect(self.option_changed)