Exemplo n.º 1
0
def test_dicts_natural_sorting_mixed_types():
    """
    Test that natural sorting actually does what it should do.
    testing for issue 13733, as mixed types were sorted incorrectly.

    Sorting for other columns will be tested as well.
    """
    import pandas as pd
    dictionary = {
        'DSeries': pd.Series(dtype=int),
        'aStr': 'algName',
        'kDict': {
            2: 'asd',
            3: 2
        }
    }

    # put this here variable, as it might change later to reflect string length
    str_size = get_size(dictionary['aStr'])

    editor = CollectionsEditor()
    editor.setup(dictionary)
    cm = editor.widget.editor.source_model
    cm.sort(0)
    keys = cm.keys
    types = cm.types
    sizes = cm.sizes

    assert keys == ['aStr', 'DSeries', 'kDict']
    assert types == ['str', 'Series', 'dict']
    assert sizes == [str_size, (0, ), 2]

    assert data_table(cm, 3, 3) == [['aStr', 'DSeries', 'kDict'],
                                    ['str', 'Series', 'dict'],
                                    [str_size, '(0,)', 2]]

    # insert an item and check that it is still sorted correctly
    editor.widget.editor.new_value('List', [1, 2, 3])
    assert data_table(cm, 4, 3) == [['aStr', 'DSeries', 'kDict', 'List'],
                                    ['str', 'Series', 'dict', 'list'],
                                    [str_size, '(0,)', 2, 3]]
    cm.sort(0)
    assert data_table(cm, 4, 3) == [['aStr', 'DSeries', 'kDict', 'List'],
                                    ['str', 'Series', 'dict', 'list'],
                                    [str_size, '(0,)', 2, 3]]

    # now sort for types
    cm.sort(1)
    assert data_table(cm, 4, 3) == [['DSeries', 'kDict', 'List', 'aStr'],
                                    ['Series', 'dict', 'list', 'str'],
                                    ['(0,)', 2, 3, str_size]]

    # now sort for sizes
    cm.sort(2)
    assert data_table(cm, 4, 3) == [['DSeries', 'kDict', 'List', 'aStr'],
                                    ['Series', 'dict', 'list', 'str'],
                                    ['(0,)', 2, 3, str_size]]
Exemplo n.º 2
0
 def show_syspath(self, syspath):
     """Show sys.path contents."""
     if syspath is not None:
         editor = CollectionsEditor(self)
         editor.setup(syspath, title="sys.path contents", readonly=True,
                      icon=ima.icon('syspath'))
         self.dialog_manager.show(editor)
     else:
         return
Exemplo n.º 3
0
def test_dicts_with_mixed_types_as_key(qtbot):
    """
    Test that we can show dictionaries with mixed data types as keys.

    This is a regression for spyder-ide/spyder#13481.
    """
    colors = {1: 'red', 'Y': 'yellow'}
    editor = CollectionsEditor()
    editor.setup(colors)
    assert editor.widget.editor.source_model.keys == [1, 'Y']
Exemplo n.º 4
0
def test_view_module_in_coledit():
    """
    Test that modules don't produce an error when opening in Variable Explorer.

    Also check that they are set as readonly. Regression test for
    spyder-ide/spyder#6080.
    """
    editor = CollectionsEditor()
    editor.setup(os, "module_test", readonly=False)
    assert editor.widget.editor.readonly
Exemplo n.º 5
0
def test_collectionseditor_with_class_having_buggy_copy(qtbot):
    """
    Test that editor for object whose .copy() returns a different type is
    readonly; cf. spyder-ide/spyder#6936.
    """
    class MyDictWithBuggyCopy(dict):
        pass

    md = MyDictWithBuggyCopy({1: 2})
    editor = CollectionsEditor()
    editor.setup(md)
    assert editor.widget.editor.readonly
Exemplo n.º 6
0
def test_pandas_dateoffset_view():
    """
    Test that pandas ``DateOffset`` objs can be viewied in CollectionsEditor.

    Regression test for spyder-ide/spyder#6729.
    """
    test_dateoffset = pandas.DateOffset()
    col_editor = CollectionsEditor(None)
    col_editor.setup(test_dateoffset)
    col_editor.show()
    assert col_editor.get_value()
    col_editor.accept()
Exemplo n.º 7
0
 def show_syspath(self):
     """
     Show `sys.path`.
     """
     editor = CollectionsEditor(parent=self)
     editor.setup(
         sys.path,
         title="sys.path",
         readonly=True,
         icon=self.create_icon('syspath'),
     )
     self.dialog_manager.show(editor)
Exemplo n.º 8
0
def test_edit_nonsettable_objects(qtbot, nonsettable_objects_data):
    """
    Test that errors trying to edit attributes in ColEdit are handled properly.

    Integration regression test for issues spyder-ide/spyder#6727 and
    spyder-ide/spyder#6728.
    """
    for test_obj, expected_obj, keys in nonsettable_objects_data:
        col_editor = CollectionsEditor(None)
        col_editor.setup(test_obj)
        col_editor.show()
        qtbot.waitForWindowShown(col_editor)
        view = col_editor.widget.editor
        indicies = [view.source_model.get_index_from_key(key) for key in keys]

        for _ in range(3):
            qtbot.keyClick(view, Qt.Key_Right)
        last_row = -1
        rows_to_test = [index.row() for index in indicies]
        for row in rows_to_test:
            for _ in range(row - last_row - 1):
                qtbot.keyClick(view, Qt.Key_Down)
            qtbot.keyClick(view, Qt.Key_Space)
            qtbot.keyClick(view.focusWidget(), Qt.Key_Backspace)
            qtbot.keyClicks(view.focusWidget(), "2")
            qtbot.keyClick(view.focusWidget(), Qt.Key_Down)
            last_row = row

        qtbot.wait(100)

        # Due to numpy's deliberate breakage of __eq__ comparison
        assert all([
            key == "_typ" or (getattr(col_editor.get_value(), key) == getattr(
                expected_obj, key)) for key in keys
        ])

        col_editor.accept()
        qtbot.wait(200)

        # Same reason as above
        assert all([
            key == "_typ" or (getattr(col_editor.get_value(), key) == getattr(
                expected_obj, key)) for key in keys
        ])

        if getattr(test_obj, "_typ", None) is None:
            keys.remove("_typ")

        assert all([
            getattr(test_obj, key) == getattr(expected_obj, key)
            for key in keys
        ])
Exemplo n.º 9
0
def test_collectionseditor_with_class_having_correct_copy(qtbot):
    """
    Test that editor for object whose .copy() returns the same type is not
    readonly; cf. spyder-ide/spyder#6936.
    """
    class MyDictWithCorrectCopy(dict):
        def copy(self):
            return MyDictWithCorrectCopy(self)

    md = MyDictWithCorrectCopy({1: 2})
    editor = CollectionsEditor()
    editor.setup(md)
    assert not editor.widget.editor.readonly
Exemplo n.º 10
0
def test_collectionseditor_when_clicking_on_header_and_large_rows(qtbot):
    """
    Test that sorting works when clicking in its header and there's a
    large number of rows.
    """
    li = [1] * 10000
    editor = CollectionsEditor()
    editor.setup(li)

    # Perform the sorting. It should be done quite quickly because
    # there's a very small number of rows in display.
    view = editor.widget.editor
    header = view.horizontalHeader()
    with qtbot.waitSignal(header.sectionClicked, timeout=200):
        qtbot.mouseClick(header.viewport(), Qt.LeftButton, pos=QPoint(1, 1))

    # Assert data was sorted correctly.
    assert data(view.model, 0, 0) == 9999
Exemplo n.º 11
0
def test_xml_dom_element_view():
    """
    Test that XML DOM ``Element``s are able to be viewied in CollectionsEditor.

    Regression test for spyder-ide/spyder#5642.
    """
    xml_path = path.join(LOCATION, 'dom_element_test.xml')
    with open(xml_path) as xml_file:
        xml_data = xml_file.read()

    xml_content = parseString(xml_data)
    xml_element = xml_content.getElementsByTagName("note")[0]

    col_editor = CollectionsEditor(None)
    col_editor.setup(xml_element)
    col_editor.show()
    assert col_editor.get_value()
    col_editor.accept()
Exemplo n.º 12
0
def test_dicts_natural_sorting(qtbot):
    """
    Test that natural sorting actually does what it should do
    """
    import random
    numbers = list(range(100))
    random.shuffle(numbers)
    dictionary = {'test{}'.format(i): None for i in numbers}
    data_sorted = sorted(list(dictionary.keys()), key=natsort)
    # numbers should be as a human would sort, e.g. test3 before test100
    # regular sort would sort test1, test10, test11,..., test2, test20,...
    expected = ['test{}'.format(i) for i in list(range(100))]
    editor = CollectionsEditor()
    editor.setup(dictionary)
    editor.widget.editor.source_model.sort(0)

    assert data_sorted == expected, 'Function failed'
    assert editor.widget.editor.source_model.keys == expected, \
        'GUI sorting fail'
Exemplo n.º 13
0
    def createEditor(self, parent, option, index, object_explorer=False):
        """Overriding method createEditor"""
        val_type = index.sibling(index.row(), 1).data()
        self.sig_open_editor.emit()
        if index.column() < 3:
            return None
        if self.show_warning(index):
            answer = QMessageBox.warning(
                self.parent(), _("Warning"),
                _("Opening this variable can be slow\n\n"
                  "Do you want to continue anyway?"),
                QMessageBox.Yes | QMessageBox.No)
            if answer == QMessageBox.No:
                return None
        try:
            value = self.get_value(index)
            if value is None:
                return None
        except ImportError as msg:
            self.sig_editor_shown.emit()
            module = str(msg).split("'")[1]
            if module in ['pandas', 'numpy']:
                if module == 'numpy':
                    val_type = 'array'
                else:
                    val_type = 'dataframe, series'
                QMessageBox.critical(
                    self.parent(), _("Error"),
                    _("Spyder is unable to show the {val_type} or object "
                      "you're trying to view because <tt>{module}</tt> was "
                      "not installed alongside Spyder. Please install "
                      "this package in your Spyder environment."
                      "<br>").format(val_type=val_type, module=module))
                return
            else:
                QMessageBox.critical(
                    self.parent(), _("Error"),
                    _("Spyder is unable to show the variable you're "
                      "trying to view because the module "
                      "<tt>{module}</tt> was not found in your  "
                      "Spyder environment. Please install "
                      "this package in your Spyder environment."
                      "<br>").format(module=module))
                return
        except Exception as msg:
            QMessageBox.critical(
                self.parent(), _("Error"),
                _("Spyder was unable to retrieve the value of "
                  "this variable from the console.<br><br>"
                  "The error message was:<br>"
                  "%s") % to_text_string(msg))
            return

        key = index.model().get_key(index)
        readonly = (isinstance(value, (tuple, set)) or self.parent().readonly
                    or not is_known_type(value))
        # CollectionsEditor for a list, tuple, dict, etc.
        if isinstance(value, (list, set, tuple, dict)) and not object_explorer:
            from spyder.widgets.collectionseditor import CollectionsEditor
            editor = CollectionsEditor(parent=parent)
            editor.setup(value,
                         key,
                         icon=self.parent().windowIcon(),
                         readonly=readonly)
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly))
            return None
        # ArrayEditor for a Numpy array
        elif (isinstance(value, (ndarray, MaskedArray))
              and ndarray is not FakeObject and not object_explorer):
            editor = ArrayEditor(parent=parent)
            if not editor.setup_and_check(value, title=key, readonly=readonly):
                return
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly))
            return None
        # ArrayEditor for an images
        elif (isinstance(value, Image) and ndarray is not FakeObject
              and Image is not FakeObject and not object_explorer):
            arr = array(value)
            editor = ArrayEditor(parent=parent)
            if not editor.setup_and_check(arr, title=key, readonly=readonly):
                return
            conv_func = lambda arr: Image.fromarray(arr, mode=value.mode)
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly,
                     conv=conv_func))
            return None
        # DataFrameEditor for a pandas dataframe, series or index
        elif (isinstance(value, (DataFrame, Index, Series))
              and DataFrame is not FakeObject and not object_explorer):
            editor = DataFrameEditor(parent=parent)
            if not editor.setup_and_check(value, title=key):
                return
            editor.dataModel.set_format(index.model().dataframe_format)
            editor.sig_option_changed.connect(self.change_option)
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly))
            return None
        # QDateEdit and QDateTimeEdit for a dates or datetime respectively
        elif isinstance(value, datetime.date) and not object_explorer:
            # Needed to handle NaT values
            # See spyder-ide/spyder#8329
            try:
                value.time()
            except ValueError:
                self.sig_editor_shown.emit()
                return None
            if readonly:
                self.sig_editor_shown.emit()
                return None
            else:
                if isinstance(value, datetime.datetime):
                    editor = QDateTimeEdit(value, parent=parent)
                else:
                    editor = QDateEdit(value, parent=parent)
                editor.setCalendarPopup(True)
                editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA))
                self.sig_editor_shown.emit()
                return editor
        # TextEditor for a long string
        elif is_text_string(value) and len(value) > 40 and not object_explorer:
            te = TextEditor(None, parent=parent)
            if te.setup_and_check(value):
                editor = TextEditor(value,
                                    key,
                                    readonly=readonly,
                                    parent=parent)
                self.create_dialog(
                    editor,
                    dict(model=index.model(),
                         editor=editor,
                         key=key,
                         readonly=readonly))
            return None
        # QLineEdit for an individual value (int, float, short string, etc)
        elif is_editable_type(value) and not object_explorer:
            if readonly:
                self.sig_editor_shown.emit()
                return None
            else:
                editor = QLineEdit(parent=parent)
                editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA))
                editor.setAlignment(Qt.AlignLeft)
                # This is making Spyder crash because the QLineEdit that it's
                # been modified is removed and a new one is created after
                # evaluation. So the object on which this method is trying to
                # act doesn't exist anymore.
                # editor.returnPressed.connect(self.commitAndCloseEditor)
                self.sig_editor_shown.emit()
                return editor
        # ObjectExplorer for an arbitrary Python object
        else:
            show_callable_attributes = index.model().show_callable_attributes
            show_special_attributes = index.model().show_special_attributes
            dataframe_format = index.model().dataframe_format

            if show_callable_attributes is None:
                show_callable_attributes = False
            if show_special_attributes is None:
                show_special_attributes = False

            from spyder.plugins.variableexplorer.widgets.objectexplorer \
                import ObjectExplorer
            editor = ObjectExplorer(
                value,
                name=key,
                parent=parent,
                show_callable_attributes=show_callable_attributes,
                show_special_attributes=show_special_attributes,
                dataframe_format=dataframe_format,
                readonly=readonly)
            editor.sig_option_changed.connect(self.change_option)
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly))
            return None
Exemplo n.º 14
0
    def createEditor(self, parent, option, index):
        """Overriding method createEditor"""
        if self.show_warning(index):
            answer = QMessageBox.warning(
                self.parent(), _("Warning"),
                _("Opening this variable can be slow\n\n"
                  "Do you want to continue anyway?"),
                QMessageBox.Yes | QMessageBox.No)
            if answer == QMessageBox.No:
                return None
        try:
            value = self.get_value(index)
            try:
                self.old_obj = value.copy()
            except AttributeError:
                self.old_obj = copy.deepcopy(value)
            if value is None:
                return None
        except Exception as msg:
            QMessageBox.critical(
                self.parent(), _("Error"),
                _("Spyder was unable to retrieve the value of "
                  "this variable from the console.<br><br>"
                  "The error message was:<br>"
                  "<i>%s</i>") % to_text_string(msg))
            return
        self.current_index = index

        key = index.model().get_key(index).obj_name
        readonly = (isinstance(value, (tuple, set)) or self.parent().readonly
                    or not is_known_type(value))

        # CollectionsEditor for a list, tuple, dict, etc.
        if isinstance(value, (list, set, tuple, dict)):
            from spyder.widgets.collectionseditor import CollectionsEditor
            editor = CollectionsEditor(parent=parent)
            editor.setup(value,
                         key,
                         icon=self.parent().windowIcon(),
                         readonly=readonly)
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly))
            return None
        # ArrayEditor for a Numpy array
        elif (isinstance(value, (ndarray, MaskedArray))
              and ndarray is not FakeObject):
            editor = ArrayEditor(parent=parent)
            if not editor.setup_and_check(value, title=key, readonly=readonly):
                return
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly))
            return None
        # ArrayEditor for an images
        elif (isinstance(value, Image) and ndarray is not FakeObject
              and Image is not FakeObject):
            arr = array(value)
            editor = ArrayEditor(parent=parent)
            if not editor.setup_and_check(arr, title=key, readonly=readonly):
                return
            conv_func = lambda arr: Image.fromarray(arr, mode=value.mode)
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly,
                     conv=conv_func))
            return None
        # DataFrameEditor for a pandas dataframe, series or index
        elif (isinstance(value, (DataFrame, Index, Series))
              and DataFrame is not FakeObject):
            editor = DataFrameEditor(parent=parent)
            if not editor.setup_and_check(value, title=key):
                return
            editor.dataModel.set_format(index.model().dataframe_format)
            editor.sig_option_changed.connect(self.change_option)
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly))
            return None
        # QDateEdit and QDateTimeEdit for a dates or datetime respectively
        elif isinstance(value, datetime.date):
            if readonly:
                return None
            else:
                if isinstance(value, datetime.datetime):
                    editor = QDateTimeEdit(value, parent=parent)
                else:
                    editor = QDateEdit(value, parent=parent)
                editor.setCalendarPopup(True)
                editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA))
                return editor
        # TextEditor for a long string
        elif is_text_string(value) and len(value) > 40:
            te = TextEditor(None, parent=parent)
            if te.setup_and_check(value):
                editor = TextEditor(value,
                                    key,
                                    readonly=readonly,
                                    parent=parent)
                self.create_dialog(
                    editor,
                    dict(model=index.model(),
                         editor=editor,
                         key=key,
                         readonly=readonly))
            return None
        # QLineEdit for an individual value (int, float, short string, etc)
        elif is_editable_type(value):
            if readonly:
                return None
            else:
                editor = QLineEdit(parent=parent)
                editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA))
                editor.setAlignment(Qt.AlignLeft)
                # This is making Spyder crash because the QLineEdit that it's
                # been modified is removed and a new one is created after
                # evaluation. So the object on which this method is trying to
                # act doesn't exist anymore.
                # editor.returnPressed.connect(self.commitAndCloseEditor)
                return editor
        # An arbitrary Python object.
        # Since we are already in the Object Explorer no editor is needed
        else:
            return None
Exemplo n.º 15
0
    def createEditor(self, parent, option, index, object_explorer=False):
        """Overriding method createEditor"""
        val_type = index.sibling(index.row(), 1).data()
        self.sig_editor_creation_started.emit()
        if index.column() < 3:
            return None
        if self.show_warning(index):
            answer = QMessageBox.warning(
                self.parent(), _("Warning"),
                _("Opening this variable can be slow\n\n"
                  "Do you want to continue anyway?"),
                QMessageBox.Yes | QMessageBox.No)
            if answer == QMessageBox.No:
                self.sig_editor_shown.emit()
                return None
        try:
            value = self.get_value(index)
            if value is None:
                return None
        except ImportError as msg:
            self.sig_editor_shown.emit()
            module = str(msg).split("'")[1]
            if module in ['pandas', 'numpy']:
                if module == 'numpy':
                    val_type = 'array'
                else:
                    val_type = 'dataframe, series'
                message = _("Spyder is unable to show the {val_type} or object"
                            " you're trying to view because <tt>{module}</tt>"
                            " is not installed. ")
                if running_in_mac_app():
                    message += _("Please consider using the full version of "
                                 "the Spyder MacOS application.<br>")
                else:
                    message += _("Please install this package in your Spyder "
                                 "environment.<br>")
                QMessageBox.critical(
                    self.parent(), _("Error"),
                    message.format(val_type=val_type, module=module))
                return
            else:
                if running_in_mac_app() or is_pynsist():
                    message = _("Spyder is unable to show the variable you're"
                                " trying to view because the module "
                                "<tt>{module}</tt> is not supported in the "
                                "Spyder Lite application.<br>")
                else:
                    message = _("Spyder is unable to show the variable you're"
                                " trying to view because the module "
                                "<tt>{module}</tt> is not found in your "
                                "Spyder environment. Please install this "
                                "package in this environment.<br>")
                QMessageBox.critical(self.parent(), _("Error"),
                                     message.format(module=module))
                return
        except Exception as msg:
            QMessageBox.critical(
                self.parent(), _("Error"),
                _("Spyder was unable to retrieve the value of "
                  "this variable from the console.<br><br>"
                  "The error message was:<br>"
                  "%s") % to_text_string(msg))
            return

        key = index.model().get_key(index)
        readonly = (isinstance(value, (tuple, set)) or self.parent().readonly
                    or not is_known_type(value))

        # We can't edit Numpy void objects because they could be anything, so
        # this might cause a crash.
        # Fixes spyder-ide/spyder#10603
        if isinstance(value, np.void):
            self.sig_editor_shown.emit()
            return None
        # CollectionsEditor for a list, tuple, dict, etc.
        elif isinstance(value, (list, set, tuple, dict)) and not object_explorer:
            from spyder.widgets.collectionseditor import CollectionsEditor
            editor = CollectionsEditor(parent=parent)
            editor.setup(value, key, icon=self.parent().windowIcon(),
                         readonly=readonly)
            self.create_dialog(editor, dict(model=index.model(), editor=editor,
                                            key=key, readonly=readonly))
            return None
        # ArrayEditor for a Numpy array
        elif (isinstance(value, (np.ndarray, np.ma.MaskedArray)) and
                np.ndarray is not FakeObject and not object_explorer):
            # We need to leave this import here for tests to pass.
            from .arrayeditor import ArrayEditor
            editor = ArrayEditor(parent=parent)
            if not editor.setup_and_check(value, title=key, readonly=readonly):
                return
            self.create_dialog(editor, dict(model=index.model(), editor=editor,
                                            key=key, readonly=readonly))
            return None
        # ArrayEditor for an images
        elif (isinstance(value, PIL.Image.Image) and
                np.ndarray is not FakeObject and
                PIL.Image is not FakeObject and
                not object_explorer):
            # Sometimes the ArrayEditor import above is not seen (don't know
            # why), so we need to reimport it here.
            # Fixes spyder-ide/spyder#16731
            from .arrayeditor import ArrayEditor
            arr = np.array(value)
            editor = ArrayEditor(parent=parent)
            if not editor.setup_and_check(arr, title=key, readonly=readonly):
                return
            conv_func = lambda arr: PIL.Image.fromarray(arr, mode=value.mode)
            self.create_dialog(editor, dict(model=index.model(), editor=editor,
                                            key=key, readonly=readonly,
                                            conv=conv_func))
            return None
        # DataFrameEditor for a pandas dataframe, series or index
        elif (isinstance(value, (pd.DataFrame, pd.Index, pd.Series))
                and pd.DataFrame is not FakeObject and not object_explorer):
            # We need to leave this import here for tests to pass.
            from .dataframeeditor import DataFrameEditor
            editor = DataFrameEditor(parent=parent)
            if not editor.setup_and_check(value, title=key):
                self.sig_editor_shown.emit()
                return
            self.create_dialog(editor, dict(model=index.model(), editor=editor,
                                            key=key, readonly=readonly))
            return None
        # QDateEdit and QDateTimeEdit for a dates or datetime respectively
        elif isinstance(value, datetime.date) and not object_explorer:
            if readonly:
                self.sig_editor_shown.emit()
                return None
            else:
                if isinstance(value, datetime.datetime):
                    editor = QDateTimeEdit(value, parent=parent)
                    # Needed to handle NaT values
                    # See spyder-ide/spyder#8329
                    try:
                        value.time()
                    except ValueError:
                        self.sig_editor_shown.emit()
                        return None
                else:
                    editor = QDateEdit(value, parent=parent)
                editor.setCalendarPopup(True)
                editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA))
                self.sig_editor_shown.emit()
                return editor
        # TextEditor for a long string
        elif is_text_string(value) and len(value) > 40 and not object_explorer:
            te = TextEditor(None, parent=parent)
            if te.setup_and_check(value):
                editor = TextEditor(value, key,
                                    readonly=readonly, parent=parent)
                self.create_dialog(editor, dict(model=index.model(),
                                                editor=editor, key=key,
                                                readonly=readonly))
            return None
        # QLineEdit for an individual value (int, float, short string, etc)
        elif is_editable_type(value) and not object_explorer:
            if readonly:
                self.sig_editor_shown.emit()
                return None
            else:
                editor = QLineEdit(parent=parent)
                editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA))
                editor.setAlignment(Qt.AlignLeft)
                # This is making Spyder crash because the QLineEdit that it's
                # been modified is removed and a new one is created after
                # evaluation. So the object on which this method is trying to
                # act doesn't exist anymore.
                # editor.returnPressed.connect(self.commitAndCloseEditor)
                self.sig_editor_shown.emit()
                return editor
        # ObjectExplorer for an arbitrary Python object
        else:
            from spyder.plugins.variableexplorer.widgets.objectexplorer \
                import ObjectExplorer
            editor = ObjectExplorer(
                value,
                name=key,
                parent=parent,
                readonly=readonly)
            self.create_dialog(editor, dict(model=index.model(),
                                            editor=editor,
                                            key=key, readonly=readonly))
            return None