python

2012年09月05日

OSXにpythonは入っているが、pipがちゃんと動かない。
homebrewを使って、改めて入れ直すことにする。
OS標準では、/usr/bin/pythonであるが、homebrewは/usr/local/binに入れてくれるので、後でpathを登録する必要がある。

1.HOMEBREWのインストール

 $ruby <(curl -fsSk https://raw.github.com/mxcl/homebrew/go)

インストール後の自己診断

 $ brew doctor
Warning: You have Macports or Fink installed.
This can cause trouble. You don't have to uninstall them, but you may like to
try temporarily moving them away, eg.

  sudo mv /opt/local ~/macports 

macportsが入っているから、消せといわれる。
ま、ディレクトリ名を変えておけばいいだろう。

 $ brew doctor
Your system is raring to brew.  

ちゃんと通った。

2.pythonのインストール

早速インストールをする。

 $ brew install python
Unsatisfied dependency: XQuartz 
Please install the latest version of XQuartz:
  https://xquartz.macosforge.org
Error: An unsatisfied requirement failed this build.  

XQuartzがないと怒られる。
pythonでX11がいるとは、驚きだがしかたない。以下からダウンロードして入れる。

3.XQuartzのインストール

以下らからISOをダウンロードして、インストーラを起動。

http://xquartz.macosforge.org/landing/

4.pipの修正

再度pythonのインストールをトライ。

 $ brew install python 

またエラーが出た。

 ==> Downloading http://pypi.python.org/packages/source/p/pip/pip-1.1.tar.gz
Already downloaded: /Library/Caches/Homebrew/pip-1.1.tar.gz
config.log was copied to /Users/terauchiyasuyuki/Library/Logs/Homebrew
Error: SHA1 mismatch
Expected: 842c4e2aff3f016feea3c6e992c7fa96e49c9aa0
Actual: 3b002db66890880ee776bbe199c3d326d8fe3d6f
Archive: /Library/Caches/Homebrew/pip-1.1.tar.gz
(To retry an incomplete download, remove the file above.) 

pipをダウンロードしたtar.gzが違うという。
いろいろ試行錯誤をしたが、結局、homebrewに登録されているハッシュ値が間違っているという結論。
以下のコマンドで、ハッシュ値を修正する。

 $ brew edit python 

変更前の23行めから26行め。

 23 class Pip < Formula
 24   url 'http://pypi.python.org/packages/source/p/pip/pip-1.1.tar.gz'
 25   sha1 '842c4e2aff3f016feea3c6e992c7fa96e49c9aa0'
 26 end 

以下のように変更。

 23 class Pip < Formula
 24   url 'http://pypi.python.org/packages/source/p/pip/pip-1.1.tar.gz'
 25   sha1 '3b002db66890880ee776bbe199c3d326d8fe3d6f'
 26 end 

5.最後、ほんとのpythonインストール

これで再度 $ brew install pythonをすると無事終了した。
PATHを/usr/local/binを優先させて。 

 $ which python
/usr/local/bin/python

$ python --version
Python 2.7.3 


sylphide_ffr31mr at 23:55コメント(0)トラックバック(0) 

2011年02月17日

google app engine上でEvernote連携のwebサービスを作るには、OAuthでの認証が必要になる。
このエントリーでは、OAuthをGoogle AppEngine上でpythonを使って認証するサンプルプログラムcunsumer_oauth.pyを提供する。
OAuthの直接的な部分は、google codeで提供されているoauth.pyを使い、それの呼び出し方を記述しているのが、consumer_oauth.pyである。
このプログラムは、oauth.pyのライブラリの使い方の参考とすることを目的としているので、元のoauth.pyライブラリに則り、MITライセンスとする。

oauth.pyを使ったサンプルプログラムは、webで調べるとtwitter向きのものが多い。
しかし、Evernoteをproviderとしたとき、同じOAuthでも、twitterとevernoteではパラメータの扱いが若干違うため、そのままは使えない。 そのあたりを修正して、ここにあげておく。

1. OAuthの仕組み

まずは、OAuthの基本的な動きを理解する。

2.ライブラリの入手

google codeでは、pythonのOAuthライブラリが ここ で公開されている。

oauth.pyを入手

ここでは、exampleとしてoauth.pyを使った client.py というのもあるのだが、これがどうもわかりづらい。
いろいろ探っているうちに、わかりやすいexampleをみつけた。

GAE+OAuth

このexampleは、いろいろミスがあり、動かすためにはかなりの修正が必要となるが、oauth.pyの使い方はとても参考になった。おかげで、oauth.pyを使えたといっても過言ではない。

3.EvernoteからAPI keyの取得

実際に、以下のプログラムを動かすには、Evernoteからconsumer用API keyを入手しなくてはならない。

以下のフォームからEvernoteにAPI keyを申請する。

https://www.evernote.com/about/developer/api/

application typeは"web application"とすること。
1,2日でメールで届くはずである。

4.Evernote OAuthの特徴

Twitterなど、あちこちで公開されているOAuthの使用例と比べて、Evernoteでは、以下の2点を注意する必要がある。

  1. twitter OAuthなどでは、request tokenからaccess tokenに交換するために、承諾されたoauth_okenを送るが、evernoteの場合は、同時にverifierも送らないといけない。
    verifierは、エンドユーザが承諾ボタンを押した後のcallback urlで戻ってくるhttp getリクエストの中に、パラーメータとして格納されている。

  2. 承諾画面より後はevernoteではoauth_secretを使わないので、url encodeされたパラメータ部分で&oauth_secret=&、と値部分がnullになるリクエストが一度だけくる。

1.については、verifierパラメータを抜き出して、リクエストURLを生成時する関数にパラメータを渡すことで対処できる。oauth.pyのライブラリは、verifierをリクエストに加える機能を持っている。

2.については、secretパラメータがnullになるとoauth.pyの中でエラーとなる。ouath.pyの以下の行でエラーを補足し、secretにダミーの文字列をセットすることで対処する。

5.oauth.py変更箇所

137行目から

(変更前)
    def from_string(s):
        """ Returns a token from something like:
        oauth_token_secret=xxx&oauth_token=xxx
        """
        params = cgi.parse_qs(s, keep_blank_values=False)
        key = params['oauth_token'][0]
        secret = params['oauth_token_secret'][0]
        token = OAuthToken(key, secret)
        try:
            token.callback_confirmed = params['oauth_callback_confirmed'][0]
        except KeyError:
            pass # 1.0, no callback confirmed.
        return token

(変更後)
    def from_string(s):
        """ Returns a token from something like:
        oauth_token_secret=xxx&oauth_token=xxx
        """
        params = cgi.parse_qs(s, keep_blank_values=False)
        key = params['oauth_token'][0]
        try:
            secret = params['oauth_token_secret'][0]
        except KeyError:
            secret = "dummy"
        token = OAuthToken(key, secret)
        try:
            token.callback_confirmed = params['oauth_callback_confirmed'][0]
        except KeyError:
            pass # 1.0, no callback confirmed.
        return token

6.Access Tokenの保存

consumer webサービスを使うたびに、毎回evernoteで承諾をするのが面倒なので、承諾済みであることをどこかに記録しておきたい。

クッキーを使ってブラウザに保存する方法と、consumerサーバ上に保存する方法がある。
今回作成したconsumer_oauth.pyでは、google app engineのデータストアに保存することにする。 そのため、consumerサービスを使うときは、googleアカウントでのログインを必須とし、GAE上のデータストアにgookeアカウントにひもづくEvernote access tokenを保存することにした。
本当のwebサービスでは、プライバシー保護としてaccess tokenを保存しないオプションを用意する予定である。

7.consumer_oauth.pyの実行

変更済みのoauth.pyとapp.yamlもセットにして、consumer_oauth.pyをgithubで公開したので、以下からダウンロードする。

consumer_oauth.pyのソース

GAE開発キットが動作する環境であれば、githubからダウンロードした3つのファイルを同一ディレクトリにおいて、開発サーバを起動すれば、ブラウザからアクセスできる。

注意点は、以下の2点である。

  1. evernote開発環境のアカウント
  2. Evernoteでの承諾は、evernoteログインが必要である。(当然だが) このプログラムでは、URLをEvernoteの開発サーバ(sandbox.evernote.com)に指定しているので、本番サーバ(www.evernote.com)のアカウントとは別に、開発サーバ用にユーザ登録をしないとEvernoteにログインはできない。

  3. Callback URL
  4. callback URLは、GAE開発環境(localhost:8080)をデフォルトとしている。GAE上にアップロードする前には、.appspot.com名のホスト名に修正してからアップロードする必要がある。

 

正常に動作すれば、以下のような画面がブラウザでみれるはず。

1.googleにもEvernoteで承認されていない状態

1-2

2.Googleにログインし、Evernoteで承認されていない状態

2-2

3.Evernoteで承認する画面

4-2

4.Evernoteに承認された状態

3-2

これ以降、このoauth_keyをEdamに格納し、Edam_userIdのディレクトリに向かってAPI を呼び出す部分を作ることで、consumerからノートの操作が可能となる。

Endpoint URL: https://sandbox.evernote.com/edam/note/<shardId>



sylphide_ffr31mr at 23:09コメント(0)トラックバック(0) 

2010年12月10日

pythonでJPEG画像のEXIF情報を扱うのが、けっこう手間取ったので、ここに記しておく。 pythonの日本語情報は、表面的なものはあるけど、ちょっと突っ込んだものはやはり少ないと実感。

exif.pyというライブラリもあるが、追加ライブラリを使わずにやりたかったので、Python Image Libraryを使う。

import Image

i=Image.open("sample.jpg")
exif=i._getexif()
print exif.__class__

for tag,value in exif.items():
    print str(tag)+ str(tag.__class__) + "==>" + str(value) + str(value.__class__)

_getexif()で取得したEXIF情報は、DICT型になっている。そして、各要素のKEYは、int型になっているため、このままでは何が何の情報なのか、さっぱりわからない。
ちなみにvalue側は、タプルだったり、stringsだったり、いろいろ違うようだ。ややこしい。

$ python exiftest.py 
<type 'dict'>
36864<type 'int'>==>0221<type 'str'>
37121<type 'int'>==><type 'str'>
37378<type 'int'>==>(196608, 65536)<type 'tuple'>
36867<type 'int'>==>2010:12:05 11:19:56<type 'str'>
36868<type 'int'>==>2010:12:05 11:19:56<type 'str'>
40965<type 'int'>==>8602<type 'int'>
40960<type 'int'>==>0100<type 'str'>
37383<type 'int'>==>5<type 'int'>
37385<type 'int'>==>16<type 'int'>
37386<type 'int'>==>(28, 1)<type 'tuple'>
40962<type 'int'>==>4752<type 'int'>
41486<type 'int'>==>(4752000, 894)<type 'tuple'>
271<type 'int'>==>Canon<type 'str'>
272<type 'int'>==>Canon EOS 50D<type 'str'>
(以下略)

そこで、exiftagsというモジュールで、要素の名前に変換してやる。

import Image
import ExifTags

i=Image.open("sample.jpg")
exif=i._getexif()

for tag,value in exif.items():
    if tag!=37500: 
        tagname=ExifTags.TAGS.get(tag)
        print str(tagname) + "==>" + str(value)

出力は、こんな感じ。

$ python exiftest.py 
ExifVersion==>0221
ApertureValue==>(196608, 65536)
DateTimeOriginal==>2010:12:05 11:19:56
DateTimeDigitized==>2010:12:05 11:19:56
ExifInteroperabilityOffset==>8602
FlashPixVersion==>0100
MeteringMode==>5
Flash==>16
FocalLength==>(28, 1)
ExifImageWidth==>4752
FocalPlaneXResolution==>(4752000, 894)
Make==>Canon
Model==>Canon EOS 50D
(以下略)

なお、37500のexif要素には、何やらバイナリデータが入っていたので(サムネイルか?)、出力をはじいています。



sylphide_ffr31mr at 00:15コメント(0)トラックバック(0) 

2010年11月19日

Google App Engineで、がんばってrubyを作ってきたが、だんだん心が挫けてきたのと、周囲でよくpythonの話が出てきたので。
rubyをあきらめて、勉強をはじめてみた。

基本構文に慣れるために、簡単な数あてゲームを作った。
コンピュータが乱数で答えを決めて、ユーザに数字を入れさせて、もっと大きくとか、ヒントを出していくもの。
BASICの時代によく作っていたような、単純なものだ。

ルールは以下の通り。
  • 答えの値の範囲は、1から100までの間。(冒頭の変数で最小値と最大値は容易に変更できる)
  • 正解のプラスマイナス5の範囲に入ったら、”もうちょっと”という表現を使い、推理のヒントにする。
  • 正解後、入力履歴を表示する。

コーディングには、以下の点に気をつけた。
  • 正しく日本語を扱う
  • 入力エラーを厳密に判断する
できあがったのは、以下のとおり。
pythonの特徴は、可読性の良さと、誰が書いても同じようなコードになることだという。
どうでしょうか?


#!/usr/bin/python
# -*- coding: utf-8 -*-

import random

min=1
max=100
n=0
c=0
answerList = []

r=random.randint(min,max)

print "Input number[%d-%d]" % (min,max)
while r <> n:
  c += 1
  print "%d:"%c,

  while 1:
    n = raw_input()
    try:
      n = int(n)
    except ValueError:
      print u"ちゃんと数字を入れて"
    except TypeError:
      print u"ちゃんと数字を入れて"
    else:
      if n>=min and n<=max:
        break
      else:
        contine

  answerList.append(n)

  if r == n:
    if c==1:
      print "Hit! You are Esper!"
    elif c > 1:
      print "Hit! answer is %d" % r
    break

  elif r < n and r+5 > n:
    answerList.append("v")
    print(u"もうちょっとだけ小さいよ")

  elif r > n and r-5 < n:
    answerList.append("^")
    print(u"もうちょっとだけ大きいよ")

  elif r > n:
    answerList.append("!")
    print(u"もっと大きいよ")

  elif r < n:
    answerList.append("V")
    print(u"もっと小さいよ") 

print
print u"入力履歴"

for i in answerList:
  print i,

print


実行結果は、以下のようになる。
$ python input_number.py 
Input number[1-100]
1: 50
もっと小さいよ
2: 25
もっと大きいよ
3: 40
もっと小さいよ
4: 30
もっと大きいよ
5: 38
もうちょっとだけ小さいよ
6: 36
もうちょっとだけ小さいよ
7: 35
Hit! answer is 35

入力履歴
50 V 25 ! 40 V 30 ! 38 v 36 v 35



sylphide_ffr31mr at 23:54コメント(0)トラックバック(0) 
記事検索
最新コメント
livedoor プロフィール
月別アーカイブ
  • ライブドアブログ