ラベル Python 2.5.1 の投稿を表示しています。 すべての投稿を表示
ラベル Python 2.5.1 の投稿を表示しています。 すべての投稿を表示

2009年4月26日日曜日

MacPortsを使って、Pythonの開発環境を整えてみた

ここ最近勉強会続きだったため、複数のバージョンのPythonの開発環境の整備をする必要に迫られました。
まずはPython2.6.2をインストールしようと考えたのですが、python.orgからdmgでダウンロードしてインストールすると余計な物をたくさんインストールされてしまいますし、何より環境の切り替えが大変です。
(Mac付属の2.5.1でないとDjangoがエラーを吐いたりするため、いつでも2.5.1に切り戻せるようにしたい)

そこで今回はMacPortsを使って開発環境を整えてみました。

■Pythonのインストール
これはMacPortsから以下のコマンドを実行するだけでいけました。
sudo port install python26

ただ、依存するモジュールが非常に多いためビルドに大変時間がかかりました。MacBook Airで、およそ1時間ぐらい。
これで/opt/local/Library/Frameworks以下にPython.frameworkがインストールされるのですが、インストールしただけでは自由に元々存在するPython 2.5.1との切り替えができません。
そこで、同じくMacPortsで提供されている、python_selectというスクリプトをインストールします。
sudo port install python_select

インストールしたら、以下のようにして自由にPythonのバージョンを切り替えることが出来ます。
$ python_select -l #利用可能なバージョン一覧を表示
Available versions:
current none python25-apple python26
$ python_select python26 #python2.6に切り替え

こいつは大変便利です。

■Djangoのインストール
DjangoもMacPortからインストールできます。
sudo port install py26-django

Djangoだけではなく、jinjaやSQLAlchemy, Werkzeugなど、名前の知られているPythonのフレームワークはすべて存在しているようです。とっても楽ちん。
ちなみにインストールできるportとしてpy25-djangoのようにPythonのバージョンを指定しているものと、py-djangoのように指定していないものがありますが、py-djangoをインストールしようとすると突然Python2.4をインストールしようとしやがりましたので、基本的にはPythonのバージョンを指定しているportを選んだ方が良さそうです。

さて、MacPortでインストールしたPythonのためにDjangoをインストールするのは簡単でしたが、
問題になってくるのは元々標準で入っているPython2.5.1のためにDjangoをインストールするときです。
easy_installが使えるようなので、今回はeasy_installを使ってインストールしました。
sudo easy_install django

ただしportと比較すると後からアンインストールするのが面倒だという欠点があります。portが使えるならportがいいですね。

■PILのインストール
PILのインストールも基本はMacPortで。
sudo port install py26-pil

問題はPython 2.5.1にインストールするときです。私の環境では、easy_installが失敗してしまい簡単にインストールできませんでした。
悩んだあげく、PILのウェブページからPython Imaging Library 1.1.6 Source Kitをダウンロードし、直接setup.pyを実行して解決しました。
tar zxvf Imaging-1.1.6.tar.gz
cd Imaging-1.1.6
sudo python setup.py install

2009年3月17日火曜日

Pythonで、特定のディレクトリ以下にあるすべてのモジュールをインポートする方法

Pythonで特定のディレクトリの下にあるすべてのモジュールをインポートしたいときの方法。
これもGAEOのソースから見つけました。
def initPlugins():
"""
Initialize the installed plugins
"""
plugins_root = os.path.join(os.path.dirname(__file__), 'plugins')
if os.path.exists(plugins_root):
plugins = os.listdir(plugins_root)
for plugin in plugins:
if not re.match('^__|^\.', plugin):
try:
exec('from plugins import %s' % plugin)
except ImportError:
logging.error('Unable to import %s' % (plugin))
except SyntaxError:
logging.error('Unable to import name %s' % (plugin))


キモは二つ。
  1. os.listdirで特定のディレクトリ以下のすべてのファイル名・ディレクトリ名を取得する
  2. 取得したディレクトリ名を使ってimport文を生成して、exec()で実行する
exec()で無理矢理実行とか正直嫌な感じです。しかしこれ以外に方法はなさそうですね・・・
ファイル名を使ってコマンドインジェクションとかできそうじゃないかと試してみましたが、そもそもファイル名には改行とかバックスラッシュとかが使えないので意外と安全かも。

GAEOでPythonのunittestモジュールを使って単体テストにチャレンジ

■まとめ
site-packagesにインポートするモジュールとかまとめておくのが使うのがいちばん楽


■何がしたいか
以下のようなGAEOプロジェクトがあります。



ここで、test.controller.forecastareaTest.pyにforecastareaモジュールのテストケースを記述するためには、applicationディレクトリにPYTHONPATHを通す必要があります。
それをいちばんスマートにやるにはどうすればよいかいろいろ悩んでました。


■どうしてそこで悩むの?
forecastareaTest.pyは単体で動作させなくてはいけないからです。
もしここで、jweeklyforecastディレクトリの直下にテストケースをおくことが出来るのであれば、
application_root = os.path.join(os.path.dirname(__file__), 'application')
test_root = os.path.join(os.path.dirname(__file__), 'test')
sys.path.append(application_root)
sys.path.append(test_root)

from application.controller import ForecastareaController
from test.controller import TestForecastarea

こんな風に自分のディレクトリからのパスをsys.pathに追加してからインポートすれば一発です。applicationもtestも自分の子供ディレクトリですから楽です。
しかしforecastareaTest.pyの位置から見ると・・・
application_root = os.path.join(os.path.dirname(__file__), '../../../application')
sys.path.append(application_root)

from application.controller import ForecastareaController

こんな風にインポートしなくちゃいけなくなります。相対指定とかする必要があって、ちょっとやな感じです。
PROJECT_HOME = '/User/akisute/DropBox/Projects/GoogleAppEngine/jweeklyforecast/'
application_root = os.path.join(PROJECT, 'application')
sys.path.append(application_root)

from application.controller import ForecastareaController

これでもいいのですが、これだとPROJECT_HOMEが各テストケースごとにべた書きになってしまいます。これまたディレクトリの移動に弱いです。
ディレクトリが動いたらテストケース100件の定数を全部書き直しとか嫌すぎです。


■最終的に出した結論がこれ
site-packagesディレクトリの中にjweeklyforecast_path.pyなる以下のようなモジュールを配置。
#!/usr/bin/env python
#encoding: utf-8
import os, sys

PROJECT_HOME = '/Users/akisute/Dropbox/Projects/GoogleAppEngine/jweeklyforecast'
sys.path.append(PROJECT_HOME)
sys.path.append(os.path.join(PROJECT_HOME, 'application'))

そしてこれを各テストケースからインポート。
するとapplicationディレクトリにパスが通るからインポートして使えるという仕組みです。
#!/usr/bin/env python
#coding: utf-8
import logging
try:
    import jweeklyforecast_path
except Exception, e:
    logging.warn("jweeklyforecast_path not found.")

import unittest
from controller.forecastarea import Forecastarea

class TestForecastarea(unittest.TestCase):
    """Forecastarea test case.
    """
    #以下テストケースがずらずらと続く・・・

ディレクトリが動いたり環境が変わったときには、このjweeklyforecast_pathをsite-packagesにコピーして、中身のPROJECT_HOMEを書き直すだけですみます。


■最後になりましたが
意味不明な記事になってしまってごめんなさい。自分の理解度不足ゆえグダグダになってしまいました><

pythonで、Objective-Cのカテゴリのように、あるクラスのソースを変更せずに任意のメソッドを追加する方法

■結論
すべてのクラスには__bases__という隠しフィールドがあるので、そこに任意のスーパークラスを作って追加する


■何がしたいか
たとえば以下のようなクラスがあります。
class Foo:
def do_something(self, x):
  print x
  return

このクラスのソースコードに指一本触れずに以下のメソッドを追加したい。
  def another_method(self, x, y):
  print x+y
  return

って将軍様が言っていたので、一⑨さんは考えました。


■チーン!ひらめいた!
まずは以下のようにスーパークラスになるクラスを作ります。
class SampleCategory:
def another_method(self, x, y):
  print x+y
  return

そしてここからがポイント。__bases__というTupleに、今作ったスーパークラスのtype型を追加します。
スーパークラスを宣言した後で・・・
from com.akisute.example import Foo
Foo.__bases__ += (SampleCategory,)

これだけです。
なぜかこれでうまくいくのがPythonのふしぎ。

実際のソースコードの例は以下のようになります(以下、拙作のプログラムから抜粋)
#!/usr/bin/env python
# encoding: utf-8
"""Login Authentication plugin.
Extends BasicController to give it an additional function for authentication
using Google account.
"""
import sys
import os

class LoginAuthPlugin:
    def is_login(self):
        """Returns True if requesting user is logged in."""
        #Do some work here
        return false

from gaeo.controller import BaseController
BaseController.__bases__ += (LoginAuthPlugin,)


JavaScriptのprototype書き換えにも似ていますね。
ただしprototype書き換えに比べて優れているのは、__bases__はTupleなので、簡単に好きなだけスーパークラスを追加することが出来ます。
(prototypeだと複数のスーパークラスを追加するのがきわめて困難)
from com.akisute.example import Foo
Foo.__bases__ += (SampleCategory,)
Foo.__bases__ += (AnotherCategory,)


■元ネタ
GAEOでpluginを読み込んでBaseControllerを拡張するときにこのテクが使われていました。
GAEO作った人は凄い。

2009年2月22日日曜日

Mac OS X LeopardでPYTHONPATHとPYTHONSTARTUPを設定してみました

  • 環境変数PYTHONPATHとは、Pythonがimportするときにモジュールを探しに行くパスのこと。JavaでいうところのCLASSPATHにあたる
  • 環境変数PYTHONSTARTUPとは、Pythonを対話モード(プロンプトモード)で実行した時に自動的に実行されるPythonスクリプトのこと。起動時に毎回読み込みたい設定とかを書いておくことができる
  • autoimpとPYTHONSTARTUPを組み合わせるとimportの手間から解放されて非常に便利

Pythonのモジュール名・関数名がわからないときや、ちょっとだけスクリプトを実験してみたいときなどPythonをコマンドラインから呼び出すことがよくあると思います。
ところが未設定のままのPython対話モードだと以下のような問題が生じます。
  • 毎回毎回使うimport osとかimport sysとかをいちいち手で実行するのが面倒くさい。自動でやりたい
  • 後からインストールしたライブラリ、特にGoogle App Engineのモジュールが利用できない
そこでこれらの問題を解決するべくPythonの環境設定を行ってみることにしました。
以下、すべてMac OS X 10.5.6と付属のPython 2.5.1 (Apple Build)で設定を行っています。python.orgからダウンロードしてきたPython 2.6や3.0の場合はファイルのあるパスが違ったりなどするかもしれません。


■PythonPathを通そう
PythonPathとは要するにJavaのクラスパスです。このパスが通っているところからPythonはモジュールをインポートしようとします。
現在のPythonPathを確認するためには、以下のPythonスクリプトを実行します。
>>> import sys
>>> sys.path

似たようなのにos.pathがありますが、アレは全く別物みたいです。まどろっこしいです。

さて、PythonPathを上手に利用するためには2通りの方法があります。
一つは自分で環境変数PYTHONPATHを設定してPythonPathに好きなパスを追加する方法です。
export PYTHONPATH=${PYTHONPATH}:/usr/local/google_appengine:/usr/local/google_appengine/lib/antlr3:/usr/local/google_appengine/lib/django:/usr/local/google_appengine/lib/webob:/usr/local/google_appengine/lib/yaml/lib

もう一つは最初からPythonPathが通っていて、かつユーザーが自由に使ってもいい領域「site-package」を利用する方法です。
詳しい理屈はよくわかりませんが、Pythonには最初からsite-packageとかいう自由にライブラリを追加するための領域があるみたいです。
現在のsite-packageを調べるためには、id:a2cさん曰く
python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

これだけでいいそうです。試しにPython 2.5.1 Apple Buildで実行してみたところ、
$ python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
/Library/Python/2.5/site-packages

こうなりました。たぶんpython.orgのPythonや、macportでインストールしたPythonだとまた全然違った値になるのではないかと。
ということでこの/Library/Python/2.5/site-packages以下に、ダウンロードしてきた外部のライブラリなどを配置していけば自動的にパスが通っていい感じになりそうです。


■autoimpを使ってみよう
autoimpというライブラリを利用すると、いちいち最初にimport osとかimport mathとかしなくても直接os.path.join()とかmath.piとかが呼び出せるみたいです。
http://www.connellybarnes.com/code/autoimp/
使い方は簡単、まずはライブラリのソースを↑のページからダウンロードしてきて、
先ほどご説明したsite-packages以下に置くだけ。

あとは、
>>> from autoimp import *
>>> os.stat('.')
>>> sys.path
>>> math.pi
>>> google.appengine.ext.db.Model

一度from autoimp import *してしまえばimportなしで何でも自由に使えるという寸法らしいです。すごい。
でもこれでは結局最初にfrom autoimp import *と書く手間がかかってしまいますので、
Python起動時に自動的にfrom autoimp import *してくれるように設定してみましょう。


■PYTHONSTARTUPを設定しよう
環境変数PYTHONSTARTUPを利用すると、Pythonの起動時に毎回決められたスクリプトを実行することが出来るらしいです。
たとえば自分のホームディレクトリに、以下の.pythonstartup.pyというファイルを作ってみます。
#!/usr/bin/env python
#coding: utf-8
print 'hogehoge'

そして環境変数PYTHONSTARTUPを以下のように設定します。
export PYTHONSTARTUP=~/.pythonstartup.py

一端ターミナルを再起動してからpythonを実行してみると・・・
akisute ~$ python
Python 2.5.1 (r251:54863, Jan 13 2009, 10:26:13)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
hogehoge
>>>

ほら、print 'hogehoge'が実行されてますよね。
同様にして、以下のように.pythonstartup.pyを設定すれば・・・
from autoimp import *

Pythonを実行すると・・・
akisute ~$ python
Python 2.5.1 (r251:54863, Jan 13 2009, 10:26:13) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> os.path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/posixpath.py'>
>>> math.pi
3.1415926535897931
>>> google.appengine.ext.db.Model
<class 'google.appengine.ext.db.Model'>

ごらんの通り!importなしに自由にモジュールが利用できています!

2009年2月15日日曜日

jweekyforecast近況報告(2009/02/15)


ようやく予報区のマスターメンテができるようになりました。
天気予報区のデータをアプリケーションに登録して、それをAPIを通じてiPhoneに引き渡すというような処理を行おうと思っています。


天気予報区には大きく分けて一次細分区域と二次細分区域がありますが、今のところ一次細分区域しか対応していません。二次細分区域を対応させようと思ったら親子関係を持たせないとなぁ。

何より問題はこのマスターメンテが死ぬほど面倒くさいことかなぁ・・・と思います ;(

さてさて、次はAPIを作らないとシステムとして成り立たないですね。

2008年12月14日日曜日

第2回 Google App Engine Hackathon

  • 今回で第2回目
  • 主催は@tmatsuoさん
  • 4チーム(内部でさらに分かれるため合計6チーム)に分かれて作業をし、最後に発表する形式
  • 1回目よりも運営が格段にスムーズで素晴らしい時間を過ごせた
  • GDataの認証はすさまじく難しい。またGDataアクセス用のライブラリがあるが、これまた非常に機能が多く難しい
  • Google App Engine Oilは凄く良い、余計なことをしないし必要な者は全部作ってくれる
  • gaeogenはバージョン0.21の地点ではバグがあるためまともに機能しない
  • DropBoxを使ったグループ開発はすさまじいスピード感がある

http://groups.google.co.jp/group/google-app-engine-japan?hl=ja
ちょっと遅くなりましたが、2008年12月13日に開催されました第2回 Google App Engine Hackathonについてご報告です。

主催は前回に引き続きGoogleの認定エキスパートである@tmatsuoさん。
前回は好き勝手にGAEで物を作るだけという感じだったのですが、今回は趣向を変えて、
  • チュートリアル:RSS Reader作成
  • チュートリアル:Twitterもどき作成
  • GDataを用いたマッシュアップ:Bloggerなどとマッシュアップする組
  • GDataを用いたマッシュアップ:Picasaなどとマッシュアップする組
  • フレームワーク
  • データモデル
以上の6組に分かれてそれぞれ活動し、結果を最後に発表すると言う形式で行われました。
目標がはっきりしていたおかげで、最後にはものすごいアプリが次々飛び出しました。大成功だったと思います!
運営の皆さんありがとうございました!
前回に引き続きお弁当おいしかったです =)


詳細につきましてはHiiroさんのブログをご参照ください。
Hiiro_memo: GAEハッカソン参加感想&まとめ:Google凄いが周辺人も凄い


私はマッシュアップ班に参加いたしました。
ちなみに隣の席が世界に名だたるおっぱいプログラマー@technohippyさんでした。びっくりです。
Da変態な人かと思っていたら、意外と普通の人でした。Vistaに泣かされていましたけど。

今回のマッシュアップ班の開発の際には、DropBoxに全員のプロジェクトファイルを配置して、いつでもみんなのファイルを参照できるようにして作業しました。
コレが凄くいいです。誰かが一人難所をクリアできれば、すぐにみんながそのソースを参照して動かせるように出来たため、作業効率が格段に良かったです。
(共有する人はコミット作業すら必要ありません。全部自動的に同期してくれるから)

さっそくDropBoxが大のお気に入りになりました。Windows機にはあまり導入したくなかったのですが、
こんなに便利なら使うしかないですね。


また、噂のGoogle App Engine Oil(GAEO)も試してみました。
gaeo testproject

とすると、testprojectを作成してくれるのですが、コレが素晴らしい!
最初から絶対に必要になるjs, img, cssフォルダを作成してくれたり、faviconの設定もしてくれたり、かゆいところに手が届く感じです。
RequestHandlerの実装も非常に簡単になっていて、
class WelcomeHandler:
  def index(self):
      #get All models from DataStore
      models = AModel.all().fetch()
      #set models to self object to use it when rendering the template
      self.models = models

たったのこれだけで、テンプレートのレンダリングまで全部自動でやってくれます。

本当はgaeogenというrailsのscaffoldのような機能があるのですが、こちらは0.21の段階ではバグがあるようでまともに機能しませんでした。
(ソースを参照したところ、argvに対してgetメソッドを呼び出したりしていました。
Pythonのargvはlist型だからdict型にしか使えないgetメソッドは利用できないです)
でもgaeoだけでも十分すぎるほど便利ですから導入する価値は有りだと思います。