Google app engineを使うにはデータストアの使い方が重要である、とよく言われている。
これは間違ってはいないけれど、でも必要以上に強調されすぎているきらいもある。
つまり、「データストアを理解していない=Google app engineでアプリが作れない」という等式が成り立っているのではないかということだ。
今回「作ればわかる!Google app engine」という本を書いた。後半の章のアプリはそれなりに本格的なものになっている。データ操作にはJDOを使っている。それでもクォーターはほとんどが上限に達していない。というか、ほぼ2〜3%だ。もちろんこれにはカラクリがあり、(残念ながら)アプリを見に来てくれる人がほとんどいないからだ。必要にもならないパフォーマンス改善テクニックよりも、チューニングが必要となるほどたくさんの人が集まるサイトを作るアイデアこそ、本当はGoogle app engineのキモだと思う。まあGoogle app engineに限らないことだけど。
なんだかとりとめなくなったけど、言いたいことは「Google app engineは敷居が低いから、アイデアを思いついたらとにかく作ってみようよ」っていうこと。
2011年5月8日日曜日
2010年3月31日水曜日
2010年3月29日月曜日
2010年3月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
仕方がないのでしばらくは、Launcherを使用せずにコマンドラインからGAEを起動するようにします。
$ /usr/local/bin/dev_appserver.py web2py
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
google.appengine.tools.dev_appserver.AppConfigNotFoundError
がでるのは、単純に実行したディレクトリが間違っていました。
上記のエラーは、web2pyディレクトリをカレントディレクトリとしていましたが、本当はweb2pyディレクトリの親ディレクトリで実行する必要があります。
しかし、さらなる罠が...
とりあえず現状をさらして、他力本願。
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
google.appengine.tools.dev_appserver.AppConfigNotFoundError
がでるのは、単純に実行したディレクトリが間違っていました。
上記のエラーは、web2pyディレクトリをカレントディレクトリとしていましたが、本当はweb2pyディレクトリの親ディレクトリで実行する必要があります。
しかし、さらなる罠が...
2010年3月1日月曜日
メール本文を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)
味も素っ気もない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)
2009年11月1日日曜日
捕捉仕切れなかった実行時例外をログに出力する
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('エラーが発生しました')
ここに、例外の情報を出力するロジックと、共通のエラー画面を表示するロジックを記述するとよい。
例外の情報は、traceback.format_exc()を使うと簡単だ。
# importは省略
class BaseRequestHandler(webapp.RequestHandler):
def handle_exception(self, exception, debug_mode):
logging.error(traceback.format_exc())
self.response.out.write('エラーが発生しました')
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
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
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になる事があるので注意しよう。
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になる事があるので注意しよう。
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 -----
��以下略)
理由半分くらい判明
開発サーバでlogin:adminで入れないのは、まあしょうがないみたい。
本番サーバでうまく行かなかったのは、app.yamlに次の設定を入れていなかったから。
inbound_services:
- mail
最初は入れていたんだけど、ソースを編集しているときに削除されてしまったみたい。
これがなくても開発サーバの管理コンソールからメールが送れてしまったのが、原因発見が遅れた原因。
無事googleさまからメールが届いて一安心。
これは便利だと早速試してみたけれども、なかなかうまく行かない。
ネットで調べてみても、「できるようになったらしいよ」と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 -----
��以下略)
理由半分くらい判明
開発サーバでlogin:adminで入れないのは、まあしょうがないみたい。
本番サーバでうまく行かなかったのは、app.yamlに次の設定を入れていなかったから。
inbound_services:
最初は入れていたんだけど、ソースを編集しているときに削除されてしまったみたい。
これがなくても開発サーバの管理コンソールからメールが送れてしまったのが、原因発見が遅れた原因。
無事googleさまからメールが届いて一安心。
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. (以下作成中)
GAEが1.2.6からメール受信機能を用意したので、smtp2webは使用しない事にした。
そのため、調査も終了〜。
1. smtp2webのインストール
smtp2webのソースコードは公開されているので、subversionを使ってチェックアウトする。
チェックアウトフォルダは、とりあえずログインしているユーザーの書類フォルダに展開。
2. smtp2webの起動
そのままだとsmtp2webは動かない。server/smtpserver.tacファイルの修正が必要。具体的には-uにroot、-gにdaemonを指定する。
runserver.shファイルがあるフォルダに移動して、sudoコマンドを使ってrunserver.shを起動する。
3. (以下作成中)
GAEが1.2.6からメール受信機能を用意したので、smtp2webは使用しない事にした。
そのため、調査も終了〜。
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
このサービスをローカルでも使うためには、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
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
このときは、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
2009年10月8日木曜日
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を生成できました。
1.2.7では動きました(^^)V
やっぱり駄目でした。具体的には、
1. ソースコードをlatin-1で保存して実行すると、実行できる。
2. ソースコードをutf-8で再保存して実行すると、上記のエラーが発生する
3. ソースコードをlatin-1にもどしても、やはりエラーが発生する
4. アプリケーションの.pycファイルを削除すると、実行できる(1.の状態に戻る)
です。
どうやら、pythonで鬼門のエンコード周りでどこかに不具合があるようです。
ちなみにサーバにデプロイするか、1.1.9にバージョンダウンするとうまく動くという事は、1.2.X系のGAEのSDKに問題がありそう...
しかしこのreportlab、ローカルのSDKではバージョンが1.2になると以下のエラーが発生する。
対応方法は、以下のURLから1.9をダウンロードしてアプリケーションに上書きすること。
「Google App Engine プロジェクト ホームページ」
http://code.google.com/p/googleappengine/downloads/list
※検索条件で「All donwloads」を選択する
ちなみに、本番環境ではSDKの環境に関係なくreportlabでPDFを生成できました。
1.2.7では動きました(^^)V
やっぱり駄目でした。具体的には、
1. ソースコードをlatin-1で保存して実行すると、実行できる。
2. ソースコードをutf-8で再保存して実行すると、上記のエラーが発生する
3. ソースコードをlatin-1にもどしても、やはりエラーが発生する
4. アプリケーションの.pycファイルを削除すると、実行できる(1.の状態に戻る)
です。
どうやら、pythonで鬼門のエンコード周りでどこかに不具合があるようです。
ちなみにサーバにデプロイするか、1.1.9にバージョンダウンするとうまく動くという事は、1.2.X系のGAEのSDKに問題がありそう...
2009年10月4日日曜日
静的ファイルを公開する
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
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
macのGAE Launcherでdebugログが出ない
Google App Engineのmac用環境で、ログ出力を実行してもdebugレベルのログが出力されない。
import logging
logging.info("これは出力される")
logging.debug("これは出力されない")
多分、サーバプロセス起動時にモードを変更する引数を渡せばよいのだと思うけど、macなのでそもそもコマンドラインの引数の渡し方がわかっていません。調査中です。
引数の渡し方がわかりました。
・Google App Engine Launcer上で、リストされているアプリケーションをダブルクリック
・"Extra flags"にフラグを追加
です。
参考URL:
http://blog.docuverse.com/2009/01/30/google-app-engine-launcher-options/
import logging
logging.info("これは出力される")
logging.debug("これは出力されない")
多分、サーバプロセス起動時にモードを変更する引数を渡せばよいのだと思うけど、macなのでそもそもコマンドラインの引数の渡し方がわかっていません。調査中です。
引数の渡し方がわかりました。
・Google App Engine Launcer上で、リストされているアプリケーションをダブルクリック
・"Extra flags"にフラグを追加
です。
参考URL:
http://blog.docuverse.com/2009/01/30/google-app-engine-launcher-options/
2009年10月3日土曜日
メールを送ろうとしてエラー
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
原因を検索中...
メールを送信するときのアドレスが、アプリケーションに登録されている必要がある。
登録する方法は、
1. http://appengine.google.com/ を開き、対象となるアプリケーションをクリックする
2. Administration - Developersを選択する
3. メールアドレスを登録する
こんな感じでいけそうです。
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
原因を検索中...
メールを送信するときのアドレスが、アプリケーションに登録されている必要がある。
登録する方法は、
1. http://appengine.google.com/ を開き、対象となるアプリケーションをクリックする
2. Administration - Developersを選択する
3. メールアドレスを登録する
こんな感じでいけそうです。
登録:
投稿 (Atom)