2007-10-11

Pythonの例外ではまる

呼出の親側で

try:
obj.call()
except:
pass

とやってて、呼び出されたobjのメソッドで次のようなコードを書いていた。


from ftplib import FTP

...

try:
ftp.storbinary()
except ftplib.error_perm:
pass

特定の状況でのエラーは無視できたので、例外をつかまえて無視したつもりだった。

だがしかし、上のコードはerror_permをキャッチできず呼出側のexcept句まで飛んでしまうのであった。なぜだろうか。

サブモジュールの行頭のimport句が重要。FTPしかimportしてないので、error_permをキャッチするコードのところで
TypeErrorが発生していたのだ。

でもって、呼出側の無指定exceptでキャッチされる、と。

教訓:面倒でも無指定exceptは使わないこと


しかし、プログラムミスも例外としてキャッチされてしまうとは予想しなかった。
予想もしないありとあらゆるものをキャッチするようだ。

2007-10-09

Widgetのパラメタを動的に変更したいんだが

on ToscaWidgets TurboGears



たとえばCheckBoxListのoptionsは生成時に固定ってことはむしろ少なくて、DBの内容にしたがって動的に変化するもんだと思う。

んが、Widgetの方針でどうも一度最初に生成しておくらしいのだ。困った。試行錯誤の結果、呼出可能オブジェクトを渡せば毎回評価されるってことが判明。


def get_opt():
import time
return [(time.ctime(), time.ctime(), [])]

class MyForm(TableForm):
class fields(WidgetsList):
box = CheckBoxList(options=get_opt)

form = MyForm(action="call")


上の例だと関数を渡してるけど、呼出可能ならなんでもいいらしい。

自分の希望としては、上の定義をさらにクラスの中でやりたいんだけど(つまりget_optのところをメソッドにしたい)、Pythonのスコープ規則を理解できてないのか、変数が未定義のエラーが出てしまって、まだ解決できず。

2007-10-08

SqlSoup: SQLAlchemyからSQLを発行する

SQLAlchemyからSQLを直接呼び出すもうちょっといいのではないかと思った方法:


from sqlalchemy.ext.sqlsoup import SqlSoup

db = SqlSoup(metadata)


上のコードをtg-admin shellの中で実行すればdbオブジェクトが手に入る。


r = db.bind.execute(text('select * from tg_user where user_name = :name'), name='dijohn')
r = r.fetchall()
print r


textはSQLAlchemyの関数。
変数展開を安全にやってくれるので使ったほうがいいと思う。(name=';'とかされてもOK)

r[0].user_nameとかすればRDBの行にアクセスできてしまう。
うむ。

SQLAlchemyからSQLを発行したい

フレームワークにTurboGearsを使っているんで、そこからどうすればいいのか?

とりあえず次のようにすれば、engineは取れた。


from turbogears.database import get_engine

e = get_engine()



これで得られるengineオブジェクトが、SQLAlchemyの解説にあるengineオブジェクトと同じものらしい。

あとは解説どおりメソッドを呼び出せば結果が得られる。

r = e.execute("SELECT * FROM tg_user")
r.fetchall()
print r[0]['user_name']

今はselectだけど、updateとかだとスレッド同期の扱いなんかはどうなるのかな?ふむむ。

2007-10-06

ToscaWidgetsでさらにはまり


class UserDataForm(TableForm):
class field(WidgetsList):
user_name = TextField(
...

てな感じで書き始めたが、input要素がいっこうに表示されない。

どこが間違っているかというと、
class field
の部分。fieldsと複数形にしなきゃならん。
いや、うっかりつーかなんつーか。

全然エラーメッセージが出ないから気付けんわこれは。

TurboGears+ToscaWidgets

これにはまりました。
最近のバージョンの問題か?

2007-09-27

Pythonでオンデマンド画像生成するには

どうすればいいのか。

PILのImage.tostringで'GIF'とかのエンコーディングを指定してもエラーになってしまう。GIF_encoderなどのメソッドがある事を期待しているが実際には定義されてないことが原因のようだ。なんか使い方間違ってるのか?

でもImage.saveでファイルへの保存はできるので結局こうした。


from cStringIO import StringIO
from PIL import Image, ImageDraw, ImageFont

from helloworld.lib.base import *

class HelloController(BaseController):

def test(self):
response.content_type = "image/gif"
im = Image.new("RGB", (40, 40))
font = ImageFont.load_default()
dr = ImageDraw.Draw(im)
dr.rectangle((0, 0, 40, 40), fill=(0, 0, 0))
dr.text((0, 0), 'Hello!!', fill=(255, 255, 255), font=font)
dr.text((0, 10), 'World?', fill=(200, 255, 255), font=font)
del dr
tmp = StringIO()
im.save(tmp, 'GIF')
return tmp.getvalue()



Image.saveの引数でファイル名のかわりにStringIOオブジェクトを渡せばメモリに書き込んでくれるので、あとはその文字列をreturnすればよい。
てか、Image.tostringというメソッドの名前からこういうことをやってくれると期待したんだけどな。