2009/02/18


先ほど試していたtw2ですが、少しやる気になってoutputzの設定もすませて動かしてみました。
ただ、中で使っているreadlineはimportした瞬間にbuilt-inのraw_input()を乗っ取ってしまい、かつ完全にマルチバイトに対応しきれていない様で、入力後の文字が化け化けになってしまいました。
おそらく、入力をutf-8で想定した作りになっているんだと思いますが、これはおそらく解決までに時間が掛かりそうな気がしています。
なのでpatchを書いてa2cさんにpull requestしました。
まれにutf-8しかない文字をtwitter/wassrに書き込んでくれる人がいるので、良いテストになりました。
raw_input()の変わりに、sys.stdin.readline()を使うようにしてあります。
diff --git a/tw2.py b/tw2.py
index fb04179..98fe90a 100755
--- a/tw2.py
+++ b/tw2.py
@@ -73,6 +73,9 @@ if __name__ == "__main__":
   friends = set()
   friendsTimeLine = []
 
+  def _T(text):
+    return text.encode('mbcs', 'ignore')
+
   def complete(text, status):
     results = [x for x in friends if x.startswith(text)] + [None]
     return results[status]
@@ -90,13 +93,13 @@ if __name__ == "__main__":
     # get twitter friends Replies
     print '\twassr replies\t'
     for data in reversed(wassr.getReplies()):
-      print '%-12s : %s' % (data['user_login_id'] ,data['text'])
+      print _T('%-12s : %s' % (data['user_login_id'] ,data['text']))
       friends.add(data['user_login_id'])
  
     # get twitter friends Replies        
     print '\n\twassr replies\t'
     for data in reversed(twitter.GetReplies()):
-      print '%-12s : %s' % (data.GetUser().GetScreenName() ,data.GetText())
+      print _T('%-12s : %s' % (data.GetUser().GetScreenName() ,data.GetText()))
       friends.add(data.GetUser().GetScreenName())
     return 0
 
@@ -105,7 +108,7 @@ if __name__ == "__main__":
     # Get FriendsTimeLine
     print ' -----  wassr Friends Time Line  -----'
     for data in reversed(wassr. getTimeline()):
-      print "%-12s: %s" % (data['user_login_id'] ,data['text'])
+      print _T("%-12s: %s" % (data['user_login_id'] ,data['text']))
       twit = "wr[]%-12s: %s" % (data['user_login_id'] ,data['text'])
       if twit in friendsTimeLine:
         pass
@@ -114,7 +117,7 @@ if __name__ == "__main__":
         friendsTimeLine.append(twit)
     print '\n  -----  twitter Friends Time Line  -----'
     for data in reversed(twitter.GetFriendsTimeline()):
-      print '%-12s : %s' % (data.GetUser().GetScreenName() ,data.GetText())
+      print _T('%-12s : %s' % (data.GetUser().GetScreenName() ,data.GetText()))
       # append log
       twit  = "tw[%s]%-12s: %s" % (data.GetCreatedAt(), data.GetUser().GetScreenName(), data.GetText())
       if twit in friendsTimeLine:
@@ -127,7 +130,8 @@ if __name__ == "__main__":
 
   prompt = '\n cmd: Friendstimeline[f] eXit[xx] \n> '
   while True:
-    input = raw_input(prompt).split(" ")
+    print prompt,
+    input = sys.stdin.readline().decode('mbcs').encode('utf-8').strip().split(" ")
     if input[0] != '':
       if len(input) == 1:
         if len(input[0]) > 2:
Macで動かなかったら御免なさい。
Posted at by




a2cさんが作ったtwitter client「tw2」を動かして見ようと思ったのですが、エラーも出るしpitが起動するエディタに何もテンプレートが出力されないのでコードを追ってみた。
調べた結果tw2ではなくpit側に原因がある事が分かった。
Bug #325139 in web.py: “web.profiler does not work on Windows”

tempfile.NamedTemporaryFile() to generate a temp file. On Windows the file cannot be opened a second time. Using tempfile.mkstemp() instead works but you lose the guaranteed cleanup of the temp file.

https://bugs.edge.launchpad.net/webpy/+bug/325139
どうやらNamedTemporaryFile()を使っていて、かつNamedTemporaryFile()はclose()時にファイルを削除してくれるのだけれど、内部でmkstempを使いfdを貰っているのにそのfdをclose()してくれていないものだからWindowsのハンドルが残りっぱなしになりwrite()もflush()もremove()出来ないと言う物だった。
Windowsでpit.pyを使ったプログラムを起動された事がある方は、一度テンポラリディレクトリの中を綺麗にした方が良いかもしれません。
    (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
    file = _os.fdopen(fd, mode, bufsize)
    return _TemporaryFileWrapper(file, name)
つまり import os, yaml, tempfile

t = tempfile.NamedTemporaryFile()
t.write("foo")
t.flush()
path = os.path.abspath(t.name)
result = open(path).read()
t.close()
print result
の様にclose()前だと、fdが開放されていないので"Permission Denited"、また import os, yaml, tempfile

t = tempfile.NamedTemporaryFile()
t.write("foo")
t.flush()
path = os.path.abspath(t.name)
t.close()
result = open(path).read()
print result
の様にclose()後だと、ファイルは消えてしまっているのでopen()出来ない...という事。なにそれ苦笑

上記リンクにある通り、NamedTemporaryFile()の変わりにmkstempを使い、かつremove()前にclose()してやれば動いた。
--- pit.py.orig 2008-06-28 16:58:42.000000000 +0900
+++ pit.py  2009-02-18 17:22:30.734375000 +0900
@@ -18,13 +18,21 @@
         else:
             if not os.environ.has_key('EDITOR'):
                 return {}
-            t = tempfile.NamedTemporaryFile()
             c = yaml.dump(opts['config'] if opts.has_key('config') else Pit.get(name) ,default_flow_style=False)
+
+            fd, path = tempfile.mkstemp()
+            os.close(fd)
+            t = open(path, "w+b")
             t.write(c)
             t.flush()
-            path = os.path.abspath(t.name)
+
             Popen([os.environ['EDITOR'],path]).communicate()
-            result = open(path).read()
+
+            t = open(path)
+            result = t.read()
+            t.close()
+            os.remove(path)
+
             if result == c:
                 print 'No Changes'
                 return profile[name]
@@ -44,7 +52,7 @@
         if opts.has_key('require'):
             flg = False
             keys = set(opts['require'].keys()) - set(ret.keys())
-            if keys:
+            if len(keys):
                 for key in keys:
                     ret[key] = opts['require'][key]
                 ret = Pit.set(name,{'config' : ret})
で、tw2については、outputzのIDがいるらしく面倒臭くなったのでヤメ。また今度試します。

ところでこのパッチ、NamedTemporaryFile()を修正するパッチにすべきか、はたまたpit.pyを修正してyoshioriさんに送ればよいのか...どうしましょうねぇ
Posted at by



2009/02/16


さらに朗報は続く
Google App Engine Blog: The sky's (almost) the limit! "High CPU" is no more.

We're very excited today to announce that we've raised limits on several App Engine operations:

  • No more "High CPU Requests"! App Engine Apps were once allowed no more than 2 CPU-intensive requests per minute. We've made some adjustments to the way we handle requests, and have eliminated this limitation altogether. To learn more about how this works and the implications for your app, see our documentation.
  • Response deadline raised to 30 seconds. The amount of time an App Engine app can take to respond to an incoming request has been raised from 10 to 30 seconds! There are limits on the number of simultaneous active requests an application can process at any given moment--see our docs to learn more.
  • Size limits on code files, static files, and requests/responses raised to 10MB! App Engine apps can now receive requests and send responses of up to 10MB in size, and users can upload 10MB code and static files as well. Note that API requests (e.g. memcache.set(), db.put()) are still limited to 1MB in size.
http://googleappengine.blogspot.com/2009/02/skys-almost-limit-high-cpu-is-no-more.html
Google App Engineに1分あたり2CPU以上負荷を掛ける様なリクエストが許される事になりました。
またレスポンスのデッドラインが10秒から30秒にまで引き上げられました。
さらにコード、静的ファイル、および要求/応答におけるサイズ制限が10MBに引き上げられました(但しmemcache.set()、db.put()はまだ1MBに制限されています)。

これで例えば、デカいクエリを投げる様な処理でもエラーで落ちるって事が少なくなるんじゃないですかね。
もうすぐすると、Google App Engineでタイマ発動処理をサポートするという噂もあるので、よりインタラクティブな処理が作れるんじゃないですかね。
Posted at by