Возникающая ошибка с не-BMP символами перезапускает оболочку - PullRequest
1 голос
/ 22 апреля 2019

Я пишу модуль на python, предназначенный для работы с отображением и вводом Emoji в pygame. Это означает, что я часто работаю с не-BMP символами Unicode, по-видимому, оболочка python не нравится.

Я сделал пользовательский объект в виде строки, чтобы упростить работу с символами и последовательностями смайликов, сохранив последовательности смайликов как один символ. Однако, хотя я бы хотел, чтобы str (self) возвращал исходное представление Unicode объекта, это вызывает проблемы при попытке распечатать или, что еще хуже, при включении в сообщение об ошибке.

Это пример того, что происходит, когда в сообщение об ошибке включен не-BMP символ. Запуск Python 3.7.3 в Windows 10.

>>> raise ValueError('Beware the non-BMP! \U0001f603')
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    raise ValueError('Beware the non-BMP! \U0001f603')
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    raise ValueError('Beware the non-BMP! \U0001f603')
Traceback (most recent call last):
  File "D:\Python37\lib\idlelib\run.py", line 474, in runcode
    exec(code, self.locals)
  File "<pyshell#0>", line 1, in <module>
Traceback (most recent call last):
  File "D:\Python37\lib\idlelib\run.py", line 474, in runcode
    exec(code, self.locals)
  File "<pyshell#0>", line 1, in <module>
ValueError: 

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\Python37\lib\idlelib\run.py", line 144, in main
    ret = method(*args, **kwargs)
  File "D:\Python37\lib\idlelib\run.py", line 486, in runcode
    print_exception()
  File "D:\Python37\lib\idlelib\run.py", line 234, in print_exception
    print_exc(typ, val, tb)
  File "D:\Python37\lib\idlelib\run.py", line 232, in print_exc
    print(line, end='', file=efile)
  File "D:\Python37\lib\idlelib\run.py", line 362, in write
    return self.shell.write(s, self.tags)
  File "D:\Python37\lib\idlelib\rpc.py", line 608, in __call__
    value = self.sockio.remotecall(self.oid, self.name, args, kwargs)
  File "D:\Python37\lib\idlelib\rpc.py", line 220, in remotecall
    return self.asyncreturn(seq)
  File "D:\Python37\lib\idlelib\rpc.py", line 251, in asyncreturn
    return self.decoderesponse(response)
  File "D:\Python37\lib\idlelib\rpc.py", line 271, in decoderesponse
    raise what
UnicodeEncodeError: 'UCS-2' codec can't encode characters in position 32-32: Non-BMP character not supported in Tk

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\Python37\lib\idlelib\run.py", line 158, in main
    print_exception()
  File "D:\Python37\lib\idlelib\run.py", line 234, in print_exception
    print_exc(typ, val, tb)
  File "D:\Python37\lib\idlelib\run.py", line 220, in print_exc
    print_exc(type(context), context, context.__traceback__)
  File "D:\Python37\lib\idlelib\run.py", line 232, in print_exc
    print(line, end='', file=efile)
  File "D:\Python37\lib\idlelib\run.py", line 362, in write
    return self.shell.write(s, self.tags)
  File "D:\Python37\lib\idlelib\rpc.py", line 608, in __call__
    value = self.sockio.remotecall(self.oid, self.name, args, kwargs)
  File "D:\Python37\lib\idlelib\rpc.py", line 220, in remotecall
    return self.asyncreturn(seq)
  File "D:\Python37\lib\idlelib\rpc.py", line 251, in asyncreturn
    return self.decoderesponse(response)
  File "D:\Python37\lib\idlelib\rpc.py", line 271, in decoderesponse
    raise what
UnicodeEncodeError: 'UCS-2' codec can't encode characters in position 32-32: Non-BMP character not supported in Tk

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "D:\Python37\lib\idlelib\run.py", line 162, in main
    traceback.print_exception(type, value, tb, file=sys.__stderr__)
  File "D:\Python37\lib\traceback.py", line 105, in print_exception
    print(line, file=file, end="")
  File "D:\Python37\lib\idlelib\run.py", line 362, in write
    return self.shell.write(s, self.tags)
  File "D:\Python37\lib\idlelib\rpc.py", line 608, in __call__
    value = self.sockio.remotecall(self.oid, self.name, args, kwargs)
  File "D:\Python37\lib\idlelib\rpc.py", line 220, in remotecall
    return self.asyncreturn(seq)
  File "D:\Python37\lib\idlelib\rpc.py", line 251, in asyncreturn
    return self.decoderesponse(response)
  File "D:\Python37\lib\idlelib\rpc.py", line 271, in decoderesponse
    raise what
UnicodeEncodeError: 'UCS-2' codec can't encode characters in position 32-32: Non-BMP character not supported in Tk

=============================== RESTART: Shell ===============================

Как вы можете видеть, похоже, что оболочка попадает в бесконечный цикл, пытаясь справиться с ошибкой, а затем перезапускает оболочку, чтобы предотвратить застревание. Есть ли способ, которым я мог бы а) заставить str работать иначе для обработчика ошибок или б) предотвратить перезапуск оболочки, чтобы ошибка отображалась правильно?

1 Ответ

1 голос
/ 22 апреля 2019

Взяв идеи из snakecharmerb и этих двух вопросов, я реализовал некоторый код, который проверяет, выполняется ли модуль в режиме IDLE и, если да, то ли функция выполняется вызывается обработчиком ошибок. Тесты работают нормально. У меня есть следующая проверка для работающей среды IDLE

IN_IDLE = False
for item in ['idlelib.__main__','idlelib.run','idlelib']:
    IN_IDLE = IN_IDLE or item in sys.modules

И ниже новая __str__ функция

    def __str__(self):
        """ Return str(self). """
        if IN_IDLE:
            # Check for caller. If string is being printed, modify
            # output to be IDLE-friendly (no non-BMP characters)
            callername = sys._getframe(1).f_code.co_name
            if callername == '_some_str':
                rstr = ''
                for char in self.__raw:
                    if ord(char) > 0xFFFF:
                        rstr += '\\U'+hex(ord(char))[2:].zfill(8)
                    else:
                        rstr += repr(char)[1:-1]
                return rstr
            else:
                return self.__raw
        else:
            return self.__raw

Где self.__raw содержит необработанное текстовое представление объекта. Я кеширую это, чтобы повысить эффективность, поскольку объекты предназначены для неизменности.

Конечно, хотя это и решает проблему, я чувствую, что python не должен делать полный перезапуск оболочки, когда это происходит. Будет публиковаться на bugs.python.org

РЕДАКТИРОВАТЬ: Опубликовано на bugs.python.org как выпуск 36698

...