2010年3月31日水曜日

web2py & GAEによるデモ on youtube2

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

2010年3月29日月曜日

web2py & GAEによるデモ on youtube

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

2010年3月16日火曜日

40秒で作るweb2pyアプリ

■[Python]40秒で作るweb2pyアプリ
web2pyもRailsには負けていません。何せ後発ですから。
「何かメモするアプリ」ということで作ってみます。環境はこんな感じです。

$ python web2py
web2py Enterprise Web Framework
Created by Massimo Di Pierro, Copyright 2007-2010
Version 1.76.5 (2010-03-11 15:19:08)
Database drivers available: SQLite3
Starting hardcron...
というわけで、つくるよ!

アプリケーション作成
管理サイト上で、アプリケーションを作ります。


モデル生成

モデルはソースコード(db.py)で定義します。
db.define_table('note',
Field('body', 'text')
)

コントローラーの作成

データの入力と表示を行うコントローラーを作成します。
def index():
form = SQLFORM(db.note)
if form.accepts(request.vars):
redirect(URL(r=request))
notes = db().select(db.note.ALL)
return dict(form=form, notes=notes)

はい、これで完成。

ブラウザで確認
ブラウザで確認します。
http://localhost:8000/mynote/
出ました!



web2pyも簡単だよ。

2010年3月15日月曜日

WHR-G300Nで接続がよく切れる

バッファロー社のWHR-G300Nを使っていて接続がぶちぶち切れてしまう時は、無線設定のWPS機能をオフにすると調子が良くなるようです。危うく新しい無線ルーターを買ってしまうところだった。

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

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ディレクトリの親ディレクトリで実行する必要があります。
しかし、さらなる罠が...

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)