我正在编写一个旨在在pygame中显示和输入表情符号的python模块。这意味着我经常使用非BMP Unicode字符,而python外壳显然不喜欢它。
我制作了一个自定义的类似字符串的对象,通过将表情符号序列存储为单个字符,使处理表情符号字符和序列更加容易。但是,尽管我想让str(self)返回对象的原始Unicode表示形式,但这会在尝试打印时甚至在错误消息中包含它时引起问题。
这是错误消息中包含非BMP字符时发生的情况的示例。在Windows 10上运行Python 3.7.3。
>>> 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 ===============================
如您所见,外壳似乎陷入无限循环以尝试处理错误,然后重新启动外壳以防止卡住。有什么办法我可以:a)使 str 在错误处理程序上的工作方式有所不同,或者b)阻止Shell重新启动以使错误正确显示?
答案 0 :(得分:1)
从snakecharmerb和these two问题出发,我已经实现了一些代码,该代码检查模块是否在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不应在发生这种情况时重新启动整个shell。将发布在bugs.python.org
编辑:以issue 36698的身份发布在bugs.python.org上