Windows, Apache, mod_python な環境で virtualenv 上の django を動かしてみた

環境構築に使ったリポジトリはここ
https://bitbucket.org/toruuetani/virtualenv-modpython-test

基本的にはここのまま。
http://mydjangoblog.com/2009/03/30/django-mod_python-and-virtualenv/

なぜ必要か

Pythonはsite-packages以下にすべてのライブラリをインストールするため、プロジェクト毎に使うライブラリが異なる場合に困ったことになる。それを解決するのが virtualenv で、サンドボックスを作成できる。

なので最近は virtualenv で環境を構築して、そこに必要なライブラリをインストールして使うようにしている。Django でアプリを作る場合も当然 virtualenv 上で作るわけなんだけども、最終的には Apache で動かすことになる。そこで virtualenv 環境のライブラリを Apache, mod_python から使えるか実験してみた。※ 過去のプロジェクトを動かしたかったので、python2.5&mod_pythonを使っている。

構築手順

D:/Work/venv_test を作業ディレクトリとする。PythonApachemod_pythonをダウンロードしておく。

1. python 2.5をインストール

2. virtualenv.py を D:/Work/venv_test にコピー

3. C:\python25\python.exe virtualenv.py . --no-site-package

4. Apache を D:/Work/venv_test/apache にインストール

5. D:/Work/venv_test/Scripts/activate.bat を実行

6. easy_install -UZ django

7. easy_install -UZ mod_python-3.3.1.win32-py2.5-Apache2.0.exe

8. 以下の内容でmypython.pyを保存

activate_this = 'D:/Work/venv_test/Scripts/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))

from django.core.handlers.modpython import handler

9. D:/Work/venv_test/apache/conf/httpd.conf に以下の設定を追記

Alias /static "D:\Work\venv_test\djtest\static"
LoadModule python_module "D:\Work\venv_test\Lib\site-packages\mod_python-3.3.1-py2.5-win32.egg\mod_python_so.pyd"
<VirtualHost 127.0.0.1:80>
    <Location "/">
        SetHandler python-program
        PythonPath "['D:\Work\venv_test\Lib\site-packages', 'D:\Work\venv_test'] + sys.path"
        PythonHandler mypython
        SetEnv DJANGO_SETTINGS_MODULE djtest.settings
    </Location>
    <Location "/static">
        SetHandler None
    </Location>
</VirtualHost>

Windows7のVHD bootとDisk2vhdで快適環境構築=>挫折した・・・

Windows7になってかなり快適になったけども、使い続けるといろいろ問題が出てくることが多い。特にVisual Studioとか開発環境を複数入れたり、再インストールしたりするとよく問題が起こる。つい最近もVisual Studio 2008にWindows Mobile 6.5.3の開発環境を構築したら、デザイナ画面を開くと必ずVisual Studioが落ちるようになって、どうしようもなくなった。それでVisual Studioをアンインストールするしたりいろいろやってたら、Windows Mobile デバイスを全く認識しなくなってOSの再インストールしか打つ手がなくなってしまった。とりあえずデータは別パーティションにあるからそれほど手間ではないとは言え、OSのインストール時間がもったいない。これを機にもう少し簡単にする手順を考えてみる。ちなみにこれを書いてる時点では理論だけで実行してない。休み明けに試す予定。=>試した結果全然快適じゃなかった・・・

現在の構成

  • Windows 7 Ultimate
  • 物理的なHDDは1つでパーティションを2つに分割
    • 1つはOSをインストール
    • もう1つにはデータを格納

目標とする構成

システムドライブに最低限必要なツールだけ入れておけば、環境構築は劇的に楽になるはず。このときVisual Studioとかみたいにレジストリをいじったりするものは入れない方が良さげ。


2011/10/03 追記

  • 挫折した理由その1・・・Disk2vhdがHDDのパーティション構成をそのままコピーする
    • 上記データドライブのパーティションも作られ、仮想サイズがHDDのサイズと同じ
    • 作成されるVHDファイルが可変サイズ(VHD bootには固定サイズがベター)
    • VHD bootする場合仮想サイズと同じ空き容量が必要なため、起動してもブルースクリーン(ノートPCなのでHDDは1つしかなく、物理的に不可能)
  • 挫折した理由その2・・・VHD Resizerが遅すぎる
    • Disk2vhdで物理サイズと同じ仮想サイズのVHDファイルが作られるので、VHD Resizerでサイズ縮小しつつ固定VHDに変換しようとしたらVHDファイルのアロケートに2〜3時間。さらにVHDファイルの中身をコピーするのに2〜3時間・・・

時間と手間がかかりすぎて、普通にインストールしたほうがまだマシな感じだったので諦めた。
Windows7標準のバックアップと復元を使ったほうがマシかもしれない。

GUIテストフレームワークwhiteがすごい

http://white.codeplex.com/

たとえばこんなWindowsアプリがあったとして、

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e) {
            this.textBox1.Text = "Hello white";
        }
    }
}

こんなコードでbutton1のクリック結果をNUnitでテスト可能。

using System;
using NUnit.Framework;
using White.Core;
using White.Core.UIItems;

namespace WindowsFormsApplication1Test {
    [TestFixture]
    public class Class1 {
        [Test]
        public void Test() {
            var exe = @"D:\Work\WindowsFormsApplication1\WindowsFormsApplication1\bin\Debug\WindowsFormsApplication1.exe";
            using (var app = White.Core.Application.Launch(exe)) {
                var win = app.GetWindow("Form1");
                var button = win.Get<Button>("button1");
                button.Click();
                Assert.AreEqual("Hello white", win.Get<TextBox>("textBox1").Text);
            }
        }
    }
}

さすがにDataGridとかはテストできなそうだけど、これは調査しないとダメだな。WindowsFormsだけじゃなくて、WPFとかSilverlightもテストできるっぽいし。

ちなみに上記のコードをコンパイルするためには、テストアセンブリにWhite.Core.dllの参照が必要。

subpathsを使ったリポジトリをcloneする方法

2012/01/25 追記
Mercurial 2.0 以降は これ を参照

subrepoを使わない場合とか、subrepoを使ってもsubpathsを使ってない場合なら、リポジトリは普通にcloneできる。ただしsubrepoかつsubpathsを使っていると、普通にcloneすると失敗する。

何故かというと、subpathsはhgrcにsubrepoが参照するリポジトリのパスを格納しているから。
cloneしてもhgrcは作成されず、hgrcは自分で作成しないといけない。

なのでhgrcにsubpathsを格納しつつpullすれば、cloneと同じような効果が得られる。
ただし毎回手打ちでやるのも面倒なので、バッチファイルを用意してみた。2段階までネストに対応。

リポジトリ(トップ、ネスト1段階目、ネスト2段階目)のパスと、ネストしたリポジトリを格納するディレクトリを変更すれば使えるはず。ディレクトリ構成はこんな感じ.

PATH_TO_TOP
├─.hg
├─SECOND_DIR
    ├─.hg
    ├─THIRD_DIR
        ├─.hg
@ECHO OFF
SET ROOT_DIR=%~DP0
SET TOP_REPO=PATH_TO_TOP
SET SECOND_REPO=PATH_TO_SECOND
SET THIRD_REPO=PATH_TO_THIRD


SET TOP_HGRC=%ROOT_DIR%\.hg\hgrc
SET SECOND_HGRC=%ROOT_DIR%\SECOND_DIR\.hg\hgrc


:CREATE_TOP
hg init
ECHO [paths]>%TOP_HGRC%
ECHO default = %TOP_REPO%>>%TOP_HGRC%
ECHO;>>%TOP_HGRC%
ECHO [subpaths]>>%TOP_HGRC%
ECHO subrepo_second = %SECOND_REPO%>>%TOP_HGRC%


:CREATE_SECOND
IF NOT EXIST %ROOT_DIR%SECOND_DIR MKDIR %ROOT_DIR%SECOND_DIR
CD /D %ROOT_DIR%SECOND_DIR
hg init
ECHO [paths]>%SECOND_HGRC%
ECHO default = %SECOND_REPO%>>%SECOND_HGRC%
ECHO;>>%SECOND_HGRC%
ECHO [subpaths]>>%SECOND_HGRC%
ECHO subrepo_third = %THIRD_REPO%>>%SECOND_HGRC%


:UPDATE
CD /D %ROOT_DIR%
hg pull
hg update -C


:END
PAUSE

subrepoをさらに便利に使うためにはsubpathsを使おう

2012/01/25 追記
Mercurial 2.0 以降は これ を参照

これの続き。

subrepoは確かに便利なんだけども、あるシチュエーションでは使いにくいことになる。

  • サーバの名前が変更されたとき
  • 場所によってpushする先が違うとき(滅多にないだろうけど)

例えば、あるマシンAではsubrepo Aにpushしたりpullしたいが、あるマシンBではsubrepo Bにpushしたりpullしたい、だけど履歴は共有したい、なおかつマシンBからsubrepo Aはアクセス出来ない場合(マシンAを中心に履歴は共有する)。あるのか?というぐらい限定的だけども、現在自分が困っていて、その解決策っぽいのが見つかったのでメモ。

解決先はこれ -> http://mercurial.selenic.com/wiki/SubrepoRemappingPlan

前回 .hgsub にリポジトリのURLを記述していたが、今回はリポジトリエイリアスを記述する。

echo subdir = subrepo_name > .hgsub

.hgsubはこうなる。

subdir = subrepo_name

次にメインリポジトリの.hg/hgrcに[subpaths]を記述する。

[subpaths]
subrepo_name = https://bitbucket.org/toruuetani/virtualenv-scaffold

subdirとsubrepo_nameはかぶらないようにすること。同名だとsubrepoがネストしてたりすると余計な置換が働いて、正しいURLにならないことがある?


.hg/hgrcは他のリポジトリに伝搬しないので、実際にやりとりしたいリポジトリを記述すればOK。

subrepoを試してみた

前から気になってた、Mercurialのsubrepoの使い方がなんとなくわかったのでメモ。

何がうれしいのか

別管理のリポジトリを一緒に扱える。具体的には、共通ライブラリは別のリポジトリで管理しつつ、それを利用するアプリのリポジトリの下に共通ライブラリのリポジトリを配置できる。Subversionで言うところのベンダーブランチとかsvn:externals。

ベンダーブランチ/svn:externalsよりもうれしいのは、アプリ側のリポジトリからライブラリ側のリポジトリのリビジョンが指定できること。アプリ側のリポジトリを特定のリビジョンに更新したら、ライブラリ側のリポジトリもその時指定していたリビジョンに更新される。これはかなり便利。

作り方

まずはアプリ側のリポジトリ生成。これは普通に作る。

hg init

次にディレクトリを作って、ライブラリのリポジトリを作る。新規リポジトリをつくってもいいが、それだとあまり意味が無いので、既存のリポジトリをcloneする。

mkdir subdir
cd subdir
hg clone https://bitbucket.org/toruuetani/virtualenv-scaffold .

最後にsubrepo設定。

cd..
echo subdir = https://bitbucket.org/toruuetani/virtualenv-scaffold > .hgsub

.hgsubの中身はこんな感じで、配置先ディレクトリ = ターゲットのリポジトリパス(ディレクトリでもURLでも可)とする。

subdir = https://bitbucket.org/toruuetani/virtualenv-scaffold

.hgsubをコミットする。

そうするとsubdirが管理下に入るのでコミットする。

コミットすると.hgsubstateがリポジトリに追加される。このファイルに、ライブラリ側のリビジョンが記録される。

この状態だとライブラリ側のリポジトリはdefaultブランチの最新なので、好きなリビジョンに更新する。

cd subdir
hg up c59d68bcc05c

そうすると.hgsubstateもそのリビジョンを指すようになるのでコミット。

こうしてできたアプリ側のリポジトリをcloneして、最新のリビジョンにupdateするとライブラリ側のリビジョンも[c59d68bcc05c]まで更新される。


もちろんライブラリ側のリポジトリは普通のリポジトリでもあるので、変更したらclone元にpushもできる。まだ使い始めたばかりだが、これはかなり便利な気がする。

TortoiseHg2.0

PyQtにポーティングしたTortoiseHgがついに出た。

Workbench(以前のログビューア)からシームレスにコミットできる。

今までなかったのが不思議なリポジトリビューアも追加

あと地味に便利なのが、エクスプローラとかコマンドプロンプトも開ける。