2010年03月31日

web2py & GAEによるデモ on youtube2

前のブログの動画の続きです。
これらの動画は、Python & Ruby東海での発表内容を動画で再構築したものです。

  
タグ :web2py
Posted by 中垣健志 at 06:20Comments(529)TrackBack(0)GAE

2010年03月29日

web2py & GAEによるデモ on youtube

0からweb2pyを使ってGoogle App Engineのアプリを作る方法を作成しました。見てね。

  
タグ :web2py
Posted by 中垣健志 at 06:15Comments(897)TrackBack(0)GAE

2010年03月13日

GAE, Snow Leopard, python

ついさっき知りましたが、GAEはpython2.5が推奨環境です。しかーし、Mac OS X Snow Leopardはデフォルトがpython2.6となっています。そのためweb2pyのアプリを乗っけるとエラーが頻発します。しかもそれらがweb2pyのエラーチケットとしてフックされ、しかもそれを見るためのGAEが立ち上がらないという堂々巡り。

仕方がないのでしばらくは、Launcherを使用せずにコマンドラインからGAEを起動するようにします。
$ /usr/local/bin/dev_appserver.py web2py
  
タグ :web2py
Posted by 中垣健志 at 13:14Comments(515)TrackBack(0)GAE

2010年03月13日

GAEの開発環境にweb2pyをデプロイできない

web2pyで作ったアプリをGAEで作っているけど、うまく行っていない。
とりあえず現状をさらして、他力本願。

OS : Mac OS X 10.6
python : Version 2.5.x
web2py : Version 1.76.5
GAE : Version 1.3.1

$ /usr/local/bin/dev_appserver.py web2py
/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/appcfg.py:41: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
import sha
/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver_login.py:33: DeprecationWarning: the md5 module is deprecated; use hashlib instead
import md5
Traceback (most recent call last):
File "/usr/local/bin/dev_appserver.py", line 68, in
run_file(__file__, globals())
File "/usr/local/bin/dev_appserver.py", line 64, in run_file
execfile(script_path, globals_)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver_main.py", line 417, in
sys.exit(main(sys.argv))
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver_main.py", line 360, in main
config, matcher = dev_appserver.LoadAppConfig(root_path, {})
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver.py", line 3444, in LoadAppConfig
raise AppConfigNotFoundError
google.appengine.tools.dev_appserver.AppConfigNotFoundError
  続きを読む
タグ :web2py
Posted by 中垣健志 at 12:39Comments(1012)TrackBack(0)GAE

2010年03月01日

メール本文をPDFに変換するアプリ

Google App Engineでメール本文をPDFに変換するアプリを作成しました。
味も素っ気もないWebページはこちら。
http://nakakenstudy.appspot.com/
このページは本質的には全然関係なくて利用に当たっては、mail2pdf@nakakenstudy.appspotmail.comまでメールを送ってください。メールの本文がPDFとなって返信されます。
PDFの変換を試すには、http://nakakenstudy.appspot.com/post2pdf をリクエストしてください。

今回はreportlabを使ってテキストをPDFに変換しました。といってもベタにテキストにするだけなので、ほとんど実装していません。あんまり短くできたので、記念にソース公開しておきます。うるさい事言わないので、勝手にコピペしてください。blogの制約上全角スペースでインデントをつけているので、各自で半角スペースに変換しておいてください。

# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import logging
import StringIO

import pdf

from email.utils import parseaddr
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp.mail_handlers import *

SENDER_ADDRESS = 'nakaken@mediacat.ne.jp'

def main():
 application = webapp.WSGIApplication([
    (r'/', MainHandler),
    (r'/_ah/mail/.+', Mail2PdfHandler),
    (r'/post2pdf', Post2PdfHandler),
 ], debug=True)
 util.run_wsgi_app(application)

def goodDecode(encodedPayload):
 encoding = encodedPayload.encoding
 payload = encodedPayload.payload
 logging.debug(encoding)
 logging.debug(payload)
 if encoding and encoding.lower() != '7bit':
  payload = payload.decode(encoding)
 else:
  try:
   payload = payload.decode('ISO-2022-JP')
  except Exception, value:
   logging.warn(value)
 return payload

class MainHandler(webapp.RequestHandler):
 def get(self):
  self.response.out.write('Mail to "mail2pdf at nakakenstudy.appspotmail.com" and you can get pdf file converted from your mail.')
 
class Mail2PdfHandler(InboundMailHandler):
 def receive(self, message):
  logging.info('do Mail2PdfHandler.receive')
  
  editormail = parseaddr(message.to)[1]
  account = editormail.split('@')[0]
  if account != 'mail2pdf':
   logging.warn(account + ' is an undefined account.')
   return
  
  content = ''
  for body in message.bodies(content_type='text/plain'):
   content += goodDecode(body[1])
  logging.debug(content)
  
  buffer = StringIO.StringIO()
  pdf.go(buffer, content)
  pdffile = buffer.getvalue()
  buffer.close()
  
  logging.info('sender=' + SENDER_ADDRESS)
  logging.info('to=' + message.sender)
  mail.send_mail(
   sender=SENDER_ADDRESS,
   to=message.sender,
   subject='result of converted pdf from mail',
   body='Here is the pdf file you want, yeah!',
   attachments=[('content.pdf', pdffile)],
  )

class Post2PdfHandler(webapp.RequestHandler):
 def get(self):
  self.response.headers['Content-Type'] = 'text/html'
  self.response.out.write("""<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
 <form action="/post2pdf" method="post">
  <p>PDFに変換したい文字列を入力してください</p>
  <textarea cols="60" rows="30" name="content"></textarea><br />
  <input type="submit" value="変換" />
 </form>
</body>
</html>"""
)

 def post(self):
  content = self.request.get('content')
  buffer = self.response.out
  pdf.go(buffer, content)
  self.response.headers['Content-Type'] = 'application/pdf'
  
if __name__ == '__main__':
 main()

[[ pdf.py ]]
# -*- coding: utf-8 -*-
import cgi
import StringIO

from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase import pdfmetrics
from reportlab.platypus import SimpleDocTemplate, Spacer, XPreformatted
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.rl_config import defaultPageSize
from reportlab.lib.units import inch

pdfmetrics.registerFont(TTFont('Togoshi-mono', 'togoshi-mono.ttf'))

PAGE_HEIGHT=defaultPageSize[1]
PAGE_WIDTH=defaultPageSize[0]

styles = getSampleStyleSheet()
my_style = styles["Normal"]
my_style.name = "bonlife"
my_style.fontName = "Togoshi-mono"
my_style.fontSize = 0.15*inch
my_style.leading = 11

def go(filename, content):
  doc = SimpleDocTemplate(filename)
  Story = [Spacer(1, 0.5*inch)]
  style = my_style
  
  x = XPreformatted(cgi.escape(content), style)
  Story.append(x)
  
  doc.build(Story)
  
Posted by 中垣健志 at 22:43Comments(622)TrackBack(0)GAE

2009年11月01日

捕捉仕切れなかった実行時例外をログに出力する

RequestHandlerは、実行例外が処理されなかった時に、最後にexception_handlerメソッドを実行する。
ここに、例外の情報を出力するロジックと、共通のエラー画面を表示するロジックを記述するとよい。
例外の情報は、traceback.format_exc()を使うと簡単だ。

# importは省略

class BaseRequestHandler(webapp.RequestHandler):
def handle_exception(self, exception, debug_mode):
logging.error(traceback.format_exc())
self.response.out.write('エラーが発生しました')
  
Posted by 中垣健志 at 18:44Comments(1107)TrackBack(0)GAE

2009年10月27日

メールに添付されているファイルを取得する

ちょい苦労したけど、これで行けそう。

class MailHandler(InboundEmailHandler):
def receive(self, message):
attachment = message.attachments # ここ注意
binarydata = message.[1].payload.decode(message[1].encode)

でもこれは、添付ファイルが一つの場合のみ。
添付ファイルが一つの時は、message.attachmentsはtupleで(添付ファイル名, EncodePayloadオブジェクト)
となっている。
添付ファイルが二つの時は、message.attachmentsはlistで、[(添付ファイル名, EncodePayloadオブジェクト), (...)]となっている。
さらに添付ファイルがない時には、messageにattachmentsがそもそも存在しない。
それも踏まえて、場合分けをする必要があるようだ。

http://groups.google.com/group/google-appengine/browse_thread/thread/8bf0ab058eb3fcb3/dc447ee56ef59890?lnk=raot  
Posted by 中垣健志 at 21:43Comments(729)TrackBack(0)GAE

2009年10月25日

GAEで受信したメールの件名を取得する

これでいけるようだ。

class MailHandler(InboundEmailHandler):
def receive(self, message):
header = decode_header(message.subject)
subject = ''
for s, charset in header:
if charset:
subject += unicode(s, charset)
else:
subject += s

無条件でunicode(s, charset)とやってしまうと、件名が英語だけの時にcharsetがNoneになる事があるので注意しよう。  
Posted by 中垣健志 at 17:36Comments(597)TrackBack(0)GAE

2009年10月25日

Google App Engineでメール受信できた人いる?

Google App Engine 1.2.6からメールを受信する機能が追加された。
これは便利だと早速試してみたけれども、なかなかうまく行かない。
ネットで調べてみても、「できるようになったらしいよ」とGoogleやGIGAZINEのニュースを引く人はいるけれども、実際に受信したとかあるいはいろいろトラブったという話は、ヒットしない。Googleのサイトも英語は説明あるけど日本語の説明がないのもちと怪しい。

とにかく、今の事象を書いておくとする。だれか助けて。

[開発サーバでの話]
app.yamlに以下の設定をする。

- url: /_ah/mail/.+
script: main.py
login: admin

そして管理コンソールからメールを送ると、次のメッセージが出る。
Message send failure
Current logged in user is not authorized to view this page

まあ、(login:adminとしているので)そりゃそうなんだけど、じゃあどうしろと?


[本番サーバでの話]
駄目もとでデプロイして、regist@appid.appspotmail.com宛にメールを送ると、こんなつれない返事が返ってくる。
(ちなみにappidは、"http://appid.appspot.com/"のappidと合わせてあります)

This is an automatically generated Delivery Status Notification

Delivery to the following recipient failed permanently:

regist@appid.appspotmail.com

----- Original message -----
(以下略)

  続きを読む
Posted by 中垣健志 at 13:06Comments(807)TrackBack(0)GAE

2009年10月19日

smtp2webをMac OS X(10.5)で動かす

GAEではメールを受信するアプリを作るときには、smtp2webを使う必要があるけれども、いちいちサーバにデプロイしないとテストができない。非常に不便なので、何とかmac上でローカルにsmtp2webをサービスとして起動できないかどうか確認する。

1. smtp2webのインストール
smtp2webのソースコードは公開されているので、subversionを使ってチェックアウトする。
チェックアウトフォルダは、とりあえずログインしているユーザーの書類フォルダに展開。

2. smtp2webの起動
そのままだとsmtp2webは動かない。server/smtpserver.tacファイルの修正が必要。具体的には-uにroot、-gにdaemonを指定する。
runserver.shファイルがあるフォルダに移動して、sudoコマンドを使ってrunserver.shを起動する。

3. (以下作成中)  続きを読む
Posted by 中垣健志 at 22:24Comments(18)TrackBack(0)GAE

2009年10月12日

PILをMac OS 10.5 (Leopard)に入れる

Google App Engineでは、画像処理を行うためのサービスが提供されている。
このサービスをローカルでも使うためには、MacにPILをインストールする必要がある。
http://code.google.com/intl/ja/appengine/docs/python/images/overview.html#Development_Server

このPILをMac OS 10.5に入れるに大変だったので、備忘録として記述。

1. PILのインストール
dmgファイルをダウンロードしてインストールしようとすると、途中でインストーラーが「このディクスにはpythonが入っていない」という警告を出して、次に進めなくなる。これは、dmgの代わりにソースをダウンロードして、コマンドラインからインストールするのがよいようだ。

Finder -> アプリケーション -> ユーティリティ -> ターミナル
$cd (ダウンロードしたtar.gzファイルを展開したディレクトリ。"setup.py"ファイルがあるはず)
$sudo python setup.py install

2. JPEGデコーダーのインストール
PILをインストールしても、JPEG画像を操作しようとすると次のエラーが発生する事がある。
IOError: decoder jpeg not available
このときは、JPEGデコーダーを追加でインストールする。

http://www.ijg.org/
jpegsrc.v7.tar.gzファイルをダウンロードして、展開する
Finder -> アプリケーション -> ユーティリティ -> ターミナル
$cd (展開したディレクトリ。install.txtがあるはず)
./configure
make
make test
sudo make install

このあと、1.をもう一度行う。
そのとき1.のディレクトリにあるbuildディレクトリを削除しておく
sudo rm -fr build
  
Posted by 中垣健志 at 21:43Comments(14)TrackBack(0)GAE

2009年10月12日

djangoテンプレートで日本語が文字化けする

utf-8で保存された文字列をsjisで定義されたdjangoのテンプレートで表示すると、日本語が化けます。
このときは、djangoのカスタムフィルターを用意して、utf-8をsjisに変換します。

[customfilters.py (utf-8 -> sjis変換をするフィルターを定義する)]
from google.appengine.ext import webapp

register = webapp.template.create_template_register()

@register.filter
def sjis(value):
return value.encode('sjis')

[main.py (テンプレートを出力するロジックのあるモジュール)]
webapp.template.register_template_library('customfilters')

[template.html]
{{ myValue|sjis }}


参考
http://kaihatsu.mikagamikobo.com/2009/09/google-app-engine-1.html  
Posted by 中垣健志 at 12:19Comments(29)TrackBack(0)GAE

2009年10月08日

reportlabは1.2系では動かない

Google App EngineでPDFを出力するには、reportlabを使うとよいと書かれている。
しかしこのreportlab、ローカルのSDKではバージョンが1.2になると以下のエラーが発生する。

: 'HardenedModulesHook' object has no attribute '_files'

対応方法は、以下のURLから1.9をダウンロードしてアプリケーションに上書きすること。

「Google App Engine プロジェクト ホームページ」
http://code.google.com/p/googleappengine/downloads/list
※検索条件で「All donwloads」を選択する

ちなみに、本番環境ではSDKの環境に関係なくreportlabでPDFを生成できました。
  続きを読む
Posted by 中垣健志 at 21:06Comments(12)TrackBack(0)GAE

2009年10月04日

静的ファイルを公開する

Google App Engineで言語がpythonのときに、静的なファイルを公開する方法。

1. 公開したいファイルを用意する。このときURLとファイル名は異なっていてもよい。
2. app.yamlのhandlersに次のエントリを用意する
- url: 静的ファイルをリクエストするURL
static_files: 用意した静的ファイルのパス
upload: 用意した静的ファイルのパス

例:http://foo.bar.com/hoge.htmlを公開する。

/static/hogeimpl.htmlファイルを用意する
- url: /hoge.html
static_files: static/hogeimpl.html
upload: static/hogeimpl.html

smtp2webがらみで使えるネタです。
この内容は、用途は違いますがGAEの一般的な質問に載っていました。
http://code.google.com/intl/ja/appengine/kb/general.html#erroruris  
Posted by 中垣健志 at 14:24Comments(980)TrackBack(0)GAE

2009年10月04日

macのGAE Launcherでdebugログが出ない

Google App Engineのmac用環境で、ログ出力を実行してもdebugレベルのログが出力されない。

import logging

logging.info("これは出力される")
logging.debug("これは出力されない")

多分、サーバプロセス起動時にモードを変更する引数を渡せばよいのだと思うけど、macなのでそもそもコマンドラインの引数の渡し方がわかっていません。調査中です。  続きを読む
Posted by 中垣健志 at 14:07Comments(36)TrackBack(0)GAE

2009年10月03日

メールを送ろうとしてエラー

Google App Engineでメールを送ろうとしたら次のエラーが発生した

Traceback (most recent call last):
File "/base/python_lib/versions/1/google/appengine/ext/webapp/__init__.py", line 509, in __call__
handler.post(*groups)
File "/base/data/home/apps/golfpaper/1.336764943207147696/main.py", line 83, in post
, body
File "/base/python_lib/versions/1/google/appengine/api/mail.py", line 239, in send_mail
message.send(make_sync_call)
File "/base/python_lib/versions/1/google/appengine/api/mail.py", line 714, in send
raise ERROR_MAP[e.application_error](e.error_detail)
InvalidSenderError: Unauthorized sender

原因を検索中...  続きを読む
Posted by 中垣健志 at 14:25Comments(11)TrackBack(0)GAE