Pythonで入れ子Zip内のファイルを透過的に開く方法 - zip_openを使う
Pythonは標準で、パッケージをzip圧縮しておいてこの中身を直接importすることができます。 例えば:
packages.zip + foo.py + bar.py
このようなzipファイルを /path/to/packages.zip に置いて、Pythonインタプリタで以下のように実行することが出来ます。
- import sys
sys.path.insert(0,'/path/to/packages.zip')
import foo, bar
foo.func()
この方法を使えば、 Google App Engine のような配置出来るファイル数に上限のある環境や、たくさんのファイルをベタに展開したくない状況(Pythonで作ったアプリを人にあげるとき)などに単純にファイル数を減らすことが出来ます。
このようなzip圧縮して配布する方法は、py2exe(-bオプション)やsetuptools(zip_safeオプション)などでも使われています。
しかし、対象パッケージが静的ファイル(htmlテンプレートやiniファイルなど)が含まれている場合にzip圧縮パッケージは問題になります。例えばpackages.zipが以下のようになっているとします:
/path/to/packages.zip + foo.py + bar.py + setting.ini
そして、前述のfoo.pyのプログラム中で open(os.path.join(os.path.dirname(__file__)),'setting.ini')) などと書いていてると、ここでopenしようとするファイルは '/path/to/packages.zip/setting.ini' になります。このようなpathはopenで開くことが出来ないのでエラーになります。
このような理由でzip_safeでないeggファイルはかなりたくさんあり、これを解決するopen関数があれば割と嬉しい人がいるんじゃないかと思うわけです。Python標準のzipimport.zipimporterを使えば似たようなことは出来ますが、このモジュールでは入れ子のZipファイルを扱うことが出来ません。
作ってみました
あったらうれしい、ということで zip_open パッケージを作ってみました。このパッケージは以下の機能を提供しています。
インストール方法
$ easy_install zip_open
利用例1: zipファイル内のファイルを開く
packages1.zip の例:
packages1.zip + file1.txt
file1.txt を開きます:
>>> from zip_open import zopen
>>> fobj = zopen('packages1.zip/file1.txt')
>>> data = fobj.read()
>>> print data
I am file1.txt, ok.
上記のコードは以下のコードと等価です:
>>> from zipfile import ZipFile
>>> zipobj = ZipFile('packages1.zip')
>>> data = zipobj.read('file1.txt')
>>> print data
I am file1.txt, ok.
利用例2: 入れ子になったzipファイル内のファイルを開く
packages2.zip の例:
packages2.zip
+ data2.zip
+ file2.txt
file2.txt を開きます:
>>> from zip_open import zopen
>>> fobj = zopen('packages2.zip/data2.zip/file2.txt')
>>> print fobj.read()
I am file2.txt, ok.
利用例3: zip圧縮されたパッケージ内のモジュールからファイルを開く
packages3.zip の例:
packages3.zip
+ foo.py
+ file1.txt
+ data3.zip
+ file3.txt
foo.py のコード例:
import os
from zip_open import zopen
def loader(filename):
fobj = zopen(os.path.join(os.path.dirname(__file__), filename))
return fobj
foo.pyのloader()をインタラクティブシェルから呼び出してファイルを開きます:
>>> import sys
>>> sys.path.insert(0, 'packages3.zip')
>>> import foo
>>> fobj = foo.loader('file1.txt')
>>> print fobj.read()
I am file1.txt, ok.
>>> fobj = foo.loader('data3.zip/file3.txt')
>>> print fobj.read()
I am file3.txt, ok.
次の目標
実際にこの仕組みを使うと嬉しいパッケージ(jinja2を使った自分のアプリ等)を調べて、この仕様で機能に過不足がないか検証する。あと入れ子になったzip内のモジュールをimport出来ると嬉しいかな。
元々は gaepytz を使っているGoogle App Engineアプリをzc.buildoutのappfy.recipe.gaeで環境管理しようとしたところ、zoneinfo.zipが入れ子zipの中に入ってしまってファイルを開けなくなってしまったため、なんとかできないかなーと思ったのが zip_open を作成した動機でした。 gaepytz の作者に入れ子zipでも動作するようにパッチを作って送ったはずみで、勢いでPyPIに登録してしまったという。。他に色々やることあったんだけど、これ作るのに半日使っちゃったよ。
- カテゴリ
-
python
- 固定リンク
- ¦
- コメント (0)
- ¦
- トラックバック (0)
- トラックバック用URL:
- http://www.freia.jp/taka/blog/727/tbping
| « | 2010 年 July | » | ||||
|---|---|---|---|---|---|---|
| Mo | Tu | We | Th | Fr | Sa | Su |
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 | |
- このBlogについて
- Zope, Python, FreeBSD, その他色々について。つまり日記か。
- 最近のエントリ
- Sphinx+翻訳Hack-a-thon2010.09に参加しアクセンスさんに初侵入しました taka 2010年09月06日
- XP祭り2010実行委員長の基調LTレポート taka 2010年09月05日
- XP祭り2010に登壇しました「Pythonでアジャイル開発サイクル 2010ver.」 taka 2010年09月04日
- cmscomさん主催の開発合宿に参加してきました taka 2010年08月29日
- BPStudy#36 に参加しました Jiemamyとbeproud-bot君の紹介 taka 2010年08月27日
- 最近のコメント
- Re:Zope2 ドキュメントを Sphinx でビルドする手順 xiangxiang 2010年09月03日
- pyreadline-1.6対応 しみずかわ 2010年07月18日
- pyreadline-1.6対応 しみずかわ 2010年07月18日
- Re:日本語キーボードから英語キーボードへ TAZO 2010年07月15日
- Re:COREBlog2をPlone3で動かすための修正: portletのカレンダー akiko 2010年06月30日
- 最近のトラックバック
- [python] エキスパートPythonプログラミング 彷徨えるフジワラ 2010年05月30日
- ファミリーコンサート 2009 終了 takalog 2009年11月10日
- Tools@System @note (PukiWiki/TrackBack 0.4) 2009年07月12日
- Windowsのコマンドプロンプトをフリーソフトで便利にする ナレッジエース 2009年05月31日
- plone研究会(2009-05) takalog 2009年05月22日
- カテゴリ
- Agile(XP) (2)
- Event (15)
- Pattern (0)
- その他 (10)
- Zope (11)
- Memo (0)
- 食 (3)
- python (21)
- Programming (1)
- Game (0)
- OO (0)
- Unix (0)
- WZ (0)
- work (0)
- Plone (11)
- Windows (1)
- IT-PC (4)
- 自転車 (0)
- TurboGears (0)
- ダーツ (0)
- JavaScript (0)
- 旅行 (1)
- Web (4)
- セキュリティー (1)
- Django (0)
- LDAP (0)
- データベース (0)
- vi/vim/gvim (0)
- C/C++ (0)
- ボドゲ (0)
- RoR (2)
- pyspa (1)
- スタトレ (0)