モブ沢工房

プログラミングとかLinux関連(特にOSSのグラフィックツール関連)とかレトロゲームとか3Dプリンタやら日曜大工等、色々。

pythonのpudbと日本語について

この記事はfc2から引っ越した記事です

pythonCUIなソースレベルのビジュアルなデバッガ、PuDB。
デスクトップだけでなくサーバでも使えて非常に便利なのですが、残念なことに何故か日本語(utf-8)の入ったソースコードを、ソースコードビューの桁数をはみ出して表示するだけで…たとえば要するにコメントなどの長い日本語の入った行が表示された瞬間に…Canvas.Errorとかいう例外で落ちるという状況でした。(@ubuntu 12.04に入ってる版)

相変わらず14.04に入ってる版でも治ってなかったので、思い切って調べました。

で、いろいろ調べて見た結果、urwidのunicode関連関数を呼んでないのでは?と考えてもみましたが間違いでした。

分析の結果、source_view.pyのSourceLineクラスで例外を発するのですが、このクラスを表示するラインごとに生成して色付けしているようですね。
そこで、utf-8なマルチバイト文字列がやってきて画面からはみ出すとき…
PuDBのSourceLineでは、はみ出た部分をカットするのに、
「表示可能な文字数(maxcol)までで文字列をスライスする」
という処理を行っています。そして、それをurwidに送っています。

このとき、単純に文字列をmaxcolまででスライスして処理を終えているのが問題で。
utf-8のマルチバイト文字は一文字で2文字分(多分)の表示領域を食っていることから、単純に端末で表示可能な「バイト単位の」文字数でカットしてしまうと、ユニコード文字列の「文字単位の」文字数とは当然合わないのですね。
文字数=バイト数な英語圏では問題にならないのでしょうけども…

そのため、urwidが文字数が合わない(はみ出た)として例外を発する、と…(;´Д`)

追ってみましたがSourceLineクラスの保持するself.textはしっかりとUnicodeでした。
urwid自体もunicodeには対応している模様…

shot_140426_124424_8426.jpg

エラー時はこんなかんじです



そんなわけで、ubuntu 14.04への移行を切っ掛けに、遂にハックな対策の実行を決意しました。
/usr/lib/python2.7/disg-packages/pudb/source_view.py
の86行目あたりの clipping - shipoutの間を改変し

# clipping ------------------------------------------------------------
if len(text) > maxcol:
text = text[:maxcol]
attr = rle_subseg(attr, 0, maxcol)
# shipout -------------------------------------------------------------


↑この部分を、↓こう

# clipping ------------------------------------------------------------
# unicode string length is NOT SAME as charactor counts within Terminal
# so convert it.
tlen=0
idx=0
for c in text:
tlen+=1
if ord(c) > 255:
tlen+=1

if tlen > maxcol:
text=text[:idx]
attr = rle_subseg(attr, 0, idx)
break
idx+=1
# shipout -------------------------------------------------------------



というかなりヤケクソなコードで無理矢理に入れてやったら、日本語を表示しても落ちなくなりました。

shot_140426_124521_3296.jpg

とりあえず、落ちない



ただ、ほんの実験みたいなもんですので、多少フォントが化けるのと、色分けは変ですが…
2文字なんて決め打ちしちゃっていいのか?という感じですが…(たぶんいけないと思います)とりあえずということで

もうちょっと追ってみますですといいたいところですが、このクイックなハックで満足してしまいそうなおいらでした…
っていうか、実はこれ以外の解決法を思いつけない(´・ω・`)

ターミナル上のキャラクタ画面で横に切るという発想が既に間違っているという気がしなくもないですが、何分素人ですので断言は避けます…やっぱこういうのは、winpdbみたいなwxwindowとか、それかGtkSourceViewとかで作ったほうが現実的でいいのかもですねぇ〜って、それだとコンソールで使えないか。

とはいえ、pythonの方針としては
「コメントはどんな下手糞でもいいから英語で書こう」 (=英語なら誰でも最低限意図を推測することは可能だが、日本語とか中国語とかで書かれるとそもそもまったく読めない人のほうが世界的には多い)
だし、ファイル埋め込みで日本語等のローカル言語を書くのも色々な意味で美しくないというか面倒な事を起こしやすいので、あまり必要ない修正とは言えます(´・ω・`)

pythonCUIなソースレベルのビジュアルなデバッガ、PuDB。
デスクトップだけでなくサーバでも使えて非常に便利なのですが、残念なことに何故か日本語(utf-8)の入ったソースコードを、ソースコードビューの桁数をはみ出して表示するだけで…たとえば要するにコメントなどの長い日本語の入った行が表示された瞬間に…Canvas.Errorとかいう例外で落ちるという状況でした。(@ubuntu 12.04に入ってる版)

相変わらず14.04に入ってる版でも治ってなかったので、思い切って調べました。

で、いろいろ調べて見た結果、urwidのunicode関連関数を呼んでないのでは?と考えてもみましたが間違いでした。

分析の結果、source_view.pyのSourceLineクラスで例外を発するのですが、このクラスを表示するラインごとに生成して色付けしているようですね。
そこで、utf-8なマルチバイト文字列がやってきて画面からはみ出すとき…
PuDBのSourceLineでは、はみ出た部分をカットするのに、
「表示可能な文字数(maxcol)までで文字列をスライスする」
という処理を行っています。そして、それをurwidに送っています。

このとき、単純に文字列をmaxcolまででスライスして処理を終えているのが問題で。
utf-8のマルチバイト文字は一文字で2文字分(多分)の表示領域を食っていることから、単純に端末で表示可能な「バイト単位の」文字数でカットしてしまうと、ユニコード文字列の「文字単位の」文字数とは当然合わないのですね。
文字数=バイト数な英語圏では問題にならないのでしょうけども…

そのため、urwidが文字数が合わない(はみ出た)として例外を発する、と…(;´Д`)

追ってみましたがSourceLineクラスの保持するself.textはしっかりとUnicodeでした。
urwid自体もunicodeには対応している模様…

shot_140426_124424_8426.jpg

エラー時はこんなかんじです



そんなわけで、ubuntu 14.04への移行を切っ掛けに、遂にハックな対策の実行を決意しました。
/usr/lib/python2.7/disg-packages/pudb/source_view.py
の86行目あたりの clipping - shipoutの間を改変し

# clipping ------------------------------------------------------------
if len(text) > maxcol:
text = text[:maxcol]
attr = rle_subseg(attr, 0, maxcol)
# shipout -------------------------------------------------------------


↑この部分を、↓こう

# clipping ------------------------------------------------------------
# unicode string length is NOT SAME as charactor counts within Terminal
# so convert it.
tlen=0
idx=0
for c in text:
tlen+=1
if ord(c) > 255:
tlen+=1

if tlen > maxcol:
text=text[:idx]
attr = rle_subseg(attr, 0, idx)
break
idx+=1
# shipout -------------------------------------------------------------



というかなりヤケクソなコードで無理矢理に入れてやったら、日本語を表示しても落ちなくなりました。

shot_140426_124521_3296.jpg

とりあえず、落ちない



ただ、ほんの実験みたいなもんですので、多少フォントが化けるのと、色分けは変ですが…
2文字なんて決め打ちしちゃっていいのか?という感じですが…(たぶんいけないと思います)とりあえずということで

もうちょっと追ってみますですといいたいところですが、このクイックなハックで満足してしまいそうなおいらでした…
っていうか、実はこれ以外の解決法を思いつけない(´・ω・`)

ターミナル上のキャラクタ画面で横に切るという発想が既に間違っているという気がしなくもないですが、何分素人ですので断言は避けます…やっぱこういうのは、winpdbみたいなwxwindowとか、それかGtkSourceViewとかで作ったほうが現実的でいいのかもですねぇ〜って、それだとコンソールで使えないか。

とはいえ、pythonの方針としては
「コメントはどんな下手糞でもいいから英語で書こう」 (=英語なら誰でも最低限意図を推測することは可能だが、日本語とか中国語とかで書かれるとそもそもまったく読めない人のほうが世界的には多い)
だし、ファイル埋め込みで日本語等のローカル言語を書くのも色々な意味で美しくないというか面倒な事を起こしやすいので、あまり必要ない修正とは言えます(´・ω・`)