spyder-ide / spyder

Official repository for Spyder - The Scientific Python Development Environment
https://www.spyder-ide.org
MIT License
8.11k stars 1.57k forks source link

accent (non-unicode) characters not working in editor, python or ipython console #19696

Open Zincr0 opened 1 year ago

Zincr0 commented 1 year ago

Problem Description

dead keys like spanish letters cannot be typed (áéíóú).

What steps reproduce the problem?

  1. Install python 3.9 in an anaconda enviroment on ubuntu 20.04
  2. Install spyder 5.3.3 inside the anaconda enviroment, using conda install (default with PyQt5 5.15.7)
  3. Open Spyder, try to type any accented letter or "dead keys"

What is the expected output? What do you see instead?

Versions

Edited: "expected", "actual output" and steps.

bw-mutley commented 1 year ago

Also, the bitewise or ( ^ ) is not working.

ccordoba12 commented 1 year ago

Hey @Zincr0 and @bw-mutley, thanks for reporting. Unfortunately, I can't reproduce this error (I also use Linux, by the way):

accents

So, unless you're able to narrow down this problem and let us know of a specific way to reproduce it, I'm afraid I'll have to close it.

bw-mutley commented 1 year ago

hi there, @ccordoba12 , thanks for the reply. It is hard to go deeper on this, seens like a dependency problem or specific configuration of PyQt. By the way, spyder 4 works fine on my machine. The only thing I can tell you is that I followed the instructions to install spyder 5 it this bug happened. Could you please recommend any investigation procedure?

Zincr0 commented 1 year ago

ok i'm a not a pyqt user, but I managed to create this script that prints the key pressed in a a pyqt text input

import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QWidget, QLabel, QLineEdit
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtCore import QSize
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QEvent
from PyQt5.QtCore import Qt

keymap = {}
for key, value in vars(Qt).items():
    if isinstance(value, Qt.Key):
        keymap[value] = key.partition('_')[2]

modmap = {
    Qt.ControlModifier: keymap[Qt.Key_Control],
    Qt.AltModifier: keymap[Qt.Key_Alt],
    Qt.ShiftModifier: keymap[Qt.Key_Shift],
    Qt.MetaModifier: keymap[Qt.Key_Meta],
    Qt.GroupSwitchModifier: keymap[Qt.Key_AltGr],
    Qt.KeypadModifier: keymap[Qt.Key_NumLock],
    }

def keyevent_to_string(event):
    sequence = []
    for modifier, text in modmap.items():
        if event.modifiers() & modifier:
            sequence.append(text)
    key = keymap.get(event.key(), event.text())
    if key not in sequence:
        sequence.append(key)
    return '+'.join(sequence)

class EventTypes:
    def __init__(self):
        """Create mapping for all known event types."""
        self.string_name = {}
        for name in vars(QEvent):
            attribute = getattr(QEvent, name)
            if type(attribute) == QEvent.Type:
                self.string_name[attribute] = name

    def as_string(self, event: QEvent.Type) -> str:
        """Return the string name for this event."""
        try:
            return self.string_name[event]
        except KeyError:
            return f"UnknownEvent:{event}"

class textbox_keypress(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("bug test")
        self.mydesign()
        self.evtype = EventTypes()
    # ----------------------------------------------------------------------------------
    def mydesign(self):
        self.textbox = QLineEdit(self)
        self.textbox.setGeometry(10,10,300,30)
        self.textbox.installEventFilter(self)

    def eventFilter(self, source, event):
        eventName = self.evtype.as_string(event.type())
        if eventName not in ["Paint", "WindowActivate", "UpdateLater", "ShowToParent", "PolishRequest",
                             "Leave", "Polish", "Move", "Resize", "Show", "InputMethodQuery", "InputMethodQuery",
                             "MetaCall", "WindowDeactivate", "Enter", "ToolTip", "Hide"]:
            if "Focus" not in eventName and "Mouse" not in eventName and "Hover" not in eventName:
                print(eventName)

        if event.type() in [QEvent.KeyPress, QEvent.KeyRelease] and source is self.textbox:
            #print(event)
            #print(event.key())
            #print(event.modifiers())
            print(keyevent_to_string(event))
            print("***********************************************")
        return super(textbox_keypress, self).eventFilter(source,event)

    # ----------------------------------------------------------------------------------
def main():
    myapp = QApplication(sys.argv)
    mywindow = textbox_keypress()
    mywindow.show()
    sys.exit(myapp.exec_())
if __name__ =="__main__":
    main()

the anaconda pyqt version when trying to type the backtick character ` goes like this:

***********************************************
ShortcutOverride
KeyPress
Dead_Acute
***********************************************
KeyRelease
Dead_Acute
***********************************************

and the anaconda python shows nothing on the text input widget.

the system python3 on the other side

***********************************************
KeyRelease
Dead_Acute
***********************************************
InputMethod
KeyRelease
Dead_Acute
***********************************************

Note that there's no KeyPress, no ShortcutOverride and an extra InputMethod appeared, and the system python shows the backtick just fine on the text input widget.

What does this means? no idea. But it shows that the problem is definitely on the pyqt side.

Zincr0 commented 1 year ago

Found a workaround:

strace will show that the anaconda's pyqt is looking for locale files in the wrong path (the anaconda enviroment)

openat(AT_FDCWD, "/disk2/mambaforge/envs/py309/share/X11/locale/locale.alias", O_RDONLY) = -1 ENOENT (No such file or directory)

and \<env>/share/X11/locale indeed does not exists.

so if we create the parent folder and link the locale system here

mkdir -p /disk2/mambaforge/envs/py309/share/X11
ln -s /usr/share/X11/locale /disk2/mambaforge/envs/py309/share/X11/locale

it will now work.

bw-mutley commented 1 year ago

Thanks for the fix, @Zincr0 .

frankmdv commented 1 year ago

Hey, I was looking all over for a solution and I found it, thank you very much @Zincr0.

Here is the solution for users who use ArchLinux:

sudo mkdir -p /opt/anaconda/share/X11 sudo ln -s /usr/share/X11/locale /opt/anaconda/share/X11/locale

b-e-n-j-a-m commented 5 months ago

I ran into the same issue. After spending some time with the workaround mentioned here, I went back to the original installation docs https://docs.spyder-ide.org/current/installation.html#conda-environment and installed the version provided through the conda-forge channel. No issues there.