IronPythonをC#アプリに組み込む

最近Pythonがにわかにマイブームで、お仕事でもSQLiteデータベースのメンテやテストデータの生成にPythonを使ったりしています。そんな中、IronPythonC#アプリ(デスクトップアプリ)に組み込むのを試してみたら思った以上に簡単に出来てほええーとなったのでブログにしたためておいた次第です。

準備

IronPythonのランタイムをプロジェクトに追加しておきます。NuGetからインストールするのが一番楽です。

スクリプトエンジンとスクリプトスコープの作成
ScriptEngine engine = IronPython.Hosting.Python.CreateEngine();
ScriptScope scope = engine.CreateScope();

スクリプトエンジン (Microsoft.Scripting.Hosting.ScriptEngine) はスクリプトを実行するクラスです。

スクリプトスコープ (Microsoft.Scripting.Hosting.ScriptScope) は変数やクラスの定義情報を格納するクラスです。エンジンにスコープオブジェクトを与えるとスクリプトはそのスコープの中で実行されます。IronPythonで定義した変数やクラスには場合はスコープオブジェクトからアクセスすることができます。

一行ずつ実行
ScriptEngine engine = IronPython.Hosting.Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
engine.Execute("print 'hello, world');
engine.Execute("foo = 100", scope);
engine.Execute("print foo", scope); // '100'と出力
int bar = engine.Execute<int>("foo", scope); // bar = 100

最後の行のように、式を評価した値を取得することもできます。

コンパイル + 実行
ScriptEngine engine = IronPython.Hosting.Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromString(@"
def hello():
    print 'hello, world'
hello()
");
CompiledCode code = source.Compile();
try
{
    code.Execute(); // 'hello, world'と出力
}
catch (Exception exeption)
{
    System.Console.WriteLine("ランタイムエラー: " + exception.Message);
}

文法エラーなどはCompile()メソッドの引数に Microsoft.Scripting.Hosting.ErrorListener を与えることで取得できます。ランタイムエラーが発生した場合は例外がスローされます。

IronPythonからCLRクラスのメソッドを呼び出す
ScriptEngine engine = IronPython.Hosting.Python.CreateEngine();
engine.Execute(@"
import clr
clr.AddReference('System.Windows.Forms')
from System.Windows.Forms import MessageBox
MessageBox.Show('hello, world')
"); // => System.Windows.Forms.MessageBoxを表示
C#からIronPythonの関数を呼び出す
ScriptEngine engine = IronPython.Hosting.Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
engine.Execute(@"
def hello():
    print 'hello, world'
", scope);
Action hello = engine.Operations.GetMember<Action>(scope, "hello");
hello(); // => 'hello, world'
C#からIronPythonのクラスのメソッドを呼び出す
ScriptEngine engine = IronPython.Hosting.Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
engine.Execute(@"
class Foo:
    def bar(self):
        print 'Foo.bar()'
", scope);
object fooObject = engine.Operations.Invoke(scope.GetVariable("Foo"));
Action bar = engine.Operations.GetMember<Action>(fooObject, "hello");
bar(); // => 'Foo.bar()'

XAMLのBindingの基本についてのメモ

Windows ストアアプリの開発で使われるXAMLのBindingがいまいちわかってなかったのでメモ。

Bindingとは

XAMLで構成されるアプリケーションでは、Bindingという機構を使ってUIのコントロールのプロパティ (ターゲット) に任意のオブジェクトのプロパティ (ソース) の値をバインド (束縛) させることができます。Bindingによって紐付けられた二つのプロパティは、一方のプロパティ (ソース) の値を変更すると、他方のプロパティ (ターゲット) の値も自動的に同期されるようになります。

ターゲットとなるプロパティはDependency Property (依存プロパティ) である必要があります。Dependency Propertyは、値を記憶するためのメモリ領域や、値の変更の監視を行うための機能が実装されたプロパティです。SDKがデフォルトで提供しているコントロールを使用する場合は気にする必要はありませんが、カスタムコントロールを実装する際は自分でDependency Propertyを実装する必要があります。

ターゲットのプロパティをソースのプロパティにバインドするには、ターゲットのプロパティに{Binding Path=SourcePropertyName}というXAMLマークアップ拡張を埋め込みます。以下はTextBlockコントロールのTextプロパティにNameという名前のプロパティをバインドする例です。

<TextBlock x:Key="myTextBlock" Text="{Binding Path=Name}"/>

Path属性は省略することができます。つまり、前述のコードは以下のコードと等価です:

<TextBlock x:Key="myTextBlock" Text="{Binding Name}"/>

ソースの指定: DataContextプロパティ

ここで一つ疑問が生まれます。Nameプロパティはいったいどのオブジェクトから読み込まれるのでしょうか。答えはDataContextプロパティにあります。 以下にLayoutAwarePageクラスを継承したクラスのLoadStateメソッドのコードの一部を示します。

var person = new Person() { Name = "John Doe" };
myTextBlock.DataContext = person;

XAMLで定義したmyTextBlockという名前のTextBlockオブジェクトのDataContextプロパティに、Personオブジェクトを設定しています。Bindingで指定したプロパティは、DataContextプロパティで指定したオブジェクトから読み出されます。

DataContextプロパティが対象となる要素に設定されていない場合、ランタイムはさらに親の要素のDataContextプロパティの値を読みに行きます。以下のようにTextBlockの親要素としてGridがある場合を想定します。

<Grid x:Key="myGrid">
  <TextBlock Text="{Binding Name}"/>
</Grid>

TextBlockのDataContextプロパティが未設定の場合、ランタイムは親要素であるGridのDataContextプロパティを読みに行きます。以下のようにmyGridのDataContextプロパティにNameプロパティを持つ任意のオブジェクトを設定することで、子の要素 (ここではTextBlock) のプロパティの値を変更することができます。

myGrid.DataContext = person;

ソースの指定: Source属性

もう一つ別の例です。以上はDataContextプロパティを使ってバインドする例でしたが、DataContextプロパティを使わずにBindingマークアップ拡張のSource属性を指定することで静的にソースを指定することもできます。

<Page.Resources>
  ...
  <local:Person x:Key="myPerson" Name="John Doe"/>
</Page.Resources>

...

<TextBlock Text="{Binding Name, Source={StaticResource myPerson}}"/>

この場合、ランタイムはmyPersonResourceというオブジェクトのNameプロパティを読みに行きます。{StaticResource myPerson}はXAMLのリソース定義部で定義されたmyPersonというキーを持つPersonオブジェクトを参照するためのマークアップ拡張です。

まとめ

  • Bindingとは、二つのプロパティの値を同期させるための仕組み
  • Bindingマークアップ拡張機能によって、バインドするプロパティのソースとターゲットを指定できる
  • どのオブジェクトのプロパティを読み出すかは、DataContextプロパティかBindingマークアップ拡張のSource属性で指定する

HTTPヘッダで彼女を募集するプロクシサーバ

Plack::App::Proxyで簡単に実現できそうだったのでPerl+Plackの練習のつもりで書いてみた (といってもほとんど http://d.hatena.ne.jp/hiratara/20100209/1265685238 からのコピペだけど).

コード

起動&テスト

$ plackup -r girlfriend.psgi
$ curl --proxy localhost:5000 http://st63jun.hatenablog.jp

tcpdump で採取したリクエストヘッダがこちら.

GET / HTTP/1.1
Proxy-connection: Keep-Alive
User-agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8rzlib/1.2.5
Connection: close
Accept: */*
Te: trailers
X-girlfriend-wanted: yes   <-- これ
Host: st63jun.hatenablog.jp
Via: 1.1 0:5000 (Plack::Middleware::Proxy::AddVia/0.01)
X-forwarded-for: 127.0.0.1
Referer: http://st63jun.hatenablog.jp/

ちなみにGoogleの検索結果のリンクのリダイレクトが効かなかったりするので,実用レベル(?)にするにはもう少しコードを書く必要があるようです.HTTPカラテが足りないので今回はここまで.

バレンタインデー前にやるべきでしたね. おわり.

BonjourでDHCP割り当てのマシンへ簡単にsshする

最近知ったこと.

DHCP割り当てのLinuxマシンfooにMacからsshするとき,fooでavahi-daemonが実行されているなら

$ ssh foo.local

でアクセスできます.ホスト名の末尾に .local を付ければBonjour (Zeroconf) が裏で名前解決してくれます.これはWebブラウザなど他のアプリでも同じ.

いちいちifconfigしてIPアドレス確認する必要なんてなかったんですねぇ.

LaTeXのソースを毎回makeしてる情弱は俺まででいい #OMake

という内なる声を感じたのでブログ書きます.

LaTeXで修論書いてると.auxや.idxや.xbbなどとやたら生成するファイルが多いので,Makefileを書いてmakeでpdfを吐くようにしていました.

別にこれでもいいのですが,論文修正→make投入を何度もやるのめんどいので,もっとスマートな方法がないのかなぁと思って調べていたらOMakeというのがありました.

http://d.hatena.ne.jp/hayamiz/20081208/1228727272

omake -P --verbose

を実行すれば、継続監視ビルド機能によって、texファイルとその依存関係にあるファイルが更新される度に、dvi と pdf ファイルが生成される。かんたん!

なにそれやばい!超便利!

しかもOMakeにはLaTeXソースのビルドを補助する機能が標準で付いているので,単純なLaTeXドキュメントであれば設定は数行で済みます.

もしLaTeXで論文を書いているのならOMakeは試してみるべきツールの一つであると思います.

Ubuntuで使う (12.10)

$ sudo apt-get install omake fam

omake -P を使う場合はFAMが必要なので一緒にインストールします.

Macで使う

OMakeの公式からMac版のバイナリパッケージをダウンロードしてインストールします. Mountain Lionの場合はCtrl+開くでGatekeeperを回避しつつインストールします.

Windowsで使う

OMakeはWindows版バイナリもあるしWindowsでも動くけど私は試してないです.

設定

OMakefileとOMakerootのひな形を生成します.

 $ omake --install

その後,OMakefileをLaTeXソースをビルドするように修正します.OMakeの日本語のドキュメントは http://omake-japanese.sourceforge.jp/ で閲覧できます.

LaTeX向けのOMakefileは http://qiita.com/items/eebbea5574a8ff42f8b2 が完成度が高いので,私はこれをコピペして使っています.

実行

$ omake -P --verbose

あとはファイルを変更する度にPDFができるので,EvinceやPreview.appなどのファイルが変更されると自動で再読み込みする系のアプリで表示しながら作業するとライフチェンジングします.

EmacsでもFlymakeを使えば同様のことはできますが,OMakeを使えばエディタに関係なく継続ビルドができるのがよいですね.

論文執筆のTODOリストを自動生成すると便利だった

下みたいなファイルを自動的に生成するようにしたら論文執筆が捗ったような気がしたので,ここに報告しておきます.

f:id:st63jun:20130124213354p:plain

一行目はEmacsで開いたときにgrep-modeで開くようにするための設定です. これを入れておくと,n/pキーでカーソルを移動させてTODOをマークした行に素早くジャンプできるので作業が捗りました.

TODOリストの生成

ボスや先輩に赤入れしてもらった論文を修正するとき,該当箇所のTeXソースコード中に指摘された内容をコメントでメモしておきます.このときコメントにTODOという文字列を入れておきます.

\section{序論}
...
% TODO: 図を入れる
% TODO: 言い回しを工夫する
...

これを下のような感じのシェルスクリプトで処理します.このスクリプトはgrepでTODOコメントの行だけ抽出してTODOというファイル名で保存します.

#!/bin/sh

TODO=`grep -nH -e '%\s*TODO:' *.tex`
COUNT=`echo "$TODO" | wc -l`
(echo "-*- mode:grep -*-"
 echo "$COUNT TODO found:"
 echo "$TODO") > TODO

これを実行すると最初の画像のようなTODOリストが出来上がります.

Makefileでコンパイル時に上記のスクリプトも一緒に実行するようにしておくと尚良しです.

Apache Ant の途中経過を Growl で通知する

MavenやGradleがある今,もはや今さら感のあるApache Antですが,ビルドの経過をGrowlに通知するようにすると少しだけ幸せになります.

f:id:st63jun:20130107191628p:plain

ant-growllistener.jar

Antのビルド経過をGrowlに通知するAnt拡張のひとつとして ant-growllistener.jar (https://github.com/tholstrup/Ant-growl) があります.今回はこれをforkしてGrowl for Linuxへの対応や細かいオプションを付けたしたもの (https://github.com/st63jun/Ant-growl) を使っています.

使い方は,ant-growllistener.jar を ~/.ant/lib に置いて,

$ ant -listener com.google.code.ant.growlnotify.GrowlListener

のように -listener オプションを追加してAntを実行すると,ターゲットが開始/終了する度に通知がぽこぽこ表示されます.

また ~/.profile あたりに

export ANT_ARGS='-listener com.google.code.ant.growlnotify.GrowlListener'

を書いておくといちいち -listener オプションを指定しなくてもGrowl通知が有効になります.

一方Gradleでは

AnnouncePluginExtensionというのがあって,デフォルトでGrowl通知ができるのでした.

まとめ

Gradleを使おう.